Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
# Created by https://www.toptal.com/developers/gitignore/api/aspnetcore,dotnetcore,visualstudio,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=aspnetcore,dotnetcore,visualstudio,visualstudiocode

# MIG
/cli

# Database
*.db

Expand Down
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"request": "launch",
"preLaunchTask": "build-cli",
"program": "${workspaceFolder}/src/CLI/bin/Debug/net5.0/linux-x64/mig-cli",
"args": ["aet", "add", "-a", "TEST", "--apps", "1,2,3"],
"args": ["config", "endpoint", "http://localhost:4500"],
"cwd": "${workspaceFolder}/src/CLI/bin/Debug/net5.0/linux-x64",
"stopAtEntry": true,
"console": "internalConsole"
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ RUN echo "Building MONAI Deploy Informatics Gateway $Version ($FileVersion)..."
RUN dotnet publish -c Release -o out --nologo /p:Version=$Version /p:FileVersion=$FileVersion src/InformaticsGateway/Monai.Deploy.InformaticsGateway.csproj

# Build runtime image
FROM mcr.microsoft.com/dotnet/runtime:5.0-focal
FROM mcr.microsoft.com/dotnet/aspnet:5.0-focal

ENV DEBIAN_FRONTEND=noninteractive

Expand Down
22 changes: 21 additions & 1 deletion src/Api/FileStorageInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// limitations under the License.

using Ardalis.GuardClauses;
using System;
using System.IO.Abstractions;

namespace Monai.Deploy.InformaticsGateway.Api
Expand All @@ -21,6 +22,11 @@ public record FileStorageInfo
{
private readonly IFileSystem _fileSystem;

/// <summary>
/// Gets the unique ID of the file.
/// </summary>
public Guid Id { get; init; }

/// <summary>
/// Gets the correlation ID of the file.
/// For SCP received DICOM instances: use internally generated unique association ID.
Expand All @@ -44,7 +50,19 @@ public record FileStorageInfo
public string[] Applications { get; private set; }

/// <summary>
/// Gets or set the number of attempts to upload.
/// Gets or sets the DateTime that the file was received.
/// </summary>
/// <value></value>
public DateTime Received { get; set; }

/// <summary>
/// Gets or set database row versioning info.
/// </summary>
/// <value></value>
public byte[] Timestamp { get; set; }

/// <summary>
/// Gets or sets the number of attempts to upload.
/// </summary>
public int TryCount { get; set; } = 0;

Expand All @@ -67,8 +85,10 @@ public FileStorageInfo(string correlationId, string storageRootPath, string mess
}

_fileSystem = fileSystem;
Id = Guid.NewGuid();
CorrelationId = correlationId;
StorageRootPath = storageRootPath;
Received = DateTime.UtcNow;
FilePath = GenerateStoragePath(storageRootPath, correlationId, messageId, fileExtension);
}

Expand Down
14 changes: 14 additions & 0 deletions src/CLI/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2021 MONAI Consortium
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Monai.Deploy.InformaticsGateway.CLI.Test")]
23 changes: 17 additions & 6 deletions src/CLI/Commands/AetCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ private void SetupAddAetCommand()

