/// <summary> /// Gets the cloud requests. /// </summary> /// <param name="taskID"></param> /// <param name="Connection"></param> /// <param name="cache"></param> /// <param name="httpManager"></param> /// <returns></returns> public async Task GetRequests(int taskID, LifeImageCloudConnection Connection, IConnectionRoutedCacheManager cache, IHttpManager httpManager) { var taskInfo = $"task: {taskID} connection: {Connection.name}"; HttpResponseMessage response = null; var httpClient = _liteHttpClient.GetClient(Connection); try { while (!_taskManager.cts.IsCancellationRequested) { await Task.Delay(_profileStorage.Current.KickOffInterval, _taskManager.cts.Token); //BOUR-1022 shb I think the code that checks for dictionary entry before enqueuing is enough to prevent duplicate behavior //skip if response cache is not empty if (LifeImageCloudConnectionManager.cache.Count > 0) { int requestCount = 0; //check to see if there are any requests foreach (var cacheItem in LifeImageCloudConnectionManager.cache.ToArray()) { _logger.Log(LogLevel.Debug, $"{taskInfo} Cache entry id: {cacheItem.Key}"); foreach (var item in cacheItem.Value.ToArray()) { _logger.Log(LogLevel.Debug, $"{taskInfo} fromConnection: {item.fromConnection} id: {item.id} started: {item.startTime} complete: {item.resultsTime} status: {item.status}"); if (item.type == RoutedItem.Type.RPC) { requestCount++; } } } if (requestCount > 0) { //BOUR-1060 relax condition and rely on dictionary logic below _logger.Log(LogLevel.Warning, $"{taskInfo} response cache has {requestCount} request items."); // _logger.Log(LogLevel.Warning, $"{taskInfo} response cache has {requestCount} request items, skipping getting new requests until clear"); // return; } } //set the URL //string agentTasksURL = Connection.URL + "/api/agent/v1/agent-tasks"; string agentTasksURL = Connection.URL + CloudAgentConstants.GetAgentTasksUrl; _logger.Log(LogLevel.Debug, $"{taskInfo} agentTasksURL: {agentTasksURL}"); var cookies = _liteHttpClient.GetCookies(agentTasksURL); _logger.LogCookies(cookies, taskInfo); // issue the GET var task = httpClient.GetAsync(agentTasksURL); response = await task; // output the result _logger.LogHttpResponseAndHeaders(response, taskInfo); if (response.StatusCode == HttpStatusCode.OK) { if (response.StatusCode == HttpStatusCode.Unauthorized) { httpManager.loginNeeded = true; } _logger.Log(LogLevel.Warning, $"{taskInfo} Problem getting agent tasks. {agentTasksURL} {response.StatusCode}"); _liteHttpClient.DumpHttpClientDetails(); } // convert from stream to JSON string results = await response.Content.ReadAsStringAsync(); var objResults = JsonSerializer.Deserialize <Dictionary <string, List <Dictionary <string, string> > > >(results); foreach (var key in objResults) { _logger.Log(LogLevel.Debug, $"{taskInfo} key: {key.Key}"); var list = key.Value; foreach (var item in list) { foreach (var subkey in item) { _logger.Log(LogLevel.Debug, $"{taskInfo} subkey.Key: {subkey.Key} subKey.Value: {subkey.Value} "); } } } if (objResults.Count > 0) { // 2018-09-19 shb unwrap encoded task data and then send to rules var agentRequestList = objResults["modelMapList"]; foreach (var agentRequest in agentRequestList) { byte[] data = Convert.FromBase64String(agentRequest["task"]); string agentRequestAsString = Encoding.UTF8.GetString(data); agentRequest["task"] = agentRequestAsString; string id = agentRequest["id"]; string request = agentRequest["task"]; string requestType = agentRequest["task_type"]; string connection = null; agentRequest.TryGetValue("connection", out connection); RoutedItem ri = new RoutedItem(fromConnection: Connection.name, id: id, request: request, requestType: requestType) { type = RoutedItem.Type.RPC, status = RoutedItem.Status.PENDING, startTime = DateTime.Now, TaskID = taskID }; if (connection != null && connection != "*") { ConnectionSet connSet = new ConnectionSet { connectionName = connection }; ri.toConnections.Add(connSet); } LifeImageCloudConnectionManager.cache.TryGetValue(ri.id, out List <RoutedItem> cacheItem); if (cacheItem == null) { //determine which connections will need to reply and prime the response cache _rulesManager.Init(_profileStorage.Current.rules); //var connsets = _profileStorage.Current.rules.Eval(ri); var connsets = _rulesManager.Eval(ri); foreach (var connset in connsets) { _routedItemManager.Init(ri); var prime = (RoutedItem)_routedItemManager.Clone(); prime.startTime = DateTime.Now; //clock starts ticking now prime.status = RoutedItem.Status.PENDING; prime.fromConnection = _profileStorage.Current.connections.Find(e => e.name == connset.connectionName).name; _logger.Log(LogLevel.Debug, $"{taskInfo} Priming Response cache id: {id} conn: {prime.fromConnection} "); cache.Route(prime); } //enqueue the request _logger.Log(LogLevel.Debug, $"{taskInfo} Enqueuing id: {id} requestType: {requestType} subKey.Value: {request} "); _routedItemManager.Init(ri); _routedItemManager.Enqueue(Connection, Connection.toRules, nameof(Connection.toRules)); //BOUR-995 let cloud know we got the request with a status of PENDING await _postResponseCloudService.PostResponse(Connection, ri, cache, httpManager, taskID); } else { _logger.Log(LogLevel.Debug, $"{taskInfo} Exists id: {id} requestType: {requestType} subKey.Value: {request} "); foreach (var item in cacheItem) { _logger.Log(LogLevel.Debug, $"{taskInfo} fromConnection: {item.fromConnection} started: {item.startTime} complete: {item.resultsTime} status: {item.status}"); foreach (var ctr in item.cloudTaskResults) { foreach (var result in ctr.results) { _logger.Log(LogLevel.Debug, $"{taskInfo} Exists id: {item.id} results: {result}"); } } } } } } } } catch (TaskCanceledException) { _logger.Log(LogLevel.Information, $"{taskInfo} Task was canceled."); } catch (System.InvalidOperationException) //for the Collection was Modified, we can wait { _logger.Log(LogLevel.Information, $"{taskInfo} Waiting for requests to complete before getting new requests"); } catch (Exception e) { _logger.LogFullException(e, taskInfo); } finally { try { _taskManager.Stop($"{Connection.name}.GetRequests"); if (response != null) { response.Dispose(); } } catch (Exception e) { _logger.LogFullException(e, taskInfo); } } }