private bool HadSuccess = true; //Asume a working condition at first public void PublishToAzure(PingDiagnostic diagnostic) { string urlToUse = ComposeUrl(azureConfig.Endpoint, diagnostic); new Thread(() => { try { logger.LogDebug($"Publishing to to Azure {urlToUse}"); HttpClient client = new HttpClient(); var objectString = JsonConvert.SerializeObject(diagnostic); var content = new StringContent(objectString, Encoding.UTF8, "application/json"); var res = client.PostAsync(urlToUse, content).GetAwaiter().GetResult(); logger.LogDebug($"Published to Azure {urlToUse} - {res.StatusCode}"); //Inform if connection is restored if (!HadSuccess) { logger.LogWarning($"Restored publish to Azure {urlToUse}"); } HadSuccess = true; } catch (Exception e) { if (HadSuccess) { //Signal warning only on change logger.LogWarning($"Cannot publish to Azure {urlToUse}: {e.Message}, will inform again when online"); } logger.LogDebug($"Cannot publish to Azure {urlToUse}: {e.Message}"); HadSuccess = false; } }).Start(); }
// Check if there is already a response from this device, we are not doing duplicates private bool IsNewResponseForPing(PingDiagnostic tripData, PingDiagnosticResponse response) { if (tripData == null || response == null) { return(false); } return(!tripData.Responders.Any(r => r.Channel == response.Channel && r.ReceiverIdentifier == response.ReceiverIdentifier)); }
private string ComposeUrl(string rootUrl, PingDiagnostic diag) { if (!rootUrl.EndsWith("/")) { rootUrl += "/"; } return($"{rootUrl}api/Ping/{diag.SessionIdentifier}/{diag.PingIdentifier}/"); }
private void HandleFinalizeOfPing(PingDiagnostic roundtrip, int sleep) { new Thread(() => { Thread.Sleep(sleep); logger.LogDebug($"Waking up to resolve ping: {roundtrip.SessionIdentifier}"); CleanupPingResult(roundtrip); OutputPingResult(roundtrip); }).Start(); }
private void RegisterPingRequest(PingDiagnostic diagnostic) { logger.LogInformation($"Writing request: {diagnostic.PingIdentifier}"); RunQuery(SQLStoreRequest, new { SessionIdentifier = diagnostic.SessionIdentifier, PingIdentifier = diagnostic.PingIdentifier, StartTime = diagnostic.StartTime }); }
public PingDiagnostic RegisterTripStart(string sessionIdentifier, string pingIdentifier) { var rt = new PingDiagnostic() { SessionIdentifier = sessionIdentifier, PingIdentifier = pingIdentifier, StartTime = DateTime.Now }; MulticastPings.Add(pingIdentifier, rt); return(rt); }
private static void WarnOnInconsistentIdentifiers(PingDiagnostic diag, ILogger log) { if (!diag.Responders?.Any() == true) { return; } if (diag.Responders.Any(r => r.PingIdentifier != diag.PingIdentifier || r.SessionIdentifier != diag.SessionIdentifier)) { log.LogWarning($"One or more responses in ping {diag.SessionIdentifier}|{diag.PingIdentifier} did not contain the same identifiers (but will be forced to the parent ping anyway)"); } }
private void OutputPingToLog(PingDiagnostic roundtrip) { if (roundtrip.IsSuccess) { string formattedReplies = String.Join("|", roundtrip.Responders.Select(r => FormatReply(r))); logger.LogInformation($"{{{roundtrip.StartTime.ToString("HH:mm:ss.fff")}|{sessionIdentifier}|{roundtrip.PingIdentifier}|SUCCESS|{{{formattedReplies}}}}}"); } else { logger.LogCritical($"{{{roundtrip.StartTime.ToString("HH:mm:ss.fff")}|{sessionIdentifier}|{roundtrip.PingIdentifier}|FAILED}}"); } }
public void PurgeTripResponse(PingDiagnostic result) { try { this.MulticastPings.Remove(result.PingIdentifier); logger.LogDebug($"Purged record: {result.PingIdentifier}"); } catch (Exception e) { logger.LogDebug($"Cannot purge: {result.PingIdentifier} -> {e.Message}"); } }
public async System.Threading.Tasks.Task WritePing(PingDiagnostic ping) { try { await firebaseClient .Child(configuration.TopicRequests) .Child(GetIdentifier(ping)) .PutAsync(ping.GetCopy()); } catch (Exception e) { logger.LogWarning($"Cannot put ping {GetIdentifier(ping)}: {e.Message}"); } }
//TODO: The dispose is possibly not called for missed pings, which is flooding the datastream public async System.Threading.Tasks.Task DisposePing(PingDiagnostic ping) { try { await firebaseClient .Child(configuration.TopicRequests) .Child(GetIdentifier(ping)) .DeleteAsync(); } catch (Exception e) { logger.LogWarning($"Cannot dispose ping {GetIdentifier(ping)}: {e.Message}"); } }
private void RegisterPongResponse(PingDiagnostic diagnostic, PingDiagnosticResponse response) { logger.LogInformation($"Writing response: {response.ReceiverIdentifier} for ping {diagnostic.PingIdentifier}"); RunQuery(SQLStoreResponse, new { SessionIdentifier = diagnostic.SessionIdentifier, PingIdentifier = diagnostic.PingIdentifier, ReceiverIdentifer = response.ReceiverIdentifier, ReceiveTime = response.ReceiveTime, Channel = response.Channel.ToString(), CellularType = response.DeviceDetail.CellularType, CellularProvider = response.DeviceDetail.CellularProvider, CellularSignalStrength = response.DeviceDetail.CellularSignalStrength, WifiProvider = response.DeviceDetail.WifiProvider, WifiSignalStrength = response.DeviceDetail.WifiSignalStrength, BatteryPercentage = response.DeviceDetail.BatteryPercentage, VolumePercentage = response.DeviceDetail.VolumePercentage }); }
public PingLookupResult RegisterTripResponse(PingDiagnostic tripData, PingDiagnosticResponse response) { //If the tripdata was not ours we skip processing and signal that it's not our process for now if (tripData == null) { return(PingLookupResult.Invalid); } if (IsNewResponseForPing(tripData, response)) { tripData.Responders.Add(response); } else { logger.LogDebug($"Response on ping {tripData.SessionIdentifier}|{tripData.PingIdentifier} by {response.ReceiveTime} over {response.Channel} is already processed, skipping duplicate"); } return(PingLookupResult.Found); //whether or not we were allowed to process this }
private void TransmitPing(PingDiagnostic ping) { //TODO: The order of execution might influence how soon everything is processed, however this might be a bit overdone to make this a set of parallel threads try { if (configuration.TestFirebase) { firebaseChannel.WritePing(ping); } if (configuration.TestMulticast) { multicastClient.SendMessage($"MCPING|{ping.SessionIdentifier}|{ping.PingIdentifier}"); } }catch (Exception e) { logger.LogWarning($"Failed to transmit ping: {e.Message}"); } }
public static async Task <IActionResult> RegisterPingData([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Ping/{sessionId}/{pingId}")] HttpRequest req, ILogger log, ExecutionContext context, string sessionId, string pingId) { try { string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); PingDiagnostic ping = JsonConvert.DeserializeObject <PingDiagnostic>(requestBody); log.LogInformation($"Received ping: {sessionId}|{pingId}"); log.LogInformation($"Ping data: {ping?.IsSuccess}"); //Sanity checks if (ping == null) { log.LogError("No ping data provided"); return(new BadRequestObjectResult("No ping body received")); } if (sessionId != ping.SessionIdentifier) { log.LogError($"Mismatch in sessionID: {sessionId} vs {ping.SessionIdentifier}"); return(new BadRequestObjectResult("SessionID mismatch between endpoint and body")); } if (pingId != ping.PingIdentifier) { log.LogError($"Mismatch in ping: {pingId} vs {ping.PingIdentifier}"); return(new BadRequestObjectResult("PingID mismatch between endpoint and body")); } WarnOnInconsistentIdentifiers(ping, log); //Init config var configRoot = GetConfigurationRoot(context); //Store the data new PingDataWriter(configRoot, log).RegisterPingData(ping); //Success, tnx and bye return(new OkObjectResult(new { success = true, message = $"Stored ping {sessionId}|{pingId}" })); } catch (Exception e) { log.LogError($"Failed request: {e.ToString()}"); return(new BadRequestObjectResult(new { success = false, message = $"Could not process request: {e.Message}" })); } }
public void RegisterPingData(PingDiagnostic diagnostic) { logger.LogInformation($"Processing storage of diagnostic with {diagnostic.Responders?.Count ?? 0} responses"); RegisterPingRequest(diagnostic); diagnostic?.Responders?.ForEach(r => RegisterPongResponse(diagnostic, r)); }
private string GetIdentifier(PingDiagnostic ping) { return($"{ping.SessionIdentifier}|{ping.PingIdentifier}"); }
private void OutputPingResult(PingDiagnostic roundtrip) { OutputPingToLog(roundtrip); azurePublisher.PublishToAzure(roundtrip); }
private void CleanupPingResult(PingDiagnostic roundtrip) { firebaseChannel.DisposePing(roundtrip); container.PurgeTripResponse(roundtrip); }