private async void ApiQuery(ApiQuery query) { try { if (!_apiQueryUpdates.ContainsKey(query.ApiKey)) { _apiQueryUpdates.TryAdd(query.ApiKey, query); } if (!_apiQueryBusy) { _apiQueryBusy = true; while (_apiQueryUpdates.Count > 0) { var apiQueries = _apiQueryUpdates.Values.ToList(); _apiQueryUpdates.Clear(); var postQuery = new PostApiQuery() { SecurityToken = _sharedSettings.SecurityToken, ApiQueries = apiQueries }; var start = new Stopwatch(); start.Start(); var result = await _sharedSettings.PostAsync <PostApiQuery, ReturnValue>("Remote/ApiQuery", postQuery, CancellationToken.None); start.Stop(); _logger.LogTrace("Send api query completed in {0}ms.", start.ElapsedMilliseconds); if (result.Success == false) { _logger.LogError(250, result.Exception, "Query api results failed. Return message was: {0}." + result.Message); } // wait a little while for more tasks results to arrive. await Task.Delay(500); } _apiQueryBusy = false; } } catch (Exception ex) { _logger.LogError(250, ex, "Update api query failed with error. Error was: {0}." + ex.Message); _apiQueryBusy = false; } }
public async Task <string> Query(string securityKey, string action, string queryString, string ipAddress, CancellationToken cancellationToken = default) { if (_liveApis.TryGetValue(securityKey, out var apiData)) { var timer = Stopwatch.StartNew(); await apiData.WaitForTask(cancellationToken); JsonDocument inputColumns = null; JsonDocument query = null; JsonDocument inputParameters = null; try { var parameters = HttpUtility.ParseQueryString(queryString); if (action?.ToLower() == "info") { var columns = apiData.Transform.CacheTable.Columns; var inputColumns2 = apiData.Transform.GetSourceReader().CacheTable.Columns.Where(c => c.IsInput); var infoQuery = new { Success = true, QueryColumns = columns, InputColumns = inputColumns2 }; return(JsonExtensions.Serialize(infoQuery)); } // check for a query var q = parameters["q"]; query = q == null ? null : JsonDocument.Parse(q); var i = parameters["i"]; inputColumns = i == null ? null : JsonDocument.Parse(i); var p = parameters["p"]; inputParameters = p == null ? null : JsonDocument.Parse(p); var cts = new CancellationTokenSource(); var t = parameters["t"]; if (t != null) { if (long.TryParse(t, out var timeout)) { cts.CancelAfter(TimeSpan.FromSeconds(timeout)); } else { throw new Exception($"The timeout (t) was set to an invalid value {t}. This needs to be the number seconds before timing out."); } } var rows = -1; var r = parameters["r"]; if (r != null) { if (!int.TryParse(r, out rows)) { throw new Exception($"The rows (r) was set to an invalid value {t}. This needs to be the maximum number of rows."); } } // TODO add EDownloadFormat to api options. var selectQuery = apiData.SelectQuery == null ? new SelectQuery() : apiData.SelectQuery.CloneProperties(); selectQuery.LoadJsonFilters(apiData.Transform.CacheTable, query); selectQuery.LoadJsonInputColumns(inputColumns); selectQuery.LoadJsonParameters(inputParameters); selectQuery.Rows = rows; var combinedCancel = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cts.Token).Token; var result = await apiData.Transform.LookupJson(selectQuery, EDuplicateStrategy.All, combinedCancel); apiData.IncrementSuccess(); timer.Stop(); var queryApi = new ApiQuery() { HubKey = apiData.HubKey, ApiKey = apiData.ApiKey, Success = true, IpAddress = ipAddress, Date = DateTime.Now, InputColumns = inputColumns?.ToString(), InputParameters = inputParameters?.ToString(), Filters = query?.ToString(), TimeTaken = timer.ElapsedMilliseconds }; ApiQuery(queryApi); ApiUpdate(apiData); return(result); } catch (Exception ex) { apiData.IncrementError(); timer.Stop(); var queryApi = new ApiQuery() { Success = false, Message = ex.Message, Exception = ex, IpAddress = ipAddress, Date = DateTime.Now, InputColumns = inputColumns?.ToString(), Filters = query?.ToString(), TimeTaken = timer.ElapsedMilliseconds }; ApiQuery(queryApi); return(JsonExtensions.Serialize(new ReturnValue(false, ex.Message, ex))); } finally { apiData.TaskComplete(); } } throw new LiveDataException("The requested API is not available."); }