// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.Use((context, next) => { context.Response.Headers["Access-Control-Allow-Origin"] = "*"; return(next.Invoke()); }); app.UseCors(builder => builder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); var webSocketOptions = new WebSocketOptions() { KeepAliveInterval = TimeSpan.FromSeconds(120), ReceiveBufferSize = 4 * 1024 }; webSocketOptions.AllowedOrigins.Add("*"); app.UseWebSockets(webSocketOptions); app.Use(async(context, next) => { if (context.Request.Path == "/ws") { if (context.WebSockets.IsWebSocketRequest) { WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); await ProcessClientMessages(context, webSocket); } else { context.Response.StatusCode = 400; } } else { await next(); } }); ChannelHub.StartCleanupThread(); }
private async Task HandleClientMessage(ChannelHub.ConnectedClient cc, string command, string payload) { if (command == "ID") // Set client Id { cc.ClientId = payload; } else if (command == "JOIN") { await ChannelHub.AddClientToChannelAsync(cc, payload); } else if (command == "LEAVE") { ChannelHub.RemoveClientFromChannel(cc, payload); } else if (command == "MSG") { var messageData = System.Text.Json.JsonSerializer.Deserialize <ChannelHub.CommandMessageData>(payload); if (messageData != null) { ChannelHub.SendMessageFromClientToChannel(cc, messageData.Channel, messageData.Data); } } }
private async Task ProcessClientMessages(HttpContext context, WebSocket webSocket) { var cc = new ChannelHub.ConnectedClient() { WebSocketClient = webSocket, Channels = new List <string>(), ClientId = null, BufferedData = new List <byte>(), SendingData = false }; var message = await ReceiveFullMessage(webSocket, CancellationToken.None); WebSocketReceiveResult result = message.Item1; while (result != null && !result.CloseStatus.HasValue) { // Process message // Command syntax: Command|Length payload|Payload if (result.MessageType == WebSocketMessageType.Text) { var data = ASCIIEncoding.UTF8.GetString(message.Item2.ToArray()); var dataLeft = data.Length; while (dataLeft > 0) { var indexOfSeperator = data.IndexOf("|"); if (indexOfSeperator <= 0) { break; // No first separator } var command = data.Substring(0, indexOfSeperator); var indexOfSecondSeperator = data.IndexOf("|", indexOfSeperator + 1); if (indexOfSecondSeperator <= 0) { break; // No second separator } if (!Int32.TryParse(data.Substring(indexOfSeperator + 1, indexOfSecondSeperator - (indexOfSeperator + 1)), out var dataLength)) { break; // Message length is not a number } var indexEndOfMessage = dataLength + indexOfSeperator + 1; if (data.Length < indexEndOfMessage) { break; // Payload part is smaller than what the header is saying } await HandleClientMessage(cc, command, data.Substring(indexOfSecondSeperator + 1, dataLength)); data = data.Substring(indexEndOfMessage); } } message = await ReceiveFullMessage(webSocket, CancellationToken.None); result = message.Item1; } if (result == null) { await webSocket.CloseAsync(WebSocketCloseStatus.MessageTooBig, "Buffer full", CancellationToken.None); } else { await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); } List <string> unsubChannels = null; lock (cc.Channels) unsubChannels = cc.Channels.ToList(); foreach (var channel in unsubChannels) { ChannelHub.RemoveClientFromChannel(cc, channel); } }