public async Task Upload(int taskID, LITEConnection connection, SemaphoreSlim toEGSSignal, ISendToAllHubsService sendToAllHubsService)
        {
            Connection           = connection;
            ToEGSSignal          = toEGSSignal;
            SendToAllHubsService = sendToAllHubsService;

            var taskInfo = $"task: {taskID} connection: {Connection.name}";

            _logger.Log(LogLevel.Debug, $"{taskInfo} Entering Upload");

            try
            {
                await UploadImpl(taskID);
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (OperationCanceledException)
            {
                _logger.Log(LogLevel.Warning, $"Wait Operation Canceled. Exiting Upload");
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, taskInfo);
                _logger.Log(LogLevel.Critical, $"{taskInfo} Exiting Upload");
            }
            finally
            {
                _taskManager.Stop($"{Connection.name}.Upload");
            }
        }
        public void Purge(int taskID, LITEConnection connection)
        {
            Connection = connection;
            var taskInfo = $"task: {taskID}";

            var profile = _profileStorage.Current;

            //purge temp
            Directory.CreateDirectory(Connection.resourcePath);
            _logger.Log(LogLevel.Debug, $"{taskInfo} Purging {Connection.resourcePath}");

            var resources = _util.DirSearch(Connection.resourcePath, "*.*");

            foreach (var file in resources)
            {
                try
                {
                    PurgeFile(profile, file, taskInfo);
                }
                catch (Exception e)
                {
                    _logger.LogFullException(e);
                }
            }

            _util.CleanUpDirectory(Connection.resourcePath);
        }
        private async Task ProcessItem(int taskID, RoutedItem routedItem, LITEConnection connection, IHttpManager httpManager)
        {
            var taskInfo = $"task: {taskID} connection: {Connection.name}";

            if (routedItem.lastAttempt == null || routedItem.lastAttempt >= DateTime.Now.AddMinutes(-connection.retryDelayMinutes)) //not attempted lately
            {
                await Task.CompletedTask;
                return;
            }

            routedItem.attempts++;
            if (routedItem.attempts > 1)
            {
                _logger.Log(LogLevel.Debug, $"{taskInfo} {routedItem.sourceFileName} second attempt.");
            }
            routedItem.lastAttempt = DateTime.Now;

            if (routedItem.attempts > connection.maxAttempts)
            {
                _logger.Log(LogLevel.Warning, $"Resource {routedItem.resource} exceeded max attempts.  Deleting item.");

                if (await _deleteEGSResourceService.DeleteEGSResource(taskID, routedItem, connection, httpManager))
                {
                    _routedItemManager.Init(routedItem);
                    _routedItemManager.Dequeue(connection, connection.fromEGS, nameof(connection.fromEGS), error: false);
                }
                else
                {
                    routedItem.Error = "Exceeded maxAttempts";
                    _routedItemManager.Init(routedItem);
                    _routedItemManager.Dequeue(connection, connection.fromEGS, nameof(connection.fromEGS), error: true);
                }
            }

            switch (Connection.protocol)
            {
            case Protocol.Http:
                //  while (!LITETask.CanStart($"{name}.DownloadViaHttp"))
                //  {
                //      await Task.Delay(LITE.profile.taskDelay).ConfigureAwait(false);
                //  }
                var  newTaskID = _taskManager.NewTaskID();
                Task task      = new Task(new Action(async() => await _downloadViaHttpService.DownloadViaHttp(newTaskID, routedItem, connection, httpManager)), _taskManager.cts.Token);
                await _taskManager.Start(newTaskID, task, $"{Connection.name}.DownloadViaHttp", routedItem.resource, isLongRunning : false).ConfigureAwait(false);

                //await DownloadViaHttp(newTaskID, ri).ConfigureAwait(false);
                break;
                // case Protocol.UDT:
                //     await DownloadViaUDTShell(remoteHostname, remotePort, $"{routedItem.box + "/" + routedItem.resource}", LITE.profile.tempPath + Path.DirectorySeparatorChar + "toScanner", taskID);
                //     break;
            }
        }
        public async Task PresentAsResource(List <RoutedItem> batch, int taskID, LITEConnection connection, ISendToAllHubsService sendToAllHubs)
        {
            Connection = connection;
            try
            {
                var path = Connection.resourcePath + Path.DirectorySeparatorChar + Connection.name + Path.DirectorySeparatorChar + "Resource" + Path.DirectorySeparatorChar + "batch" + Path.DirectorySeparatorChar + System.Guid.NewGuid();
                Directory.CreateDirectory(path);

                //Move all files in batch to separate folder
                foreach (var ri in batch)
                {
                    File.Move(ri.sourceFileName, path + Path.DirectorySeparatorChar + ri.sourceFileName.Substring(ri.sourceFileName.LastIndexOf(Path.DirectorySeparatorChar)));
                    ri.sourceFileName = path + Path.DirectorySeparatorChar + ri.sourceFileName.Substring(ri.sourceFileName.LastIndexOf(Path.DirectorySeparatorChar));
                }

                var file = path + ".zip";

                //zip up files and meta
                ZipFile.CreateFromDirectory(path, file);


                //protect the file
                //var protected file = Crypto.Protect(file)


                //let EGGS know it's available, or when we convert udt to .net core then perhaps push so no open socket required on client.
                await sendToAllHubs.SendToAllHubs(X509CertificateService.ServicePointName, file);

                //Dequeue
                foreach (var ri in batch)
                {
                    _routedItemManager.Init(ri);
                    _routedItemManager.Dequeue(Connection, Connection.toEGS, nameof(Connection.toEGS), error: false);
                }
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (Exception e)
            {
                _logger.LogFullException(e);
            }
        }
        public async Task <bool> ping(LITEConnection connection, IHttpManager httpManager)
        {
            var taskInfo   = $"connection: {Connection.name}";
            var httpClient = _liteHttpClient.GetClient(connection);

            try
            {
                if (httpClient != null)
                {
                    try
                    {
                        //var task = httpClient.GetAsync(Connection.URL + "/api/LITE");
                        var task   = httpClient.GetAsync(Connection.URL + LiteAgentConstants.BaseUrl);
                        var result = await task;

                        if (result.StatusCode == HttpStatusCode.OK)
                        {
                            return(true);
                        }
                    }
                    catch (Exception e)
                    {
                        _logger.LogFullException(e, $"{taskInfo} ping failed:");
                        _liteHttpClient.DumpHttpClientDetails();
                    }

                    _logger.Log(LogLevel.Warning, $"{taskInfo} ping failed: setting loginNeeded = true");
                }

                httpManager.loginNeeded = true;
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, taskInfo);
            }

            return(false);
        }
