/// <summary> /// This routine fetches the list of annotations that the requester's team has made since the last /// time the requester got a list of annotations. /// </summary> private async Task GetAnnotationsRequesterLacks(DecodedSyncRequest request, SyncResponse response, int puzzleId, int teamId) { // We get the current time (which we'll later set as the "sync time") *before* we do the // query, so that it's a conservative estimate of when the sync happened. DateTime now = DateTime.Now; List <Annotation> annotations; if (request.LastSyncTime == null) { // If the requester didn't specify a last-sync time, then provide all the annotations from their team // for this puzzle. annotations = await(from a in context.Annotations where a.PuzzleID == puzzleId && a.TeamID == teamId select a).ToListAsync(); } else { // We know the time of the last request, so in theory we should just return only // annotations that are from that time or later. But, it could happen that an // update that was concurrent with the previous sync request didn't make it into the // returned list but nevertheless got a timestamp after that sync request. Also, // there may be multiple web servers, with slightly unsynchronized clocks. So, for // safety, we subtract five seconds. This may cause us to unnecessarily fetch and // return an annotation the requester already knows about, but this is harmless: The // requester will see that the annotation has the same version number as the one // the requester already knows about for that key, and ignore it. var lastSyncTimeMinusSlop = request.LastSyncTime.Value.AddSeconds(-5); annotations = await(from a in context.Annotations where a.PuzzleID == puzzleId && a.TeamID == teamId && a.Timestamp >= lastSyncTimeMinusSlop select a).ToListAsync(); } response.SetSyncTimeAndAnnotations(now, annotations); }