/// Websocket methods public static async Task AddClientToChannelAsync(ConnectedClient ws, string channel) { if (ws.Channels.Contains(channel)) { return; } IdentityHandler.InternalIdentity identity = null; if (channel.StartsWith("https://") || channel.StartsWith("http://")) { // Check if this client is allowed to join this channel identity = await IdentityHandler.GetIdentityAsync(ws.ClientId, channel); if (identity == null) { return; } } InternalChannel internalChannel = null; lock (Channels) { if (!Channels.ContainsKey(channel)) { Channels.Add(channel, new InternalChannel() { Channel = channel, LastMessage = DateTime.UtcNow, Messages = new ChannelMessageData[MaxMessageBuffer], CurIndex = 0, Clients = new List <ConnectedClient>() }); } internalChannel = Channels[channel]; } lock (internalChannel.Clients) internalChannel.Clients.Add(ws); ws.Channels.Add(channel); }
public static async Task <ChannelData> GetMessagesForChannelSinceIndexAsync(string clientId, string channel, long index) { // If Channel starts with https:// , use the clientId to request the identity from the url IdentityHandler.InternalIdentity identity = null; if (channel.StartsWith("https://") || channel.StartsWith("http://")) { identity = await IdentityHandler.GetIdentityAsync(clientId, channel); if (identity == null) { return(null); } } InternalChannel internalChannel = null; lock (Channels) { if (!Channels.ContainsKey(channel)) { return(null); } internalChannel = Channels[channel]; } var container = new ChannelData() { Channel = channel }; if (identity != null && !identity.Data.allowChannelReceive) // Check if we are allowed to receive messages { container.Messages = new List <ChannelMessageData>(); return(container); } if (index == -1) // On the first request from the client (index == -1), we will only give back at what position we are. { container.Index = internalChannel.CurIndex; container.Messages = new List <ChannelMessageData>(); return(container); } // Find out count to pre-allocate the memory space before going into our locked section var count = internalChannel.CurIndex - index; if (count > MaxMessageBuffer) { count = MaxMessageBuffer; } if (count <= 0) { container.Messages = new List <ChannelMessageData>(); container.Index = internalChannel.CurIndex; return(container); } container.Messages = new List <ChannelMessageData>((int)count); lock (internalChannel.Messages) { // In case the CurIndex is changed before we got the lock container.Index = internalChannel.CurIndex; count = internalChannel.CurIndex - index; if (count > MaxMessageBuffer || count < 0) { count = MaxMessageBuffer; } for (var i = internalChannel.CurIndex - count; i < internalChannel.CurIndex; i++) { var arrayIndex = i % MaxMessageBuffer; var messageObj = internalChannel.Messages[(int)arrayIndex]; if (messageObj.ClientId == clientId) { continue; } container.Messages.Add(messageObj); } } return(container); }
public static async Task SendMessageAsync(string clientId, string channel, string data, ConnectedClient filterClient = null) { if (data.Length > 1024 * 4) { return; } // If Channel starts with https:// , use the clientId to request the identity from the url IdentityHandler.InternalIdentity identity = null; if (channel.StartsWith("https://") || channel.StartsWith("http://")) { identity = await IdentityHandler.GetIdentityAsync(clientId, channel); if (identity == null || !identity.Data.allowChannelSend) { return; } } // Add to channel message hub InternalChannel internalChannel = null; lock (Channels) { if (!Channels.ContainsKey(channel)) { Channels.Add(channel, new InternalChannel() { Channel = channel, LastMessage = DateTime.UtcNow, Messages = new ChannelMessageData[MaxMessageBuffer], CurIndex = 0, Clients = new List <ConnectedClient>() }); } internalChannel = Channels[channel]; } var message = new ChannelMessageData() { Data = data, Identity = identity, ClientId = clientId }; lock (internalChannel.Messages) { var arrayIndex = internalChannel.CurIndex % MaxMessageBuffer; internalChannel.Messages[arrayIndex] = message; internalChannel.CurIndex++; internalChannel.LastMessage = DateTime.UtcNow; } // Broadcast to all websocket connected clients List <ConnectedClient> clients = null; lock (internalChannel.Clients) clients = internalChannel.Clients.Where(a => (filterClient != null && a != filterClient) || (filterClient == null && a.ClientId != clientId)).ToList(); if (clients.Count > 0) { var json = System.Text.Json.JsonSerializer.Serialize(new CommandMessageData() { Channel = channel, Identity = identity?.Data?.publicIdentifier, Data = data }); var dataBytes = System.Text.ASCIIEncoding.UTF8.GetBytes("MSG|" + json.Length + "|" + json); // MSG = 'Channel Message' Command Type foreach (var client in clients) { _ = client.SendDataAsync(dataBytes); } } }