-
Notifications
You must be signed in to change notification settings - Fork 36
Sync reset #1280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Sync reset #1280
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,8 +45,6 @@ public partial class ClientSyncComponent | |
|
|
||
| TableClient TableClient { get; set; } | ||
|
|
||
| List<string> ReceivedValues { get; set; } = new List<string>(); | ||
|
|
||
| Timer Timer { get; set; } | ||
|
|
||
| bool Paused { get; set; } = false; | ||
|
|
@@ -182,7 +180,23 @@ public async void OnPuzzleChangedAsync(JsPuzzleChange[] puzzleChanges) | |
| value: change.value, | ||
| channel: change.channel); | ||
|
|
||
| await TableClient.UpsertEntityAsync(puzzleEntry); | ||
| await TableClient.UpsertEntityAsync(puzzleEntry, TableUpdateMode.Replace); | ||
| } | ||
| } | ||
|
|
||
| [JSInvokable] | ||
| public async Task OnPuzzleResetAsync(JsPuzzleReset resets) | ||
| { | ||
| if (!SyncEnabled || Paused) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // Create a reset entry for each sub-puzzle | ||
| foreach (string subPuzzleId in resets.puzzleIds) | ||
| { | ||
| PuzzleItemProperty resetEntry = PuzzleItemProperty.CreateReset(PuzzleId, TeamId, Base64UrlTextEncoder.Encode(Encoding.UTF8.GetBytes(subPuzzleId)), PuzzleUserId, channel: resets.channel); | ||
| await TableClient.UpsertEntityAsync(resetEntry, TableUpdateMode.Replace); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -229,29 +243,77 @@ private async Task SyncAsync() | |
| { | ||
| bool foundNewData = false; | ||
|
|
||
| var newChanges = TableClient.QueryAsync<PuzzleItemProperty>(entry => entry.PartitionKey == PuzzleItemProperty.CreatePartitionKey(PuzzleId, TeamId) && entry.Timestamp > LastSyncUtc); | ||
| var unsortedChanges = TableClient.QueryAsync<PuzzleItemProperty>(entry => entry.PartitionKey == PuzzleItemProperty.CreatePartitionKey(PuzzleId, TeamId) && entry.Timestamp > LastSyncUtc); | ||
|
|
||
| List<JsPuzzleChange> jsChanges = new List<JsPuzzleChange>(); | ||
| await foreach (PuzzleItemProperty entry in newChanges) | ||
| List<PuzzleItemProperty> newChanges = new List<PuzzleItemProperty>(); | ||
| await foreach (PuzzleItemProperty entry in unsortedChanges) | ||
| { | ||
| newChanges.Add(entry); | ||
| } | ||
| newChanges.Sort((a, b) => a.Timestamp?.CompareTo(b.Timestamp!.Value) ?? 0); | ||
|
|
||
| // If a puzzle was reset, remove the earlier data for that puzzle to avoid it flashing in and then disappearing | ||
|
|
||
| bool removedEntries = false; | ||
| do | ||
| { | ||
| removedEntries = false; | ||
| for (int i = 0; i < newChanges.Count; i++) | ||
| { | ||
| PuzzleItemProperty entry = newChanges[i]; | ||
| if (entry.IsReset) | ||
| { | ||
| // Remove all data entries for this sub-puzzle | ||
| int removedForReset = newChanges.RemoveAll(e => e.SubPuzzleId == entry.SubPuzzleId && | ||
| e.Timestamp < entry.Timestamp && !e.IsReset); | ||
morganbr marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you do not need to do the IsReset check here - if there are two resets for the same puzzle you only need one and your timestamp check will keep you from removing yourself |
||
| if (removedForReset > 0) | ||
| { | ||
| removedEntries = true; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just say
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussion: Do one loop to identify reset timestamps and then one to build the collection of post-reset data to populate onto the page to guarantee O(N) |
||
| break; | ||
| } | ||
| } | ||
| } | ||
| } while (removedEntries); | ||
|
|
||
| List < JsPuzzleChange > jsChanges = new List<JsPuzzleChange>(); | ||
| foreach (PuzzleItemProperty entry in newChanges) | ||
| { | ||
| foundNewData = true; | ||
| ReceivedValues.Add(entry.Value); | ||
| jsChanges.Add(new JsPuzzleChange() | ||
| if (entry.IsReset) | ||
| { | ||
| // If this is a reset, we need to send a reset message to the JS side | ||
| await JSRuntime.InvokeVoidAsync("onPuzzleResetSynced", new JsPuzzleReset() | ||
| { | ||
| puzzleIds = new[] { Encoding.UTF8.GetString(Base64UrlTextEncoder.Decode(entry.SubPuzzleId)) }, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not build a list of IDs and send them all at once |
||
| channel = entry.Channel | ||
| }); | ||
| } | ||
| else | ||
| { | ||
| locationKey = entry.LocationKey, | ||
| playerId = PuzzleUserId.ToString(), | ||
| propertyKey = entry.PropertyKey, | ||
| puzzleId = Encoding.UTF8.GetString(Base64UrlTextEncoder.Decode(entry.SubPuzzleId)), | ||
| teamId = TeamId.ToString(), | ||
| value = entry.Value | ||
| }); | ||
| jsChanges.Add(new JsPuzzleChange() | ||
| { | ||
| locationKey = entry.LocationKey, | ||
| playerId = PuzzleUserId.ToString(), | ||
| propertyKey = entry.PropertyKey, | ||
| puzzleId = Encoding.UTF8.GetString(Base64UrlTextEncoder.Decode(entry.SubPuzzleId)), | ||
| teamId = TeamId.ToString(), | ||
| value = entry.Value, | ||
| channel = entry.Channel | ||
| }); | ||
|
|
||
| //morganb debug | ||
| await JSRuntime.InvokeVoidAsync("onPuzzleSynced", [jsChanges.ToArray()]); | ||
| jsChanges.Clear(); | ||
morganbr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| LastSyncUtc = entry.Timestamp > LastSyncUtc ? entry.Timestamp.Value : LastSyncUtc; | ||
| DisplayLastSyncUtc = entry.Timestamp > DisplayLastSyncUtc ? entry.Timestamp.Value : DisplayLastSyncUtc; | ||
| } | ||
|
|
||
| if (foundNewData) | ||
| { | ||
| await JSRuntime.InvokeVoidAsync("onPuzzleSynced", [jsChanges.ToArray()]); | ||
| // morganb debug | ||
| //await JSRuntime.InvokeVoidAsync("onPuzzleSynced", [jsChanges.ToArray()]); | ||
morganbr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| await InvokeAsync(StateHasChanged); | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.