public SubscriptionList(Socket socket) { _subscribedSockets = new ConcurrentDictionary<int, Socket> { [socket.GetHashCode()] = socket }; }
public void UnSubscribe(string topic, Socket socket) { SubscriptionList topicSubscribers; if (!_subscriptions.TryGetValue(topic, out topicSubscribers)) return; topicSubscribers.Remove(socket); }
internal JoinResult Join(string topic, Socket socket) { var attr = _channelTopics.Keys.FirstOrDefault(a => a.IsMatch(topic)); if (attr == null) throw new Exception($"Unable to route ${topic} to a channel topic in class ${GetType()}"); MethodInfo action; if (!_channelTopics.TryGetValue(attr, out action)) throw new Exception($"Unable to get channel join action for topic {topic}."); if (!attr.HasBoundSubtopic) return action.Invoke(this, new object[] { socket }) as JoinResult; var boundParam = attr.GetBoundSubtopic(topic); var paramsInfo = action.GetParameters(); var args = new object[paramsInfo.Length]; for (int i = 0; i < paramsInfo.Length; i++) { var paramInfo = paramsInfo[i]; if (paramInfo.ParameterType == typeof(Socket)) args[i] = socket; else if (paramInfo.Name == boundParam.Name && paramInfo.ParameterType == typeof(string)) args[i] = boundParam.Value; else throw new Exception($"Unable to bind param {paramInfo.Name}."); } return action.Invoke(this, args) as JoinResult; }
/// <summary> /// Creates a socket and dispatches it and a message to a channel. /// </summary> protected Task Dispatch(Message message) { if (message == null) return Task.FromResult(0); var channel = Channel.MatchTopic(message.Topic); var socket = new Socket(this, _pubSub, channel, message.Topic); switch (message.Event) { case "phx_join": return JoinChannel(socket, message); case "phx_leave": return LeaveChannel(socket, message); case "heartbeat": return Heartbeat(socket, message); default: return DispatchMessage(socket, message); } }
public void Remove(Socket socket) { Socket _; _subscribedSockets.TryRemove(socket.GetHashCode(), out _); }
public bool Add(Socket socket) => _subscribedSockets.TryAdd(socket.GetHashCode(), socket);
public Task Broadcast(Socket socket, string @event, JObject payload) => Broadcast(socket.Topic, @event, payload);
public void Subscribe(string topic, Socket socket) { var subscriptionList = _subscriptions.GetOrAdd(topic, _key => new SubscriptionList(socket)); subscriptionList.Add(socket); }
/// <summary> /// Dispatches a message to a channel. /// </summary> /// <param name="message"></param> /// <returns></returns> protected static async Task DispatchMessage(Socket socket, Message message) { var eventResult = await socket.Channel.HandleIn(message, socket); switch(eventResult.ResultAction) { case EventResult.Action.NoReply: return; case EventResult.Action.Reply: await socket.Transport.SendReply(new Reply(message.Ref, message.Topic, eventResult.Status, eventResult.Response)); return; case EventResult.Action.Stop: // ?? return; } }
/// <summary> /// Converts a heartbeat message to a heartbeat reply. /// </summary> protected static Task Heartbeat(Socket socket, Message message) => socket.Transport.SendReply((new Reply(message.Ref, message.Topic, "ok", new JObject())));
protected static Task LeaveChannel(Socket socket, Message message) { return null; }
/// <summary> /// Subscribes to a channel topic. /// </summary> protected static Task JoinChannel(Socket socket, Message message) { JObject payload; string status; var joinResult = socket.Channel.Join(message.Topic, socket); if (joinResult.Success) { socket.PubSub.Subscribe(message.Topic, socket); status = "ok"; payload = joinResult.Response; } else { status = "error"; payload = new JObject(joinResult.Error); } return socket.Transport.SendReply(new Reply(message.Ref, message.Topic, status, payload)); }
public static Task Push(Socket socket, string @event, JObject payload) { var broadcast = new Broadcast(socket.Topic, @event, payload); return socket.Transport.SendBroadcast(broadcast); }
public static Task Broadcast(Socket socket, string @event, JObject payload) { return socket.PubSub.Broadcast(socket, @event, payload); }
internal async Task<EventResult> HandleOut(string @event, JObject payload, Socket socket) { var attr = _outgoingEvents.Keys.FirstOrDefault(a => a.IsMatch(@event)); if (attr == null) { await Push(socket, @event, payload); return EventResult.NoReply; } MethodInfo action; if (!_outgoingEvents.TryGetValue(attr, out action)) throw new Exception($"Unable to get channel handle out hook for event {@event}."); return await (action.Invoke(this, new object[] { payload, socket }) as Task<EventResult>); }
internal async Task<EventResult> HandleIn(Message message, Socket socket) { var attr = _incomingEvents.Keys.FirstOrDefault(a => a.IsMatch(message.Event)); if (attr == null) throw new Exception($"Unable to route ${message.Event} to a channel incoming event hook in class ${GetType()}"); MethodInfo action; if (!_incomingEvents.TryGetValue(attr, out action)) throw new Exception($"Unable to get channel handle in hook for event {message.Event}."); return await (action.Invoke(this, new object[] { message.Payload, socket }) as Task<EventResult>); }