Esempio n. 1
0
        private void CleanupDatabase()
        {
            var log = Log.GetLogger();
            var cfg = CapiConfig.GetConfig();

            if (cfg == null)
            {
                throw new ApplicationException("Unable to find config file.");
            }
            var dbBroker = new DbBroker(cfg.AgentDbConnectionString);

            if (dbBroker.Database.EnsureCreated())
            {
                log.Info("Database not found, so it has been created.");
            }
            else
            {
                log.Info("Database found.");
            }

            if (!dbBroker.Database.CanConnect())
            {
                log.Error("Could not connect to database using string: " + cfg.AgentDbConnectionString);
            }
            else
            {
                log.Info("DB Connection established");
            }

            try
            {
                log.Info("DB Connection good? " + dbBroker.Database.CanConnect());
                var failedCases = dbBroker.GetCaseByStatus("Processing");

                foreach (var c in failedCases)
                {
                    var tmp = c;
                    tmp.Status = "Pending";
                    dbBroker.Attempts.Update(tmp);
                    dbBroker.SaveChanges();
                }
                var failedJobs = dbBroker.GetJobByStatus("Processing");
                foreach (var j in failedJobs)
                {
                    var tmp = j;
                    tmp.Status = "Failed";
                    dbBroker.Jobs.Update(tmp);
                    dbBroker.SaveChanges();
                }
            }
            catch (Exception e)
            {
                log.Error("Error while accesing database. If this is due to an incompatible schema, maybe try wiping the database and starting again?");
                log.Error(e);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Builds a Job using details in Recipe
        /// </summary>
        /// <param name="recipe">Contains details of studies to process, source and destinations</param>
        /// <returns></returns>
        public Job Build(Recipe recipe, Attempt attempt)
        {
            if (string.IsNullOrEmpty(recipe.CurrentAccession))
            {
                recipe.CurrentAccession = attempt.CurrentAccession;
            }
            // TODO: We probably don't need to replace the prior accession since the attempt shouldn't have anything at this stage.
            if (string.IsNullOrEmpty(recipe.PriorAccession))
            {
                recipe.PriorAccession = attempt.PriorAccession;
            }

            // Setup out dicom service.
            var dicomSource = CreateDicomSource(recipe.SourceAet);

            // Get patient id
            var patientId = GetPatientId(recipe, dicomSource);

            // A list of all studies for the patient.
            // TODO: I don't love the fact that we can't just use the patient ID which we should have above.
            // But this code is defensive so I don't want to change it and introduce more bugs.
            var allStudiesForPatient =
                GetStudiesForPatient(patientId, recipe.PatientFullName, recipe.PatientBirthDate, dicomSource);

            // Update attempt in DB
            @attempt.PatientId = recipe.PatientId;
            _context.Attempts.Update(@attempt);
            _context.SaveChanges();

            // If there are no studies, have a cry.
            if (allStudiesForPatient.Count < 1)
            {
                throw new StudyNotFoundException(
                          $"No studies for patient [{recipe.PatientFullName}] could be found in node AET: [{dicomSource.RemoteNode.AeTitle}]");
            }

            // Update patient ID in DB for a second time?
            @attempt.PatientId        = allStudiesForPatient.FirstOrDefault().PatientId;
            @attempt.PatientFullName  = allStudiesForPatient.FirstOrDefault().PatientsName;
            @attempt.PatientBirthDate = allStudiesForPatient.FirstOrDefault().PatientBirthDate.ToString("yyyyMMdd");
            _context.Attempts.Update(@attempt);
            _context.SaveChanges();

            // Update the recipe with all the details for the patient?
            recipe = UpdateRecipeWithPatientDetails(recipe, allStudiesForPatient);

            // Find Current Study
            _log.Info("Finding current series using recipe provided...");
            var currentDicomStudy = GetCurrentDicomStudy(recipe, allStudiesForPatient, dicomSource);

            // Update case in DB with patient name and DOB
            @attempt.PatientFullName  = recipe.PatientFullName;
            @attempt.PatientBirthDate = recipe.PatientBirthDate;
            _context.Attempts.Update(@attempt);
            _context.SaveChanges();

            // If we don't have a matching study for current have a cry.
            if (currentDicomStudy == null ||
                currentDicomStudy.Series.Count == 0)
            {
                throw new StudyNotFoundException("No workable series were found for accession");
            }

            // Update attempt with accession number.
            @attempt.CurrentAccession = currentDicomStudy.AccessionNumber;
            @attempt.CurrentSeriesUID = currentDicomStudy.Series.FirstOrDefault().SeriesInstanceUid;
            _context.Attempts.Update(@attempt);
            _context.SaveChanges();

            // Create a new job based on the recipe.
            var job = new Job(recipe, attempt);

            job.Status    = "Pending";
            job.AttemptId = attempt.Id;

            // Setup temp directory for images.
            var capiConfig = CapiConfig.GetConfig();

            try
            {
                job.ProcessingFolder = Path.GetFullPath(Path.Combine(capiConfig.ImagePaths.ImageRepositoryPath, job.Attempt.CurrentAccession + "-" + job.Id));
            }
            catch (Exception ex)
            {
                Log.GetLogger().Error($"{capiConfig.ImagePaths.ImageRepositoryPath} may not be a valid path.");
                Log.GetLogger().Error(ex.Message);
            }
            try
            {
                job.ResultSeriesDicomFolder = Path.GetFullPath(Path.Combine(job.ProcessingFolder, Results));
            }
            catch (Exception ex)
            {
                Log.GetLogger().Error($"{Path.Combine(job.ProcessingFolder, Results)} may not be a valid path.");
                Log.GetLogger().Error(ex.Message);
            }
            try
            {
                job.PriorReslicedSeriesDicomFolder = Path.GetFullPath(Path.Combine(job.ProcessingFolder, PriorResliced));
            }
            catch (Exception ex)
            {
                Log.GetLogger().Error($"{Path.Combine(job.ProcessingFolder, PriorResliced)} may not be a valid path.");
                Log.GetLogger().Error(ex.Message);
            }
            try
            {
                job.ReferenceSeriesDicomFolder = Path.GetFullPath(GetReferenceSeriesForRegistration(job, allStudiesForPatient, dicomSource));
            }
            catch (Exception ex)
            {
                Log.GetLogger().Info($"{GetReferenceSeriesForRegistration(job, allStudiesForPatient, dicomSource)} may not be a valid path.");
            }

            // Find Prior Study (Floating)
            _log.Info("Finding prior series using recipe provided...");
            var studyFixedIndex = allStudiesForPatient.IndexOf(currentDicomStudy);
            var priorDicomStudy =
                GetPriorDicomStudy(recipe, studyFixedIndex, allStudiesForPatient, dicomSource);

            // If we couldn't find the prior study, have a cry.
            if (priorDicomStudy == null)
            {
                throw new StudyNotFoundException("No prior workable series were found");
            }
            // Otherwise update the attempt
            job.Attempt.PriorAccession = priorDicomStudy.AccessionNumber;
            job.Attempt.PatientId      = currentDicomStudy.PatientId;

            // Update attempt with prior accession details.
            @attempt.PriorAccession = priorDicomStudy?.AccessionNumber;
            @attempt.PriorSeriesUID = priorDicomStudy?.Series?.FirstOrDefault()?.SeriesInstanceUid;
            @attempt.SourceAet      = recipe.SourceAet;
            @attempt.DestinationAet = JsonConvert.SerializeObject(recipe.OutputSettings.DicomDestinations);
            @job.RecipeString       = JsonConvert.SerializeObject(job.Recipe, new CapiConfigJsonConverter());
            _context.Attempts.Update(@attempt);
            _context.Jobs.Update(@job);
            _context.SaveChanges();

            // If both current and prior are found, save them to disk for processing
            _log.Info("Saving current series to disk...");
            try
            {
                job.CurrentSeriesDicomFolder =
                    SaveDicomFilesToFilesystem(currentDicomStudy, job.ProcessingFolder, Current, dicomSource);
            }
            catch (Exception ex)
            {
                _log.Error("Failed to save current series dicom files to disk.", ex);
                throw ex;
            }

            if (Directory.EnumerateFiles(job.CurrentSeriesDicomFolder).Count() < 1)
            {
                _log.Error($"Could not find any dicom files for current series in directory {job.CurrentSeriesDicomFolder}. Check that Accession exists and you can perform a CMOVE to this machine.");
                throw new Exception($"Could not find any dicom files for current series in directory {job.CurrentSeriesDicomFolder}. Check that Accession exists and you can perform a CMOVE to this machine.");
            }

            _log.Info($"Saved current series to [{job.CurrentSeriesDicomFolder}]");

            _log.Info("Saving prior series to disk...");
            try
            {
                job.PriorSeriesDicomFolder = SaveDicomFilesToFilesystem(
                    priorDicomStudy, job.ProcessingFolder, Prior, dicomSource);
            }
            catch (Exception ex)
            {
                _log.Error("Failed to save prior series dicom files to disk.", ex);
                throw;
            }

            if (Directory.EnumerateFiles(job.PriorSeriesDicomFolder).Count() < 1)
            {
                _log.Error($"Could not find any dicom files for prior series in directory {job.PriorSeriesDicomFolder}. Check that Accession exists and you can perform a CMOVE to this machine.");
                throw new Exception($"Could not find any dicom files for prior series in directory {job.PriorSeriesDicomFolder}. Check that Accession exists and you can perform a CMOVE to this machine.");
            }

            _log.Info($"Saved prior series to [{job.PriorReslicedSeriesDicomFolder}]");

            // All done.
            return(job);
        }