/** * Used to sync a diff of presence join and leave * events from the server, as they happen. Like `syncState`, `syncDiff` * accepts optional `onJoin` and `onLeave` callbacks to react to a user * joining or leaving from a device. */ private static State SyncDiff( State state, Diff diff, OnJoinDelegate onJoin, OnLeaveDelegate onLeave ) { foreach (var key in diff.Joins.Keys) { var newPresence = diff.Joins[key]; var found = state.TryGetValue(key, out var currentPresence); state[key] = newPresence; if (found) { var joinedRefs = state[key].Metas.Select(m => m["phx_ref"]).ToList(); var curMetas = currentPresence.Metas.Where(m => joinedRefs.IndexOf(m["phx_ref"]) < 0).ToList(); state[key].Metas.InsertRange(0, curMetas); } onJoin?.Invoke(key, currentPresence, newPresence); } foreach (var key in diff.Leaves.Keys) { var leftPresence = diff.Leaves[key]; var found = state.TryGetValue(key, out var currentPresence); if (!found) { continue; } var refsToRemove = leftPresence.Metas.Select(m => m["phx_ref"]).ToList(); var filteredMetas = currentPresence.Metas.Where( m => refsToRemove.IndexOf(m["phx_ref"]) < 0).ToList(); var newPresence = new MetadataContainer { Metas = filteredMetas }; onLeave?.Invoke(key, newPresence, leftPresence); if (newPresence.Metas.Count == 0) { state.Remove(key); } else { state[key] = newPresence; } } return(state); }
public static State SyncDiff(State currentState, Diff diff, OnJoinDelegate onJoin, OnLeaveDelegate onLeave) { var state = Clone(currentState); foreach (var entry in diff["joins"]) { Item currentItem = null; if (state.ContainsKey(entry.Key)) { currentItem = state[entry.Key]; } state[entry.Key] = entry.Value; if (currentItem != null) { var joinedRefs = state[entry.Key]["metas"].Select(m => m["phx_ref"]).ToList(); var curMetas = currentItem["metas"].Where(m => !joinedRefs.Contains(m["phx_ref"])).ToList(); state[entry.Key]["metas"] = curMetas.Concat(state[entry.Key]["metas"]).ToList(); } onJoin?.Invoke(entry.Key, currentItem, entry.Value); } foreach (var entry in diff["leaves"]) { if (!state.ContainsKey(entry.Key)) { continue; } var currentItem = state[entry.Key]; var refsToRemove = entry.Value["metas"].Select(m => m["phx_ref"]).ToList(); currentItem["metas"] = currentItem["metas"].Where(m => !refsToRemove.Contains(m["phx_ref"])).ToList(); onLeave?.Invoke(entry.Key, currentItem, entry.Value); if (currentItem["metas"].Count() == 0) { state.Remove(entry.Key); } } return(state); }