public FailedCacheFetchRequestProvider(ICacheProgress cacheProgress, int batchSize = 50) { _cacheProgress = cacheProgress; _batchSize = batchSize; Current = null; }
public TestCacheChunk(DateTime fetchDate) { Request = new CacheFetchRequest(null, fetchDate) { ChunkPeriod = new TimeSpan(1, 0, 0) }; }
public override TestCacheChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { var c = new TestCacheChunk(Request.Start); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "!!" + request.Start.ToString("g"))); return(c); }
/// <summary> /// Returns the next <see cref="ICacheFetchRequest"/> based on the <see cref="Current"/> /// </summary> /// <param name="listener"></param> /// <returns></returns> public ICacheFetchRequest GetNext(IDataLoadEventListener listener) { if (_initialRequest == null) { return(Current = _initialRequest = CreateInitialRequest()); } return(Current = CreateNext()); }
public override SMIDataChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"ProcessBasedCacheSource version is {typeof(ProcessBasedCacheSource).Assembly.GetName().Version}. Assembly is {typeof(ProcessBasedCacheSource).Assembly} ")); // Where we are putting the files var cacheDir = new LoadDirectory(Request.CacheProgress.LoadProgress.LoadMetadata.LocationOfFlatFiles).Cache; var cacheLayout = new SMICacheLayout(cacheDir, new SMICachePathResolver("ALL")); Chunk = new SMIDataChunk(Request) { FetchDate = Request.Start, Modality = "ALL", Layout = cacheLayout }; var workingDirectory = cacheLayout.GetLoadCacheDirectory(listener); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Working directory is:" + workingDirectory)); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Fetch Start is:" + request.Start)); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Fetch End is:" + request.End)); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Command is:" + Command)); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Args template is:" + Args)); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Datetime format is:" + TimeFormat)); string args = Args .Replace("%s", request.Start.ToString(TimeFormat)) .Replace("%e", request.End.ToString(TimeFormat)) .Replace("%d", workingDirectory.FullName); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Args resolved is:" + args)); using (var p = new Process()) { p.StartInfo.FileName = Command; p.StartInfo.Arguments = args; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.OutputDataReceived += (sender, a) => listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, a.Data)); p.Start(); p.BeginOutputReadLine(); p.WaitForExit(); listener.OnNotify(this, new NotifyEventArgs(p.ExitCode == 0 ? ProgressEventType.Information : ProgressEventType.Warning, "Process exited with code " + p.ExitCode)); if (p.ExitCode != 0 && ThrowOnNonZeroExitCode) { throw new Exception("Process exited with code " + p.ExitCode); } } return(Chunk); }
public override ICacheChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { //Data is never available for download if (runs < 10) { runs++; return(new DoNothingCacheChunk(CatalogueRepository) { RunIteration = runs }); } return(null); }
public ICacheFetchRequest GetNext(IDataLoadEventListener listener) { // If we haven't provided one, give out _initialRequest if (Current == null) { Current = _initialRequest; } else { Current = Current.GetNext(); // We have provided requests for the whole time period if (Current.Start > _endDateInclusive) { return(null); } } return(Current); }
public ICacheFetchRequest GetNext(IDataLoadEventListener listener) { // If we haven't provided one, give out _initialRequest if (Current == null) { Current = _initialRequest; } else { Current = Current.GetNext(); // We have provided requests for more than one day if (Current.Start >= _initialRequest.Start.AddDays(1)) { return(null); } } // Otherwise we have provided our request so signal there is none left return(Current); }
/// <summary> /// /// </summary> /// <returns>Next CacheFetchRequest or null if there are no further request failures to process</returns> public ICacheFetchRequest GetNext(IDataLoadEventListener listener) { if (!_failuresToProvide.Any()) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Getting next batch of request failures from database.")); GetNextBatchFromDatabase(); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Fetched " + _failuresToProvide.Count + " failures from database.")); // If there are still no failures in the queue then we're done if (!_failuresToProvide.Any()) { return(null); } } // Create a new CacheFetchRequest from the failure var cacheFetchFailure = _failuresToProvide.Dequeue(); Current = new CacheFetchRequest(cacheFetchFailure, _cacheProgress); return(Current); }
public override TestDataWriterChunk DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { // don't load anything for today onwards var today = DateTime.Now.Subtract(DateTime.Now.TimeOfDay); if (Request.Start > today) { return(null); } DateTime currentDay = Request.Start; List <FileInfo> toReturn = new List <FileInfo>(); while (currentDay <= Request.End) { toReturn.Add(GetFileForDay(currentDay)); currentDay = currentDay.AddDays(1); } return(new TestDataWriterChunk(Request, toReturn.ToArray())); }
/// <summary> /// Enforces behaviour required for logging unsuccessful cache requests and providing implementation-independent checks, so that the plugin author /// doesn't need to remember to call Request[Succeeded|Failed] or do general checks. Plugin author provides implementation-specific caching in /// the 'DoGetChunk' function. /// </summary> /// <param name="listener"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public virtual T GetChunk(IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { Request = RequestProvider.GetNext(listener); // If GetNext returns null, there are no further failures to process and we're done if (Request == null) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "The RequestProvider has no more requests to provide (RequestProvider.GetNext returned null)")); return(null); } if (Request.CacheProgress == null) { throw new InvalidOperationException("The request has no CacheProgress item (in this case to determine when the lag period begins)"); } // Check if we will stray into the lag period with this fetch and if so signal we are finished var cacheLagPeriod = Request.CacheProgress.GetCacheLagPeriod(); if (cacheLagPeriod != null && cacheLagPeriod.TimeIsWithinPeriod(Request.End)) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "The Request is for a time within the Cache Lag Period. This means we are up-to-date and can stop now.")); return(null); } Chunk = DoGetChunk(Request, listener, cancellationToken); if (Chunk != null && Chunk.Request == null && Request != null) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Error, "DoGetChunk completed and set a Chunk Successfully but the Chunk.Request was null. Try respecting the Request property in your class when creating your Chunk.")); } return(Chunk); }
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); }
public SingleDayCacheFetchRequestProvider(ICacheFetchRequest initialRequest) { Current = null; _initialRequest = initialRequest; }
public override SMIDataChunk DoGetChunk(ICacheFetchRequest cacheRequest, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"PACSSource version is {typeof(PACSSource).Assembly.GetName().Version}. Assembly is {typeof(PACSSource).Assembly} ")); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"Fo-Dicom version is {typeof(DicomClient).Assembly.GetName().Version}. Assembly is {typeof(DicomClient).Assembly} ")); var dicomConfiguration = GetConfiguration(); var requestSender = new DicomRequestSender(dicomConfiguration, listener); var dateFrom = Request.Start; var dateTo = Request.End; 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 }; ConcurrentBag <StudyToFetch> studiesToOrder = new ConcurrentBag <StudyToFetch>(); CachingSCP.OnEndProcessingCStoreRequest = (storeRequest, storeResponse) => { SaveSopInstance(storeRequest, cacheLayout, listener); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Debug, "Stored sopInstance" + storeRequest.SOPInstanceUID.UID)); }; //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)) { DicomClient client = new DicomClient(dicomConfiguration.RemoteAetUri.Host, dicomConfiguration.RemoteAetUri.Port, false, dicomConfiguration.LocalAetTitle, dicomConfiguration.RemoteAetTitle); try { // Find a list of studies #region Query listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Requesting Studies from " + dateFrom + " to " + dateTo)); var request = CreateStudyRequestByDateRangeForModality(dateFrom, dateTo, Modality); request.OnResponseReceived += (req, response) => { if (Filter(_whitelist, response)) { studiesToOrder.Add(new StudyToFetch(response.Dataset.GetSingleValue <string>(DicomTag.StudyInstanceUID))); } }; requestSender.ThrottleRequest(request, client, cancellationToken.AbortToken); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Debug, "Total filtered studies for " + dateFrom + " to " + dateTo + "is " + studiesToOrder.Count)); #endregion //go and get them #region Retrieval var transferStopwatch = new Stopwatch(); StudyToFetch current; int consecutiveFailures = 0; //While we have things to fetch while (studiesToOrder.TryTake(out current)) { transferStopwatch.Restart(); //delay value in mills if (dicomConfiguration.TransferCooldownInMilliseconds != 0) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Transfers sleeping for " + dicomConfiguration.TransferCooldownInMilliseconds / 1000 + "seconds")); Task.Delay(dicomConfiguration.TransferCooldownInMilliseconds, cancellationToken.AbortToken).Wait(cancellationToken.AbortToken); } bool done = false; //Build fetch command that Study var cMoveRequest = CreateCMoveByStudyUid(LocalAETitle, current.StudyUid, listener); //Register callbacks cMoveRequest.OnResponseReceived += (requ, response) => { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Debug, $"Got {response.Status.State} response for {requ}. Items remaining {response.Remaining}")); switch (response.Status.State) { case DicomState.Pending: case DicomState.Warning: // ignore break; case DicomState.Cancel: case DicomState.Failure: consecutiveFailures++; if (current.RetryCount < MaxRetries) { // put it back in the bag with a increased retry count current.RetryCount++; studiesToOrder.Add(current); } // final state done = true; break; case DicomState.Success: // final state consecutiveFailures = 0; done = true; break; } }; //send the command to the server //tell user what we are sending listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, CMoveRequestToString(cMoveRequest, current.RetryCount + 1))); //do not use requestSender.ThrottleRequest(cMoveRequest, cancellationToken); //TODO is there any need to throtttle this request given its lifetime requestSender.ThrottleRequest(cMoveRequest, client, cancellationToken.AbortToken); //enforce a minimum timeout var swStudyTransfer = Stopwatch.StartNew(); bool hasTransferTimedOut = false; do { Task.Delay(Math.Max(100, dicomConfiguration.TransferPollingInMilliseconds), cancellationToken.AbortToken) .Wait(cancellationToken.AbortToken); hasTransferTimedOut = swStudyTransfer.ElapsedMilliseconds > dicomConfiguration.TransferTimeOutInMilliseconds; }while(!done && !hasTransferTimedOut); // Study has finished being fetched (or timed out) if (hasTransferTimedOut) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Abandonning fetch of study " + current.StudyUid)); } if (consecutiveFailures > 5) { throw new Exception("Too many consecutive failures, giving up"); } // 1 failure = study not available, 2 failures = system is having a bad day? if (consecutiveFailures > 1) { //wait 4 minutes then 6 minutes then 8 minutes, eventually server will start responding again? int sleepFor = consecutiveFailures * 2 * 60_000; listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, $"Sleeping for {sleepFor}ms due to {consecutiveFailures} consecutive failures")); Task.Delay(sleepFor, cancellationToken.AbortToken) .Wait(cancellationToken.AbortToken); } } #endregion } finally { server.Stop(); } } return(Chunk); }
/// <summary> /// Handles the current <paramref name="request"/> returning an appropriate <see cref="ICacheChunk"/> for the time range specified. /// </summary> /// <param name="request">The period of time we want to fetch</param> /// <param name="listener">For auditing progress during the fetch</param> /// <param name="cancellationToken">Indicates if user is trying to cancel the process</param> public abstract T DoGetChunk(ICacheFetchRequest request, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken);
public TestDataWriterChunk(ICacheFetchRequest request, FileInfo[] files) { Request = request; Files = files; }
public SMIDataChunk(ICacheFetchRequest request) { Request = request; }
public override SMIDataChunk DoGetChunk(ICacheFetchRequest cacheRequest, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"CFindSource version is {typeof(CFindSource).Assembly.GetName().Version}. Assembly is {typeof(PACSSource).Assembly} ")); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"Fo-Dicom version is {typeof(DicomClient).Assembly.GetName().Version}. Assembly is {typeof(DicomClient).Assembly} ")); var dicomConfiguration = GetConfiguration(); var requestSender = new DicomRequestSender(dicomConfiguration, listener); var dateFrom = Request.Start; var dateTo = Request.End; 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 }; // Create filepath for the results of the C-Find var workingDirectory = cacheLayout.GetLoadCacheDirectory(listener); var filename = $"{dateFrom:yyyyMMddhhmmss}.csv"; var filepath = Path.Combine(workingDirectory.FullName, filename); var sw = new StreamWriter(filepath); var writer = new CsvWriter(sw, new CsvConfiguration(CultureInfo.CurrentCulture)); WriteHeaders(writer); DicomClient client = new DicomClient(dicomConfiguration.RemoteAetUri.Host, dicomConfiguration.RemoteAetUri.Port, false, dicomConfiguration.LocalAetTitle, dicomConfiguration.RemoteAetTitle); try { // Find a list of studies #region Query listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Requesting Studies from " + dateFrom + " to " + dateTo)); int responses = 0; var request = CreateStudyRequestByDateRangeForModality(dateFrom, dateTo, Modality); request.OnResponseReceived += (req, response) => { if (Filter(Whitelist, response)) { Interlocked.Increment(ref responses); WriteResult(writer, response); } }; requestSender.ThrottleRequest(request, client, cancellationToken.AbortToken); listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Debug, "Total filtered studies for " + dateFrom + " to " + dateTo + " is " + responses)); #endregion } finally { writer.Dispose(); } return(Chunk); }
public MultiDayCacheFetchRequestProvider(ICacheFetchRequest initialRequest, DateTime endDateInclusive) { Current = null; _initialRequest = initialRequest; _endDateInclusive = endDateInclusive; }