Compare commits
2 Commits
master
...
feature/mi
| Author | SHA1 | Date | |
|---|---|---|---|
| ae69d5ef41 | |||
| c0ff0f35c3 |
22
Dockerfile
Normal file
22
Dockerfile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Use the official .NET SDK image to build the app
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the csproj and restore any dependencies
|
||||||
|
COPY *.csproj ./
|
||||||
|
RUN dotnet restore
|
||||||
|
|
||||||
|
# Copy the entire project and build the app
|
||||||
|
COPY . ./
|
||||||
|
RUN dotnet publish -c Release -o out
|
||||||
|
|
||||||
|
# Use the official .NET runtime image to run the app
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:6.0
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build-env /app/out .
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Entry point to run the application
|
||||||
|
ENTRYPOINT ["dotnet", "DicomMigratorApp.dll"]
|
||||||
143
Program.cs
143
Program.cs
@ -8,6 +8,7 @@ using System.Collections.Generic;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace DicomMigratorApp
|
namespace DicomMigratorApp
|
||||||
{
|
{
|
||||||
@ -20,8 +21,8 @@ namespace DicomMigratorApp
|
|||||||
private static string targetIP;
|
private static string targetIP;
|
||||||
private static string senderAET;
|
private static string senderAET;
|
||||||
private static string targetAET;
|
private static string targetAET;
|
||||||
private static string folderLocation;
|
|
||||||
private static int targetPort;
|
private static int targetPort;
|
||||||
|
private static string db_status_to_pick;
|
||||||
|
|
||||||
static async Task Main(string[] args)
|
static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
@ -38,12 +39,12 @@ namespace DicomMigratorApp
|
|||||||
|
|
||||||
_logger.LogInformation("Application started");
|
_logger.LogInformation("Application started");
|
||||||
|
|
||||||
connectionString = "Server=127.0.0.1;Port=3306;Database=dms_db;User Id=root;Password=Rootmatrix23@;";
|
connectionString = Environment.GetEnvironmentVariable("ConnectionStrings__DefaultConnection") ?? "Server=127.0.0.1;Port=3306;Database=dms_db;User Id=root;Password=Rootmatrix23@;";
|
||||||
targetIP = "127.0.0.1";
|
targetIP = Environment.GetEnvironmentVariable("Dest__IP") ?? "127.0.0.1";
|
||||||
senderAET = "MYAE";
|
senderAET = Environment.GetEnvironmentVariable("Sender__AET") ?? "MYAE";
|
||||||
targetAET = "ORTHANC";
|
targetAET = Environment.GetEnvironmentVariable("Dest__AET") ?? "ORTHANC";
|
||||||
folderLocation = "D:\\dicom_imags\\";
|
var targetPortStr = Environment.GetEnvironmentVariable("Dest__Port") ?? "4242";
|
||||||
var targetPortStr = "4242";
|
db_status_to_pick = Environment.GetEnvironmentVariable("DB_STATUS") ?? "MIGRATION_QUEUE";
|
||||||
|
|
||||||
if (!int.TryParse(targetPortStr, out targetPort))
|
if (!int.TryParse(targetPortStr, out targetPort))
|
||||||
{
|
{
|
||||||
@ -51,126 +52,134 @@ namespace DicomMigratorApp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
while (true)
|
||||||
{
|
{
|
||||||
var migrationStudy = await GetMigrationStudy(connectionString);
|
|
||||||
if (migrationStudy == null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No studies found for migration.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Retrieved studyDetails for Migration");
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await MigrateStudy(migrationStudy.StudyInstanceUID, folderLocation + migrationStudy.StudyInstanceUID);
|
var imagePaths = await GetMigrationImages(connectionString,db_status_to_pick);
|
||||||
await UpdateSourceCFind(connectionString, migrationStudy.StudyInstanceUID, "MIGRATION_COMPLETE");
|
if (imagePaths == null || imagePaths.Count == 0)
|
||||||
|
{
|
||||||
|
await Task.Delay(5000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var image in imagePaths)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await MigrateImage(image.Path);
|
||||||
|
await UpdateImagePathStatus(connectionString, image.Id, "MIGRATION_COMPLETE");
|
||||||
|
}
|
||||||
|
catch (DicomAssociationRejectedException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Association rejected for image path {image.Path}");
|
||||||
|
await UpdateImagePathStatus(connectionString, image.Id, "MIGRATION_ERRORED");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"An error occurred while migrating image path {image.Path}");
|
||||||
|
await UpdateImagePathStatus(connectionString, image.Id, "MIGRATION_ERRORED");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (DicomAssociationRejectedException ex)
|
catch (MySqlException ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"Association rejected for studyInstanceUID {migrationStudy.StudyInstanceUID}");
|
_logger.LogError(ex, "An error occurred while connecting to the database");
|
||||||
await UpdateSourceCFind(connectionString, migrationStudy.StudyInstanceUID, "MIGRATION_ERRORED");
|
break;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"An error occurred while retrieving or saving studyInstanceUID {migrationStudy.StudyInstanceUID}");
|
_logger.LogError(ex, "An error occurred in the main processing loop");
|
||||||
await UpdateSourceCFind(connectionString, migrationStudy.StudyInstanceUID, "MIGRATION_ERRORED");
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "An error occurred in the main processing loop");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<SourceStudy> GetMigrationStudy(string connectionString)
|
private static async Task<List<ImageRecord>> GetMigrationImages(string connectionString, string db_status_to_pick)
|
||||||
{
|
{
|
||||||
var qrStudy = new SourceStudy();
|
var imagePaths = new List<ImageRecord>();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var connection = new MySqlConnection(connectionString))
|
using (var connection = new MySqlConnection(connectionString))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Opening a connection to the database");
|
|
||||||
await connection.OpenAsync();
|
await connection.OpenAsync();
|
||||||
_logger.LogInformation("Database connection established");
|
_logger.LogInformation("Database connection established");
|
||||||
var command = new MySqlCommand("SELECT study_instance_uid,patient_id,status FROM source_cfind WHERE status='QR_COMPLETE' LIMIT 1", connection);
|
|
||||||
|
var command = new MySqlCommand("SELECT id, image_path FROM priority_migration_image WHERE status=@Status order by priority LIMIT 10", connection);
|
||||||
|
command.Parameters.AddWithValue("@Status", db_status_to_pick);
|
||||||
|
|
||||||
var reader = await command.ExecuteReaderAsync();
|
var reader = await command.ExecuteReaderAsync();
|
||||||
|
|
||||||
while (await reader.ReadAsync())
|
while (await reader.ReadAsync())
|
||||||
{
|
{
|
||||||
qrStudy = new SourceStudy
|
imagePaths.Add(new ImageRecord
|
||||||
{
|
{
|
||||||
StudyInstanceUID = reader.IsDBNull(0) ? null : reader.GetString(0),
|
Id = reader.IsDBNull(0) ? 0 : reader.GetInt32(0),
|
||||||
PatientID = reader.IsDBNull(1) ? null : reader.GetString(1),
|
Path = reader.IsDBNull(1) ? null : reader.GetString(1)
|
||||||
Status = reader.IsDBNull(2) ? null : reader.GetString(2)
|
});
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.Close();
|
reader.Close();
|
||||||
}
|
}
|
||||||
if (qrStudy.StudyInstanceUID != null)
|
_logger.LogInformation($"Retrieved {imagePaths.Count} image paths for migration");
|
||||||
{
|
|
||||||
_logger.LogInformation("Picked study to be migrated from the database");
|
|
||||||
await UpdateSourceCFind(connectionString, qrStudy.StudyInstanceUID, "MIGRATION_INPROGRESS");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qrStudy = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error retrieving study to be migrated from the database");
|
_logger.LogError(ex, "Error retrieving image paths from the database");
|
||||||
|
throw; // Re-throw the exception to ensure it is caught by the outer try-catch block
|
||||||
}
|
}
|
||||||
|
|
||||||
return qrStudy;
|
return imagePaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task UpdateSourceCFind(string connectionString, string study_instance_uid, string updateStatus)
|
private static async Task UpdateImagePathStatus(string connectionString, int imageId, string updateStatus)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var connection = new MySqlConnection(connectionString))
|
using (var connection = new MySqlConnection(connectionString))
|
||||||
{
|
{
|
||||||
await connection.OpenAsync();
|
await connection.OpenAsync();
|
||||||
var command = new MySqlCommand("UPDATE source_cfind SET status = @Status WHERE study_instance_uid = @StudyInstanceUID", connection);
|
var command = new MySqlCommand("UPDATE priority_migration_image SET status = @Status WHERE id = @ImageId", connection);
|
||||||
|
|
||||||
command.Parameters.AddWithValue("@StudyInstanceUID", study_instance_uid);
|
command.Parameters.AddWithValue("@ImageId", imageId);
|
||||||
command.Parameters.AddWithValue("@Status", updateStatus);
|
command.Parameters.AddWithValue("@Status", updateStatus);
|
||||||
|
|
||||||
await command.ExecuteNonQueryAsync();
|
await command.ExecuteNonQueryAsync();
|
||||||
_logger.LogInformation($"Updated source C-FIND record for study instance uid {study_instance_uid}");
|
_logger.LogInformation($"Updated image path record for image ID {imageId} with status {updateStatus}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"Error updating source study record for study {study_instance_uid}");
|
_logger.LogError(ex, $"Error updating image path record for image ID {imageId}");
|
||||||
|
throw; // Re-throw the exception to ensure it is caught by the outer try-catch block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task MigrateStudy(string studyInstanceUID, string folderPath)
|
private static async Task MigrateImage(string imagePath)
|
||||||
{
|
{
|
||||||
var client = DicomClientFactory.Create(targetIP, targetPort, false, senderAET, targetAET);
|
try
|
||||||
|
|
||||||
var files = System.IO.Directory.GetFiles(folderPath, "*");
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
{
|
||||||
var dicomFile = await DicomFile.OpenAsync(file);
|
var client = DicomClientFactory.Create(targetIP, targetPort, false, senderAET, targetAET);
|
||||||
|
|
||||||
|
var dicomFile = await DicomFile.OpenAsync(imagePath);
|
||||||
await client.AddRequestAsync(new DicomCStoreRequest(dicomFile));
|
await client.AddRequestAsync(new DicomCStoreRequest(dicomFile));
|
||||||
|
|
||||||
|
await client.SendAsync();
|
||||||
|
|
||||||
|
_logger.LogInformation($"Migrated image {imagePath} to target AET {targetAET}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Error migrating image {imagePath}");
|
||||||
|
throw; // Re-throw the exception to ensure it is caught by the outer try-catch block
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.SendAsync();
|
|
||||||
|
|
||||||
_logger.LogInformation($"Migrated studyInstanceUID {studyInstanceUID} to target AET {targetAET}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SourceStudy
|
class ImageRecord
|
||||||
{
|
{
|
||||||
public string PatientID { get; set; }
|
public int Id { get; set; }
|
||||||
public string StudyInstanceUID { get; set; }
|
public string Path { get; set; }
|
||||||
public string Status { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
docker-compose.yml
Normal file
21
docker-compose.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
dicom-migrator-app:
|
||||||
|
image: seyfertsoft/dicommigratorapp:1.0.0
|
||||||
|
container_name: dicommigrator
|
||||||
|
environment:
|
||||||
|
- "ConnectionStrings__DefaultConnection=Server=mysqldb;Port=3306;Database=dms_db;User Id=root;Password=Rootmatrix23@;"
|
||||||
|
- Dest__IP=127.0.0.1
|
||||||
|
- Sender__AET=MYAE
|
||||||
|
- Dest__AET=ORTHANC
|
||||||
|
- Dest__Port=4242
|
||||||
|
volumes:
|
||||||
|
- /path/to/images1:/app/images1
|
||||||
|
- /path/to/images2:/app/images2
|
||||||
|
networks:
|
||||||
|
- dmsnetwork
|
||||||
|
|
||||||
|
networks:
|
||||||
|
dmsnetwork:
|
||||||
|
external: true
|
||||||
Loading…
x
Reference in New Issue
Block a user