예제 #1
0
        public override SMIDataChunk DoGetChunk(ICacheFetchRequest cacheRequest, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken)
        {
            #region assigns
            var dicomConfiguration  = GetConfiguration();
            var requestSender       = new DicomRequestSender(dicomConfiguration, listener);
            var dateFrom            = Request.Start;
            var dateTo              = Request.End;
            var hasTransferTimedOut = false;
            CachingSCP.LocalAet = LocalAETitle;
            CachingSCP.Listener = listener;

            if (PatientIdWhitelistColumnInfo != null && !IgnoreWhiteList)
            {
                GetWhitelist(listener);
            }


            //temp dir
            var cacheDir    = new LoadDirectory(Request.CacheProgress.LoadProgress.LoadMetadata.LocationOfFlatFiles).Cache;
            var cacheLayout = new SMICacheLayout(cacheDir, new SMICachePathResolver(Modality));


            Chunk = new SMIDataChunk(Request)
            {
                FetchDate = dateFrom,
                Modality  = Modality,
                Layout    = cacheLayout
            };
            //            IOrder order = new ItemsBasedOrder(dateFrom, dateTo, PlacementMode.PlaceThenFill,OrderLevel, listener);
            IOrder  order                = new HierarchyBasedOrder(dateFrom, dateTo, PlacementMode.PlaceThenFill, OrderLevel, listener);
            IPicker picker               = null;
            var     pickerFilled         = false;
            var     transferTimeOutTimer = new Timer(dicomConfiguration.TransferTimeOutInMilliseconds);
            transferTimeOutTimer.Elapsed += (source, eventArgs) =>
            {
                hasTransferTimedOut = true;
                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Information, "Transfer Timeout Exception Generated"));
                throw new TimeoutException("Transfer Timeout Exception");
            };

            CachingSCP.OnEndProcessingCStoreRequest = (storeRequest, storeResponse) =>
            {
                var item = new Item(storeRequest);
                transferTimeOutTimer.Reset();
                if (picker != null)
                {
                    picker.Fill(item);
                    pickerFilled = picker.IsFilled();
                }
                SaveSopInstance(storeRequest, cacheLayout, listener);
                listener.OnNotify(this,
                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                      "Stored sopInstance" + storeRequest.SOPInstanceUID.UID));
            };
            #endregion

            //helps with tyding up resources if we abort or through an exception and neatly avoids ->  Access to disposed closure
            using (var server = (DicomServer <CachingSCP>)DicomServer.Create <CachingSCP>(dicomConfiguration.LocalAetUri.Port))
            {
                try
                {
                    // Find a list of studies
                    #region Query

                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Information,
                                                          "Requesting Studies from " + dateFrom + " to " + dateTo));
                    var studyUids = new List <string>();
                    var request   = CreateStudyRequestByDateRangeForModality(dateFrom, dateTo, Modality);
                    request.OnResponseReceived += (req, response) =>
                    {
                        if (Filter(_whitelist, response))
                        {
                            studyUids.Add(response.Dataset.GetSingleValue <string>(DicomTag.StudyInstanceUID));
                        }
                    };
                    requestSender.ThrottleRequest(request, cancellationToken);
                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Debug,
                                                          "Total filtered studies for " + dateFrom + " to " + dateTo + "is " + studyUids.Count));
                    foreach (var studyUid in studyUids)
                    {
                        listener.OnNotify(this,
                                          new NotifyEventArgs(ProgressEventType.Debug,
                                                              "Sending series query for study" + studyUid));
                        var seriesUids = new List <string>();
                        request = CreateSeriesRequestByStudyUid(studyUid);
                        request.OnResponseReceived += (req, response) =>
                        {
                            if (response.Dataset == null)
                            {
                                return;
                            }
                            var seriesInstanceUID = response.Dataset.GetSingleValue <string>(DicomTag.SeriesInstanceUID);
                            if (seriesInstanceUID != null)
                            {
                                seriesUids.Add(seriesInstanceUID);
                            }
                        };
                        requestSender.ThrottleRequest(request, cancellationToken);
                        listener.OnNotify(this,
                                          new NotifyEventArgs(ProgressEventType.Debug,
                                                              "Total series for " + studyUid + "is " + seriesUids.Count));
                        foreach (var seriesUid in seriesUids)
                        {
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Debug,
                                                                  "Sending image query for series" + seriesUid));
                            request = CreateSopRequestBySeriesUid(seriesUid);
                            int imageCount = 0;
                            request.OnResponseReceived += (req, response) =>
                            {
                                if (response.Dataset == null)
                                {
                                    return;
                                }

                                var sopUid    = response.Dataset.GetSingleValue <string>(DicomTag.SOPInstanceUID);
                                var patientId = response.Dataset.GetSingleValue <string>(DicomTag.PatientID);

                                if (sopUid != null && patientId != null)
                                {
                                    //Place order
                                    order.Place(patientId, studyUid, seriesUid, sopUid);
                                    imageCount++;
                                }
                            };
                            requestSender.ThrottleRequest(request, cancellationToken);
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Debug,
                                                                  "Successfully finished image query for " + seriesUid + " Toal images in series = " + imageCount));
                        }
                        listener.OnNotify(this,
                                          new NotifyEventArgs(ProgressEventType.Debug,
                                                              "Successfully finished series query for " + studyUid));
                    }
                    listener.OnNotify(this,
                                      new NotifyEventArgs(ProgressEventType.Debug,
                                                          "Successfully finished query phase"));

                    #endregion
                    //go and get them
                    #region Retrieval

                    var transferStopwatch = new Stopwatch();
                    //start building request to fill orders
                    //get the picker - the for loop avoids sleeping after all the transfers have finished and attempting dequeue on empty queue
                    for (int delay = 0, transferTimerPollingPeriods;
                         order.HasNextPicker() && !hasTransferTimedOut;
                         delay = (int)(dicomConfiguration.TransferDelayFactor * transferTimerPollingPeriods * dicomConfiguration.TransferPollingInMilliseconds)
                                 + dicomConfiguration.TransferCooldownInMilliseconds
                         )
                    {
                        transferStopwatch.Restart();
                        //delay value in mills
                        if (delay != 0)
                        {
                            listener.OnNotify(this,
                                              new NotifyEventArgs(ProgressEventType.Information,
                                                                  "Transfers sleeping for " + delay / 1000 + "seconds"));
                            Task.Delay(delay, cancellationToken.AbortToken).Wait(cancellationToken.AbortToken);
                        }

                        //set this here prior to request
                        pickerFilled = false;
                        transferTimerPollingPeriods = 0;
                        //get next picker
                        picker = order.NextPicker();
                        //  A CMove will be performed if the storescp exists and this storescp is known to the QRSCP:
                        var cMoveRequest = picker.GetDicomCMoveRequest(LocalAETitle);

                        /* this won't work which means we cannot enforce (low) priority
                         * cMoveRequest.Priority=DicomPriority.Low;*/

                        cMoveRequest.OnResponseReceived += (requ, response) =>
                        {
                            if (response.Status.State == DicomState.Pending)
                            {
                                listener.OnNotify(this,
                                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                                      "Request: " + requ.ToString() + "items remaining: " + response.Remaining));
                            }
                            else if (response.Status.State == DicomState.Success)
                            {
                                listener.OnNotify(this,
                                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                                      "Request: " + requ.ToString() + "completed successfully"));
                            }
                            else if (response.Status.State == DicomState.Failure)
                            {
                                listener.OnNotify(this,
                                                  new NotifyEventArgs(ProgressEventType.Debug,
                                                                      "Request: " + requ.ToString() + "failed to download: " + response.Failures));
                            }
                        };

                        listener.OnProgress(this,
                                            new ProgressEventArgs(CMoveRequestToString(cMoveRequest),
                                                                  new ProgressMeasurement(picker.Filled(), ProgressType.Records, picker.Total()),
                                                                  transferStopwatch.Elapsed));
                        //do not use requestSender.ThrottleRequest(cMoveRequest, cancellationToken);
                        //TODO is there any need to throtttle this request given its lifetime
                        DicomClient client = new DicomClient();
                        requestSender.ThrottleRequest(cMoveRequest, client, cancellationToken);
                        transferTimeOutTimer.Reset();
                        while (!pickerFilled && !hasTransferTimedOut)
                        {
                            Task.Delay(dicomConfiguration.TransferPollingInMilliseconds, cancellationToken.AbortToken)
                            .Wait(cancellationToken.AbortToken);
                            transferTimerPollingPeriods++;
                        }
                        transferTimeOutTimer.Stop();
                        client.Release();
                        listener.OnProgress(this,
                                            new ProgressEventArgs(CMoveRequestToString(cMoveRequest),
                                                                  new ProgressMeasurement(picker.Filled(), ProgressType.Records, picker.Total()),
                                                                  transferStopwatch.Elapsed));
                    }

                    #endregion
                }
                finally
                {
                    server.Stop();
                }
            }
            return(Chunk);
        }