private async Task<int> ListAeTitlehandlerAsync(IHost host, bool verbose, CancellationToken cancellationToken)
{
Guard.Against.Null(host, nameof(host));

this.LogVerbose(verbose, host, "Configuring services...");

var console = host.Services.GetRequiredService<IConsole>();
Expand All @@ -100,8 +102,9 @@ private async Task<int> ListAeTitlehandlerAsync(IHost host, bool verbose, Cancel
IReadOnlyList<MonaiApplicationEntity> items = null;
try
{
ConfigurationOptions config = LoadConfiguration(verbose, configService, client);
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {config.Endpoint}...");
CheckConfiguration(configService);
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
this.LogVerbose(verbose, host, $"Retrieving MONAI SCP AE Titles...");
items = await client.MonaiScpAeTitle.List(cancellationToken);
}
Expand Down Expand Up @@ -142,6 +145,9 @@ private async Task<int> ListAeTitlehandlerAsync(IHost host, bool verbose, Cancel

private async Task<int> RemoveAeTitlehandlerAsync(string name, IHost host, bool verbose, CancellationToken cancellationToken)
{
Guard.Against.NullOrWhiteSpace(name, nameof(name));
Guard.Against.Null(host, nameof(host));

this.LogVerbose(verbose, host, "Configuring services...");
var configService = host.Services.GetRequiredService<IConfigurationService>();
var client = host.Services.GetRequiredService<IInformaticsGatewayClient>();
Expand All @@ -153,8 +159,9 @@ private async Task<int> RemoveAeTitlehandlerAsync(string name, IHost host, bool

try
{
ConfigurationOptions config = LoadConfiguration(verbose, configService, client);
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {config.Endpoint}...");
CheckConfiguration(configService);
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
this.LogVerbose(verbose, host, $"Deleting MONAI SCP AE Title {name}...");
_ = await client.MonaiScpAeTitle.Delete(name, cancellationToken);
logger.Log(LogLevel.Information, $"MONAI SCP AE Title '{name}' deleted.");
Expand All @@ -174,6 +181,9 @@ private async Task<int> RemoveAeTitlehandlerAsync(string name, IHost host, bool

private async Task<int> AddAeTitlehandlerAsync(MonaiApplicationEntity entity, IHost host, bool verbose, CancellationToken cancellationToken)
{
Guard.Against.Null(entity, nameof(entity));
Guard.Against.Null(host, nameof(host));

this.LogVerbose(verbose, host, "Configuring services...");
var configService = host.Services.GetRequiredService<IConfigurationService>();
var client = host.Services.GetRequiredService<IInformaticsGatewayClient>();
Expand All @@ -185,9 +195,10 @@ private async Task<int> AddAeTitlehandlerAsync(MonaiApplicationEntity entity, IH

try
{
ConfigurationOptions config = LoadConfiguration(verbose, configService, client);
CheckConfiguration(configService);
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);

this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {config.Endpoint}...");
this.LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
var result = await client.MonaiScpAeTitle.Create(entity, cancellationToken);

logger.Log(LogLevel.Information, "New MONAI Deploy SCP Application Entity created:");
Expand Down
37 changes: 16 additions & 21 deletions src/CLI/Commands/CommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Monai.Deploy.InformaticsGateway.Client;
using System;
using System.CommandLine;

Expand All @@ -28,12 +27,17 @@ public CommandBase(string name, string description) : base(name, description)

protected ILogger CreateLogger<T>(IHost host)
{
Guard.Against.Null(host, nameof(host));

var loggerFactory = host.Services.GetService<ILoggerFactory>();
return loggerFactory?.CreateLogger<T>();
}

protected void LogVerbose(bool verbose, IHost host, string message)
{
Guard.Against.Null(host, nameof(host));
Guard.Against.NullOrWhiteSpace(message, nameof(message));

if (verbose)
{
var logger = CreateLogger<CommandBase>(host);
Expand All @@ -48,33 +52,24 @@ protected void LogVerbose(bool verbose, IHost host, string message)
}
}

protected ConfigurationOptions LoadConfiguration(bool verbose, IConfigurationService configurationService, IInformaticsGatewayClient client)
protected void AddConfirmationOption() => AddConfirmationOption(this);

protected void AddConfirmationOption(Command command)
{
Guard.Against.Null(configurationService, nameof(configurationService));
Guard.Against.Null(client, nameof(client));
Guard.Against.Null(command, nameof(command));

var configuration = LoadConfiguration(verbose, configurationService);
client.ConfigureServiceUris(new Uri(configuration.Endpoint));
return configuration;
var confirmationOption = new Option<bool>(new[] { "-y", "--yes" }, "Automatic yes to prompts");
command.AddOption(confirmationOption);
}

protected ConfigurationOptions LoadConfiguration(bool verbose, IConfigurationService configurationService)
protected void CheckConfiguration(IConfigurationService configService)
{
Guard.Against.Null(configurationService, nameof(configurationService));

if (configurationService.ConfigurationExists())
Guard.Against.Null(configService, nameof(configService));
if (!configService.IsInitialized)
{
var config = configurationService.Load(verbose);
return config;
throw new ConfigurationException($"Please execute `{AppDomain.CurrentDomain.FriendlyName} config init` to intialize Informatics Gateway.");
}

throw new ConfigurationException($"{Strings.ApplicationName} endpoint not configured. Please run 'config` first.");
}

protected void AddConfirmationOption()
{
var confirmationOption = new Option<bool>(new[] { "-y", "--yes" }, "Automatic yes to prompts");
this.AddOption(confirmationOption);
}
}
}
Loading