Esempio n. 6
0
        public async Task RegisterWithEGS(int taskID, LITEConnection connection, IHttpManager httpManager)
        {
            Connection = connection;
            var taskInfo = $"task: {taskID} connection: {Connection.name}";

            var httpClient = _liteHttpClient.GetClient(connection);

            try
            {
                //contact each EGS and register presence with LITEServicePoint and share dest info which will be used for address oriented routing.
                IPHostEntry hostEntry = Dns.GetHostEntry(Connection.remoteHostname);
                //look up on known dns the other LITE EGS instances and register presence
                foreach (var iPAddress in hostEntry.AddressList)
                {
                    //set the URL
                    //string url = Connection.URL + "/api/LITE";
                    string url = Connection.URL + LiteAgentConstants.BaseUrl;
                    _logger.Log(LogLevel.Debug, $"{taskInfo} url: {url}");

                    // issue the POST
                    HttpResponseMessage response = null;

                    var cookies = _liteHttpClient.GetCookies(url);
                    _logger.LogCookies(cookies, taskInfo);

                    var profile = _profileStorage.Current;

                    string profilejson = JsonSerializer.Serialize(profile);
                    var    stream      = new MemoryStream();
                    var    writer      = new StreamWriter(stream);
                    writer.Write(profilejson);
                    writer.Flush();
                    stream.Position = 0;
                    StreamContent content = new StreamContent(stream);

                    var task = httpClient.PostAsync(url, content, _taskManager.cts.Token);

                    response = await task;

                    // output the result
                    _logger.LogHttpResponseAndHeaders(response, taskInfo);

                    _logger.Log(LogLevel.Debug, $"{taskInfo} await response.Content.ReadAsStringAsync(): {await response.Content.ReadAsStringAsync()}");

                    if (response.StatusCode == HttpStatusCode.Created)
                    {
                        connection.loginAttempts = 0;
                        _logger.Log(LogLevel.Debug, $"{taskInfo} LITE Successfully Registered with EGS!");

                        httpManager.loginNeeded = false;
                    }
                    else
                    {
                        _liteHttpClient.DumpHttpClientDetails();

                        httpManager.loginNeeded = true;
                        if (response.StatusCode == HttpStatusCode.Unauthorized && connection.loginAttempts == Connection.maxAttempts)
                        {
                            LiteEngine.shutdown(null, null);
                            Environment.Exit(0);
                        }
                    }
                }
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"{taskInfo} Task Canceled");
            }
            catch (HttpRequestException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} HttpRequestException: Unable to login: {e.Message} {e.StackTrace}");
                if (e.InnerException != null)
                {
                    _logger.Log(LogLevel.Warning, $"{taskInfo} HttpRequestException: (Inner Exception) {e.InnerException.Message} {e.InnerException.StackTrace}");
                }

                _liteHttpClient.DumpHttpClientDetails();
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, $"{taskInfo} Unable to login");
                _liteHttpClient.DumpHttpClientDetails();
            }
        }
