// lower-level public static API /** * Used to sync the list of presences on the server * with the client's state. An optional `onJoin` and `onLeave` callback can * be provided to react to changes in the client's local presences across * disconnects and reconnects with the server. */ public static State SyncState( State currentState, State newState, OnJoinDelegate onJoin = null, OnLeaveDelegate onLeave = null ) { var joins = new State(); var leaves = new State(); foreach (var key in currentState.Keys.Where(key => !newState.ContainsKey(key))) { leaves[key] = currentState[key]; } foreach (var key in newState.Keys) { var newPresence = newState[key]; var found = currentState.TryGetValue(key, out var currentPresence); if (found) { var newRefs = newPresence.Metas.Select(m => m["phx_ref"]).ToList(); var curRefs = currentPresence.Metas.Select(m => m["phx_ref"]).ToList(); var joinedMetas = newPresence.Metas.Where(m => curRefs.IndexOf(m["phx_ref"]) < 0).ToList(); var leftMetas = currentPresence.Metas.Where(m => !newRefs.Contains(m["phx_ref"])).ToList(); if (joinedMetas.Count > 0) { joins[key] = new MetadataContainer { Metas = joinedMetas }; } if (leftMetas.Count > 0) { leaves[key] = new MetadataContainer { Metas = leftMetas }; } } else { joins[key] = newPresence; } } var diff = new Diff { Joins = joins, Leaves = leaves }; return(SyncDiff(new State(currentState), diff, onJoin, onLeave)); }
public static State SyncState(State currentState, State newState, OnJoinDelegate onJoin, OnLeaveDelegate onLeave) { var state = Clone(currentState); var joins = new State(); var leaves = new State(); foreach (var entry in state) { if (!newState.ContainsKey(entry.Key)) { leaves[entry.Key] = entry.Value; } } foreach (var entry in newState) { if (state.ContainsKey(entry.Key)) { var currentItem = state[entry.Key]; var newRefs = entry.Value["metas"].Select(m => m["phx_ref"]).ToList(); var curRefs = currentItem["metas"].Select(m => m["phx_ref"]).ToList(); var joinedMetas = entry.Value["metas"].Where(m => !curRefs.Contains(m["phx_ref"])).ToList(); var leftMetas = currentItem["metas"].Where(m => !newRefs.Contains(m["phx_ref"])).ToList(); if (joinedMetas.Count() > 0) { joins[entry.Key] = entry.Value; joins[entry.Key]["metas"] = joinedMetas; } if (leftMetas.Count() > 0) { leaves[entry.Key] = Clone(currentItem); leaves[entry.Key]["metas"] = leftMetas; } } else { joins[entry.Key] = entry.Value; } } var diff = new Diff(); diff["joins"] = joins; diff["leaves"] = leaves; return(SyncDiff(state, diff, onJoin, onLeave)); }
private (Presence, Channel) NewPresence(string id, OnJoinDelegate onJoin = null, OnLeaveDelegate onLeave = null, OnSyncDelegate onSync = null) { var socketFactory = new DotNetWebSocketFactory(); var socket = new Socket(socketFactory, new Socket.Options { channelRejoinInterval = TimeSpan.FromMilliseconds(200), logger = new BasicLogger() }); var url = string.Format("ws://{0}/phoenix_sharp_test", host); socket.Connect(url); Assert.IsTrue(socket.state == Socket.State.Open); var channel = socket.MakeChannel("presence"); var presence = new Presence(channel); if (onJoin != null) { presence.onJoin = onJoin; } if (onLeave != null) { presence.onLeave = onLeave; } if (onSync != null) { presence.onSync = onSync; } Reply?joinOkReply = null; Reply?joinErrorReply = null; channel.Join(new Dictionary <string, object> { { "id", id } }) .Receive(Reply.Status.Ok, r => joinOkReply = r) .Receive(Reply.Status.Error, r => joinErrorReply = r); Assert.That(() => joinOkReply.HasValue, Is.True.After(networkDelay, 10)); return(presence, channel); }
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); }
public Task <IAsyncDisposable> OnJoin(OnJoinDelegate handler) { return(InnerSubscribe(handler, x => x.OnJoin(default(WampSessionDetails)))); }