public void Pong(Guid pingId, long clientTimeSent) { //simulate up latency here //System.Threading.Thread.Sleep(2000); var serverTimeReceived = DateTime.UtcNow; var ping = Pings[pingId]; var clientPing = TimeSyncMessage.NewFrom(ping); clientPing.ConnectionId = Context.ConnectionId; clientPing.ClientTimeSent = JavaScriptDateConverter.Convert(clientTimeSent); clientPing.ServerTimeReceived = serverTimeReceived; Pongs.AddOrUpdate(clientPing.ConnectionId, c => clientPing, (c, old) => { if (old.Roundtrip > clientPing.Roundtrip) { //this was more accurate...use it return(clientPing); } else { return(old); } }); ShowPings(); }
//Usage public string SendCommand(long clientTimeSent, string message = "General Command") { //Random r = new Random(); //var upArtificialLatency = r.Next(500, 1500); //var downArtificialLatency = r.Next(0, 500); //simulate up latency here //System.Threading.Thread.Sleep(upArtificialLatency); var serverReceiveDateTime = DateTime.UtcNow; var clientDateTime = JavaScriptDateConverter.Convert(clientTimeSent); Pongs.TryGetValue(Context.ConnectionId, out TimeSyncMessage senderTimeSync); var sendTimeFromServerPerspective = clientDateTime.Subtract(senderTimeSync.ClientOffsetTimespan); TimeSpan possibleUpLatency = serverReceiveDateTime - sendTimeFromServerPerspective; if (possibleUpLatency.TotalMilliseconds >= 500) { //fail command //return $"Command rejected: already {possibleUpLatency.TotalMilliseconds}ms old."; message += $"(passed server threshold. saw {possibleUpLatency.TotalMilliseconds}ms)"; } ClientIds.Keys.Where(id => id != Context.ConnectionId).ToList().ForEach(id => { //get if (!Pongs.TryGetValue(id, out TimeSyncMessage receiverTimeSync)) { return; } var sendTimeFromReceiverPerspective = sendTimeFromServerPerspective.Add(receiverTimeSync.ClientOffsetTimespan); var wrappedMessage = new { sendTimeFromSendersPerspective = clientDateTime, sendTimeFromServerPerspective, sendTimeFromReceiverPerspective, sendTime = JavaScriptDateConverter.Convert(sendTimeFromReceiverPerspective), message, // upArtificialLatency, //downArtificialLatency, //totalArtificialLatency = upArtificialLatency + downArtificialLatency }; //simulate down latency here //System.Threading.Thread.Sleep(downArtificialLatency); Clients.Client(id).receiveCommand(wrappedMessage); }); return(""); }