Esempio n. 7
0
        public async Task <bool> DeleteEGSResource(int taskID, RoutedItem routedItem, LITEConnection connection, IHttpManager httpManager)
        {
            Connection = connection;

            var taskInfo = $"task: {taskID} connection: {Connection.name}";

            HttpResponseMessage response = null;

            //string resourceURL = Connection.URL + "/api/File/" + routedItem.box + "/" + routedItem.resource;
            string resourceURL = Connection.URL + FileAgentConstants.GetDeleteUrl(routedItem);

            var httpClient = _liteHttpClient.GetClient(Connection);

            try
            {
                var stopWatch = new Stopwatch();
                stopWatch.Start();

                //set the URL
                _logger.Log(LogLevel.Debug, $"{taskInfo} URL: {resourceURL}");


                // issue the POST
                Task <HttpResponseMessage> task;

                task = httpClient.DeleteAsync(resourceURL, _taskManager.cts.Token);

                response = await task.ConfigureAwait(false);

                // output the result
                _logger.LogHttpResponseAndHeaders(response, taskInfo);

                stopWatch.Stop();
                _logger.Log(LogLevel.Information, $"{taskInfo} elapsed: {stopWatch.Elapsed}");

                switch (response.StatusCode)
                {
                case HttpStatusCode.NoContent:
                    return(true);

                default:
                    if (response.StatusCode == HttpStatusCode.Unauthorized)
                    {
                        httpManager.loginNeeded = true;
                    }

                    _logger.Log(LogLevel.Warning, $"Deletion of {resourceURL} failed with {response.StatusCode}");

                    _liteHttpClient.DumpHttpClientDetails();

                    return(false);
                }
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (HttpRequestException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} Exception: {e.Message} {e.StackTrace}");
                if (e.InnerException != null)
                {
                    _logger.Log(LogLevel.Warning, $"Inner Exception: {e.InnerException}");
                }

                _liteHttpClient.DumpHttpClientDetails();
            }
            catch (FileNotFoundException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} {e.Message} {e.StackTrace}");
            }
            catch (IOException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} {e.Message} {e.StackTrace}");
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, taskInfo);

                _liteHttpClient.DumpHttpClientDetails();
            }
            finally
            {
                if (response != null)
                {
                    response.Dispose();
                }
            }

            return(false);
        }
        public async Task <int> GetResources(int taskID, LITEConnection connection, IHttpManager manager)
        {
            Connection = connection;

            //get the resource list from EGS
            try
            {
                var httpClient = _liteHttpClient.GetClient(connection);

                var taskInfo = $"task: {taskID} connection: {Connection.name}";
                foreach (var shareDestination in Connection.boxes)
                {
                    //set the URL
                    string url = Connection.URL + "/api/File/" + shareDestination.boxUuid;  //add summary
                    _logger.Log(LogLevel.Debug, $"{taskInfo} URL: {url}");

                    var cookies = _liteHttpClient.GetCookies(url);
                    _logger.LogCookies(cookies, taskInfo);

                    // issue the GET
                    var task     = httpClient.GetAsync(url);
                    var response = await task;

                    // output the result
                    _logger.LogHttpResponseAndHeaders(response, taskInfo);

                    _logger.Log(LogLevel.Debug, $"{taskInfo} response.Content.ReadAsStringAsync(): {await response.Content.ReadAsStringAsync()}");
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        if (response.StatusCode == HttpStatusCode.Unauthorized)
                        {
                            manager.loginNeeded = true;
                        }

                        _logger.Log(LogLevel.Warning, $"{taskInfo} {response.StatusCode} {response.ReasonPhrase}");

                        _liteHttpClient.DumpHttpClientDetails();
                    }

                    //2018-02-06 shb convert from stream to JSON and clean up any non UTF-8 that appears like it did
                    // when receiving "contains invalid UTF8 bytes" exception
                    // var serializer = new DataContractJsonSerializer(typeof(Files));
                    // var streamReader = new StreamReader(await response.Content.ReadAsStreamAsync(), Encoding.UTF8);
                    // byte[] byteArray = Encoding.UTF8.GetBytes(streamReader.ReadToEnd());
                    // MemoryStream stream = new MemoryStream(byteArray);

                    // var newResources = serializer.ReadObject(stream) as Files;  //List<EGSFileInfo>

                    var newResources = JsonSerializer.Deserialize <FilesModel>(await response.Content.ReadAsStringAsync());

                    if (newResources != null && newResources.files.Count > 0)
                    {
                        lock (Connection.fromEGS)
                        {
                            //take the new studies from cloud and merge with existing
                            foreach (var ri in newResources.files)
                            {
                                if (!Connection.fromEGS.Any(e => e.resource == ri.resource))
                                {
                                    _logger.Log(LogLevel.Information, $"Adding {ri.resource}");

                                    _routedItemManager.Init(ri);

                                    _routedItemManager.Enqueue(connection, connection.fromEGS, nameof(connection.fromEGS), copy: false);
                                }
                                else
                                {
                                    _logger.Log(LogLevel.Error, $"Resource already exists: {ri.resource}");
                                }
                            }
                        }
                        return(newResources.files.Count);
                    }
                }
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (System.Runtime.Serialization.SerializationException e)
            {
                //eat it for now
                _logger.Log(LogLevel.Warning, $"{e.Message} {e.StackTrace}");
            }
            catch (System.Net.Http.HttpRequestException e)
            {
                _logger.Log(LogLevel.Warning, $"{e.Message} {e.StackTrace}");
                if (e.InnerException != null)
                {
                    _logger.Log(LogLevel.Warning, $"Inner Exception: {e.InnerException}");
                }
            }
            catch (Exception e)
            {
                _logger.LogFullException(e);
                //throw e;
            }

            return(0);
        }
Esempio n. 9
0
        public async Task SendToEGS(int taskID, LITEConnection connection, ISendToAllHubsService sendToAllHubs)
        {
            Connection = connection;
            //2018-02-02 shb RoutedItem does not necessarily have an open stream at this point any more

            var taskInfo = $"task: {taskID} connection: {Connection.name}";

            _logger.Log(LogLevel.Information, $"{taskInfo} toEGS: {(Connection.toEGS == null ? 0 : Connection.toEGS.Count)} items to send.");

            Dictionary <string, List <RoutedItem> > shareSet = new Dictionary <string, List <RoutedItem> >(); //I need a set for each sharing dest set
            List <List <RoutedItem> > sizeSet = new List <List <RoutedItem> >();                              //I need a set for each minEGSBatchSize

            try
            {
                Task.WaitAll(_taskManager.FindByType($"{Connection.name}.PresentAsResource"));
                Task.WaitAll(_taskManager.FindByType($"{Connection.name}.Store"));

                int retryDelayed = 0;

                if (Connection.toEGS.Count > 0)
                {
                    var toEGSTemp = Connection.toEGS.ToArray();
                    //remove the toCloud item if it has exceeded maxAttempts
                    foreach (var routedItem in toEGSTemp)
                    {
                        if (_taskManager.cts.IsCancellationRequested)
                        {
                            return;
                        }

                        if (routedItem.lastAttempt != null && routedItem.lastAttempt < DateTime.Now.AddMinutes(-Connection.retryDelayMinutes)) //not attempted lately
                        {
                            routedItem.attempts++;
                            if (routedItem.attempts > 1)
                            {
                                _logger.Log(LogLevel.Debug, $"{taskInfo} {routedItem.sourceFileName} second attempt.");
                            }
                            routedItem.lastAttempt = DateTime.Now;

                            if (routedItem.attempts > Connection.maxAttempts)
                            {
                                _logger.Log(LogLevel.Error, $"{taskInfo} {routedItem.sourceFileName} has exceeded maxAttempts of {Connection.maxAttempts}.  Will move to errors and not try again.");

                                routedItem.Error = "Exceeded maxAttempts";

                                _routedItemManager.Init(routedItem);
                                _routedItemManager.Dequeue(Connection, Connection.toEGS, nameof(Connection.toEGS), error: true);
                            }
                            else
                            {
                                _logger.Log(LogLevel.Information, $"{taskInfo} {routedItem.sourceFileName} attempts: {routedItem.attempts}");
                            }

                            //inspect the sharing headers and batch by set
                            string shareString = "";
                            if (Connection.shareDestinations != null)
                            {
                                foreach (var connectionSet in routedItem.toConnections.FindAll(e => e.connectionName.Equals(Connection.name)))
                                {
                                    if (connectionSet.shareDestinations != null)
                                    {
                                        foreach (var shareDestination in connectionSet.shareDestinations)
                                        {
                                            shareString += shareDestination.boxUuid;
                                        }
                                    }
                                }
                            }

                            if (shareSet.ContainsKey(shareString))
                            {
                                _logger.Log(LogLevel.Debug, $"{taskInfo} Adding {routedItem.sourceFileName} to shareString: {shareString}");
                                shareSet.GetValueOrDefault(shareString).Add(routedItem);
                            }
                            else
                            {
                                var list = new List <RoutedItem>
                                {
                                    routedItem
                                };
                                _logger.Log(LogLevel.Debug, $"{taskInfo} Adding {routedItem.sourceFileName} to shareString: {shareString}");
                                shareSet.Add(shareString, list);
                            }
                        }
                        else
                        {
                            retryDelayed++;
                        }
                    }

                    //Now that each key in the Dictionary is to a single set of sharing destinations, let's break it up further by minEGSBatchSize
                    //What we want is a big enough upload to solve the small file problem, but small enough so the upload makes forward progress.
                    //If this is not the first attempt, then disable batching and send individually.


                    foreach (var share in shareSet.Values)
                    {
                        if (_taskManager.cts.IsCancellationRequested)
                        {
                            return;
                        }

                        var batch = new List <RoutedItem>();

                        long bytes = 0;
                        foreach (var element in share)
                        {
                            if (File.Exists(element.sourceFileName))
                            {
                                try
                                {
                                    element.length = new FileInfo(element.sourceFileName).Length;
                                }
                                catch (FileNotFoundException e)
                                {
                                    _logger.Log(LogLevel.Error, $"{taskInfo} {e.Message} {e.StackTrace}");

                                    continue;
                                }
                                catch (IOException e)
                                {
                                    _logger.Log(LogLevel.Error, $"{taskInfo} {e.Message} {e.StackTrace}");
                                    //condition may be transient like file in use so skip for the moment
                                    continue;
                                }
                                catch (Exception e)
                                {
                                    _logger.LogFullException(e, taskInfo);
                                    //condition may be transient like file so skip for the moment
                                    continue;
                                }
                            }
                            else
                            {
                                element.Error = $"File {element.sourceFileName} does not exist";
                                _routedItemManager.Init(element);
                                _routedItemManager.Dequeue(Connection, Connection.toEGS, nameof(Connection.toEGS), true);
                            }

                            //If this is not the first attempt, then disable batching and send individually.
                            if (element.length < Connection.minEGSBatchSize && bytes < Connection.minEGSBatchSize && element.attempts == 1)
                            {
                                bytes += element.length;
                                _logger.Log(LogLevel.Debug, $"{taskInfo} Adding {element.sourceFileName} to batch...");
                                batch.Add(element);
                            }
                            else
                            {
                                _logger.Log(LogLevel.Debug, $"{taskInfo} Batch is full with count: {batch.Count} size: {bytes} attempts: {element.attempts} {(element.attempts > 1 ? "items are sent individually after 1st attempt!" : "")}");
                                sizeSet.Add(batch);
                                batch = new List <RoutedItem>();
                                bytes = element.length;
                                batch.Add(element);
                            }
                        }

                        if (!sizeSet.Contains(batch) && batch.Count > 0)
                        {
                            _logger.Log(LogLevel.Debug, $"{taskInfo} Add final batch to set with count: {batch.Count} size: {bytes}");
                            sizeSet.Add(batch);
                        }
                    }

                    int tempcount = 0;
                    foreach (var batch in sizeSet)
                    {
                        tempcount += batch.Count;
                    }

                    _logger.Log(LogLevel.Information, $"{taskInfo} {sizeSet.Count} batches to send, selected: {tempcount}/{toEGSTemp.Length} retry delayed: {retryDelayed}");

                    foreach (var batch in sizeSet)
                    {
                        if (_taskManager.cts.IsCancellationRequested)
                        {
                            return;
                        }

                        //if (loginNeeded) break;

                        if (batch.Count > 0)
                        {
                            switch (Connection.PushPull)
                            {
                            case PushPullEnum.pull:
                                switch (Connection.protocol)
                                {
                                case Protocol.Http:
                                case Protocol.UDT:
                                    var  newTaskID = _taskManager.NewTaskID();
                                    Task task      = new Task(new Action(async() => await _presentAsResourceService.PresentAsResource(batch, newTaskID, connection, sendToAllHubs)));
                                    await _taskManager.Start(newTaskID, task, $"{Connection.name}.PresentAsResource", $"{Connection.name}.PresentAsResource batch {batch.Count}", isLongRunning : false);

                                    break;
                                }

                                break;

                            case PushPullEnum.push:
                                switch (Connection.protocol)
                                {
                                case Protocol.Http:
                                    var  newTaskID2 = _taskManager.NewTaskID();
                                    Task task2      = new Task(new Action(async() => await _liteStoreService.store(batch, newTaskID2, connection)));
                                    await _taskManager.Start(newTaskID2, task2, $"{Connection.name}.Store", $"{Connection.name}.Store batch {batch.Count}", isLongRunning : false);

                                    break;

                                case Protocol.UDT:
                                    break;
                                }

                                break;

                            case PushPullEnum.both:
                                //since each method dequeues it's own work we would need a separate queue before we can do both, like toEGSPull toEGSPush.
                                break;
                            }
                        }
                    }
                }
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, taskInfo);
            }
        }
        public async Task Download(int taskID, LITEConnection connection, IHttpManager httpManager, SemaphoreSlim FromEGSSignal)
        {
            Connection = connection;

            var taskInfo = $"task: {taskID} connection: {Connection.name}";

            var profile = _profileStorage.Current;

            DateTime lastGetResources     = DateTime.MinValue;
            int      GetResourcesInterval = 120000;
            int      lastResourceCount    = 0;

            try
            {
                do
                {
                    var temp = Connection.fromEGS.ToList();
                    if (temp.Count == 0 || !temp.Any(e => e.attempts == 0))
                    {
                        var getResourcesTime = DateTime.Now.AddMilliseconds(GetResourcesInterval * -1);
                        if (lastGetResources.CompareTo(getResourcesTime) < 0 || lastResourceCount > 0)
                        {
                            lastResourceCount = await _getLiteReresourcesService.GetResources(taskID, connection, httpManager);

                            lastGetResources = DateTime.Now;
                        }

                        bool success = await FromEGSSignal.WaitAsync(profile.KickOffInterval, _taskManager.cts.Token).ConfigureAwait(false);

                        // FromEGSSignal.Dispose();
                        // FromEGSSignal = new SemaphoreSlim(0, 1);
                    }
                    else
                    {
                        await Task.Delay(profile.taskDelay).ConfigureAwait(false);
                    }

                    foreach (var routedItem in Connection.fromEGS.ToArray())
                    {
                        await ProcessItem(taskID, routedItem, connection, httpManager);
                    }

                    Task.WaitAll(_taskManager.FindByType($"{Connection.name}.DownloadViaHttp"));
                } while (Connection.responsive);
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (OperationCanceledException)
            {
                _logger.Log(LogLevel.Warning, $"Wait Operation Canceled. Exiting Download");
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, taskInfo);
                _logger.Log(LogLevel.Critical, $"{taskInfo} Exiting Download");
            }
            finally
            {
                _taskManager.Stop($"{Connection.name}.Download");
            }
        }
        /// <summary>
        /// wado downloads studies from liCloud.  ImagingStudy is required while Series and Instance are optional.  RAM utilization remains low regardless of download size.
        /// </summary>
        /// <param name="taskID"></param>
        /// <param name="routedItem"></param>
        /// <param name="connection"></param>
        /// <param name="httpManager"></param>
        /// <param name="compress"></param>
        /// <returns></returns>
        public async Task DownloadViaHttp(int taskID, RoutedItem routedItem, LITEConnection connection, IHttpManager httpManager, bool compress = true)
        {
            Connection = connection;
            var taskInfo  = $"task: {taskID} connection: {Connection.name} resource: {routedItem.resource}";
            var profile   = _profileStorage.Current;
            var stopWatch = new Stopwatch();

            stopWatch.Start();
            //string url = Connection.URL + $"/api/File/{routedItem.box}/{routedItem.resource}";
            string url = Connection.URL + FileAgentConstants.GetDownloadUrl(routedItem);
            string dir = profile.tempPath + Path.DirectorySeparatorChar + Connection.name + Path.DirectorySeparatorChar + Constants.Dirs.ToRules + Path.DirectorySeparatorChar + Guid.NewGuid();

            Directory.CreateDirectory(dir);
            long fileSize = 0;
            HttpResponseMessage         response       = null;
            MultipartFileStreamProvider streamProvider = null;
            MultipartFileStreamProvider contents       = null;

            var httpClient = _liteHttpClient.GetClient(connection);

            try
            {
                _logger.Log(LogLevel.Debug, $"{taskInfo} download dir will be {dir}");
                _logger.Log(LogLevel.Debug, $"{taskInfo} url: {url} attempt: {routedItem.attempts}");

                var cookies = _liteHttpClient.GetCookies(url);
                _logger.LogCookies(cookies, taskInfo);

                // issue the GET
                var task = httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, _taskManager.cts.Token);

                try
                {
                    response = await task.ConfigureAwait(false);
                }
                catch (TaskCanceledException)
                {
                    _logger.Log(LogLevel.Information, $"{taskInfo} Task Canceled");
                }

                // output the result
                _logger.LogHttpResponseAndHeaders(response, taskInfo);

                //if(Logger.logger.FileTraceLevel == "Verbose") _logger.Log(LogLevel.Debug,$"{taskInfo} await response.Content.ReadAsStringAsync(): {await response.Content.ReadAsStringAsync()}");
                switch (response.StatusCode)
                {
                case HttpStatusCode.OK:
                    break;

                case HttpStatusCode.NotFound:
                    routedItem.Error = HttpStatusCode.NotFound.ToString();

                    _routedItemManager.Init(routedItem);
                    _routedItemManager.Dequeue(Connection, Connection.fromEGS, nameof(Connection.fromEGS), error: true);
                    return;

                case HttpStatusCode.Unauthorized:
                    httpManager.loginNeeded = true;
                    _liteHttpClient.DumpHttpClientDetails();
                    return;

                default:
                    _liteHttpClient.DumpHttpClientDetails();
                    return;
                }

                if (!_util.IsDiskAvailable(dir, profile, routedItem.length))
                {
                    _logger.Log(LogLevel.Debug, $"{taskInfo} Insufficient disk to write {url} to {dir} guessing it could be 16GB");
                    return;
                }

                streamProvider = new MultipartFileStreamProvider(dir, 1024000);

                try
                {
                    contents = await response.Content.ReadAsMultipartAsync(streamProvider, _taskManager.cts.Token).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    //MIME is corrupt such as Unexpected end of MIME multipart stream. MIME multipart message is not complete.
                    //This usually happens if the upload does not complete.  Catch as "normal" and remove resource as if success
                    //since retrying will not help this condition.

                    _logger.LogFullException(e, taskInfo);

                    _liteHttpClient.DumpHttpClientDetails();

                    if (await _deleteEGSResourceService.DeleteEGSResource(taskID, routedItem, connection, httpManager).ConfigureAwait(false))
                    {
                        _routedItemManager.Init(routedItem);
                        _routedItemManager.Dequeue(Connection, Connection.fromEGS, nameof(Connection.fromEGS), error: false);
                    }
                    else
                    {
                        routedItem.Error = "Unable to delete EGS resource";
                        _routedItemManager.Init(routedItem);
                        _routedItemManager.Dequeue(Connection, Connection.fromEGS, nameof(Connection.fromEGS), error: true);
                    }

                    return;
                }

                int index = 0;
                _logger.Log(LogLevel.Debug, $"{taskInfo} Splitting {contents?.FileData.Count} files into RoutedItems.");
                foreach (var part in contents.FileData)
                {
                    try
                    {
                        index++;

                        fileSize += new FileInfo(part.LocalFileName).Length;

                        _logger.Log(LogLevel.Debug, $"{taskInfo} downloaded file: {part.LocalFileName}");

                        RoutedItem ri = new RoutedItem(fromConnection: Connection.name, sourceFileName: part.LocalFileName, taskID: taskID, fileIndex: index, fileCount: contents.FileData.Count)
                        {
                            type = RoutedItem.Type.FILE
                        };

                        _logger.Log(LogLevel.Debug, $"{taskInfo} Enqueuing RoutedItem {routedItem.sourceFileName}");

                        _routedItemManager.Init(ri);
                        _routedItemManager.Enqueue(Connection, Connection.toRules, nameof(Connection.toRules));
                    }
                    catch (Exception e)
                    {
                        _logger.LogFullException(e, taskInfo);
                    }
                }

                if (await _deleteEGSResourceService.DeleteEGSResource(taskID, routedItem, connection, httpManager).ConfigureAwait(false))
                {
                    _routedItemManager.Init(routedItem);
                    _routedItemManager.Dequeue(Connection, Connection.fromEGS, nameof(Connection.fromEGS), error: false);
                }
                else
                {
                    routedItem.Error = "Unable to delete EGS resource";
                    _routedItemManager.Init(routedItem);
                    _routedItemManager.Dequeue(Connection, Connection.fromEGS, nameof(Connection.fromEGS), error: true);
                }
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (NullReferenceException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} Exception: {e.Message} {e.StackTrace}");
                //throw e;
            }
            catch (HttpRequestException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} Exception: {e.Message} {e.StackTrace}");
                if (e.InnerException != null)
                {
                    _logger.Log(LogLevel.Warning, $"Inner Exception: {e.InnerException}");
                }

                _liteHttpClient.DumpHttpClientDetails();
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, taskInfo);
                _liteHttpClient.DumpHttpClientDetails();
            }
            finally
            {
                if (response != null)
                {
                    response.Dispose();
                }

                _taskManager.Stop($"{Connection.name}.DownloadViaHttp");
            }

            stopWatch.Stop();
            _logger.Log(LogLevel.Information, $"{taskInfo} elapsed: {stopWatch.Elapsed} size: {fileSize} rate: {(float)fileSize / stopWatch.Elapsed.TotalMilliseconds * 1000 / 1000000} MB/s");
        }
        /// <summary>
        /// Store takes a batch of RoutedItem, all going to the same share destination, and uploads them as a single operation. This is done to solve the many small files problem.Larger files can go individually.
        /// </summary>
        /// <param name="batch"></param>
        /// <param name="taskID"></param>
        /// <param name="connection"></param>
        /// <returns></returns>
        public async Task store(List <RoutedItem> batch, int taskID, LITEConnection connection)
        {
            Connection = connection;

            var                 taskInfo      = $"task: {taskID} connection: {Connection.name}";
            StreamContent       streamContent = null;
            MultipartContent    content       = null;
            HttpResponseMessage response      = null;
            string              testFile      = null;

            var firstRecord = batch.First();

            try
            {
                var stopWatch = new Stopwatch();
                stopWatch.Start();

                //set the URL
                //string resourceURL = Connection.URL + "/api/File";
                string resourceURL = Connection.URL + FileAgentConstants.BaseUrl;
                _logger.Log(LogLevel.Debug, $"{taskInfo} URL: {resourceURL}");

                // generate guid for boundary...boundaries cannot be accidentally found in the content
                var boundary = Guid.NewGuid();
                _logger.Log(LogLevel.Debug, $"{taskInfo} boundary: {boundary}");

                // create the content
                content = new MultipartContent("related", boundary.ToString());

                //add the sharing headers
                List <string> shareHeader = new List <string>();
                if (Connection.shareDestinations != null)
                {
                    foreach (var connectionSet in firstRecord.toConnections.FindAll(e => e.connectionName.Equals(Connection.name)))
                    {
                        if (connectionSet.shareDestinations != null)
                        {
                            foreach (var shareDestination in connectionSet.shareDestinations)
                            {
                                shareHeader.Add(shareDestination.boxUuid);
                                _logger.Log(LogLevel.Debug, $"{taskInfo} sharing to: {shareDestination.boxId} {shareDestination.boxName} {shareDestination.groupId} {shareDestination.groupName} {shareDestination.organizationName} {shareDestination.publishableBoxType}");
                            }
                        }
                    }
                }

                content.Headers.Add("X-Li-Destination", shareHeader);

                long fileSize = 0;
                var  profile  = _profileStorage.Current;
                var  dir      = profile.tempPath + Path.DirectorySeparatorChar + Connection.name + Path.DirectorySeparatorChar + "toEGS";
                Directory.CreateDirectory(dir);
                testFile = dir + Path.DirectorySeparatorChar + Guid.NewGuid() + ".gz";

                using (FileStream compressedFileStream = File.Create(testFile))
                {
                    using GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress);
                    foreach (var routedItem in batch)
                    {
                        if (File.Exists(routedItem.sourceFileName))
                        {
                            routedItem.stream = File.OpenRead(routedItem.sourceFileName);

                            if (Connection.calcCompressionStats)
                            {
                                routedItem.stream.CopyTo(compressionStream);
                            }

                            fileSize     += routedItem.length;
                            streamContent = new StreamContent(routedItem.stream);

                            streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                            {
                                FileName = routedItem.sourceFileName
                            };
                            content.Add(streamContent);

                            streamContent.Headers.Add("content-type", "application/octet-stream");
                        }
                        else
                        {
                            _logger.Log(LogLevel.Error, $"{taskInfo} {routedItem.sourceFileName} no longer exists.  Increase tempFileRetentionHours for heavy transfer backlogs that may take hours!!");
                            routedItem.Error = "File no longer exists";
                            _routedItemManager.Init(routedItem);
                            _routedItemManager.Dequeue(Connection, Connection.toEGS, nameof(Connection.toEGS), error: true);
                        }
                    }
                }

                if (Connection.calcCompressionStats)
                {
                    FileInfo info = new FileInfo(testFile);
                    _logger.Log(LogLevel.Information, $"{taskInfo} orgSize: {fileSize} compressedSize: {info.Length} reduction: {(fileSize == 0 ? 0 : (fileSize * 1.0 - info.Length) / (fileSize) * 100)}%");
                }

                // issue the POST
                Task <HttpResponseMessage> task;

                var httpClient = _liteHttpClient.GetClient(connection);

                if (firstRecord.Compress == true)
                {
                    var compressedContent = new CompressedContent(content, "gzip");

                    _logger.Log(LogLevel.Debug, $"{taskInfo} compressedContent.Headers {compressedContent.Headers} ");

                    compressedContent.Headers.Remove("Content-Encoding");

                    var cookies = _liteHttpClient.GetCookies(resourceURL);
                    _logger.LogCookies(cookies, taskInfo);

                    task = httpClient.PostAsync(resourceURL, compressedContent);
                }
                else
                {
                    _logger.Log(LogLevel.Debug, $"{taskInfo} will send content.Headers {content.Headers}");

                    var cookies = _liteHttpClient.GetCookies(resourceURL);
                    _logger.LogCookies(cookies, taskInfo);

                    task = httpClient.PostAsync(resourceURL, content);
                }

                response = await task;

                // output the result
                _logger.LogHttpResponseAndHeaders(response, taskInfo);

                _logger.Log(LogLevel.Debug, $"{taskInfo} response.Content.ReadAsStringAsync(): {await response.Content.ReadAsStringAsync()}");

                stopWatch.Stop();
                _logger.Log(LogLevel.Information, $"{taskInfo} elapsed: {stopWatch.Elapsed} size: {fileSize} rate: {(float)fileSize / stopWatch.Elapsed.TotalMilliseconds * 1000 / 1000000} MB/s");

                switch (response.StatusCode)
                {
                case HttpStatusCode.Created:
                    //dequeue the work, we're done!
                    if (streamContent != null)
                    {
                        streamContent.Dispose();
                    }
                    if (response != null)
                    {
                        response.Dispose();
                    }
                    if (content != null)
                    {
                        content.Dispose();
                    }

                    foreach (var ri in batch)
                    {
                        _routedItemManager.Init(ri);
                        _routedItemManager.Dequeue(Connection, Connection.toEGS, nameof(Connection.toEGS));
                    }

                    //let EGGS know it's available, or when we convert udt to .net core then perhaps push so no open socket required on client.
                    //await SendToAllHubs(LITEServicePoint, batch);

                    break;

                case HttpStatusCode.UnprocessableEntity:
                    //dequeue the work, we're done!
                    _logger.Log(LogLevel.Warning, $"creation of {firstRecord.sourceFileName} and others in batch failed with {response.StatusCode}");

                    if (streamContent != null)
                    {
                        streamContent.Dispose();
                    }
                    if (response != null)
                    {
                        response.Dispose();
                    }
                    if (content != null)
                    {
                        content.Dispose();
                    }

                    foreach (var ri in batch)
                    {
                        ri.Error = HttpStatusCode.UnprocessableEntity.ToString();

                        _routedItemManager.Init(ri);
                        _routedItemManager.Dequeue(Connection, Connection.toEGS, nameof(Connection.toEGS), error: true);
                    }

                    break;

                default:
                    if (response.StatusCode == HttpStatusCode.Unauthorized)
                    {
                        Connection.loginNeeded = true;
                    }

                    _logger.Log(LogLevel.Warning, $"creation of {firstRecord.sourceFileName} and others in batch failed with {response.StatusCode}");

                    _liteHttpClient.DumpHttpClientDetails();
                    break;
                }

                //delete the compression test file
                File.Delete(testFile);
            }
            catch (TaskCanceledException)
            {
                _logger.Log(LogLevel.Information, $"Task was canceled.");
            }
            catch (HttpRequestException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} Exception: {e.Message} {e.StackTrace}");
                if (e.InnerException != null)
                {
                    _logger.Log(LogLevel.Warning, $"Inner Exception: {e.InnerException}");
                }

                _liteHttpClient.DumpHttpClientDetails();
            }
            catch (FileNotFoundException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} {e.Message} {e.StackTrace}");
            }
            catch (IOException e)
            {
                _logger.Log(LogLevel.Warning, $"{taskInfo} {e.Message} {e.StackTrace}");
            }
            catch (Exception e)
            {
                _logger.LogFullException(e, taskInfo);
                _liteHttpClient.DumpHttpClientDetails();
            }
            finally
            {
                try
                {
                    if (streamContent != null)
                    {
                        streamContent.Dispose();
                    }
                    if (response != null)
                    {
                        response.Dispose();
                    }
                    if (content != null)
                    {
                        content.Dispose();
                    }
                    File.Delete(testFile);
                    _taskManager.Stop($"{Connection.name}.Store");
                }
                catch (Exception e)
                {
                    _logger.LogFullException(e, taskInfo);
                }
            }
        }