Exemple #1
0
 private static void UnbindEvent(Thing thing, ThingObserver observer)
 {
     foreach (var @event in observer.EventsBind)
     {
         thing.ThingContext.Events[@event].Added -= observer.OnEvenAdded;
     }
 }
Exemple #2
0
 private static void UnbindActions(Thing thing, ThingObserver observer)
 {
     foreach (var(_, actionContext) in thing.ThingContext.Actions)
     {
         actionContext.Actions.Change -= observer.OnActionChange;
     }
 }
Exemple #3
0
        public static async Task InvokeAsync(HttpContext context)
        {
            var service      = context.RequestServices;
            var cancellation = context.RequestAborted;

            var logger = service.GetRequiredService <ILogger <WebSocket> >();

            var things = service.GetRequiredService <IEnumerable <Thing> >();
            var option = service.GetRequiredService <ThingOption>();

            var name = context.GetRouteData <string>("name");

            var thing = option.IgnoreCase switch
            {
                true => things.FirstOrDefault(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)),
                _ => things.FirstOrDefault(x => x.Name == name)
            };

            if (thing == null)
            {
                logger.LogInformation("Thing not found. [Name: {name}]", name);
                context.Response.StatusCode = (int)HttpStatusCode.NotFound;
                return;
            }

            logger.LogInformation("Going to accept new Web Socket connection for {thing} Thing", name);
            var socket = await context.WebSockets.AcceptWebSocketAsync()
                         .ConfigureAwait(false);


            var id = Guid.NewGuid();

            thing.ThingContext.Sockets.TryAdd(id, socket);

            byte[]? buffer = null;

            var actions = service.GetRequiredService <Dictionary <string, IWebSocketAction> >();

            var jsonOptions = service.GetRequiredService <JsonSerializerOptions>();

            var webSocketOption = service.GetRequiredService <IOptions <WebSocketOptions> >().Value;

            var observer = new ThingObserver(service.GetRequiredService <ILogger <ThingObserver> >(),
                                             jsonOptions, socket, cancellation, thing);

            try
            {
                BindActions(thing, observer);
                BindPropertyChanged(thing, observer);

                while (!socket.CloseStatus.HasValue && !cancellation.IsCancellationRequested)
                {
                    if (buffer != null)
                    {
                        s_pool.Return(buffer, true);
                    }

                    buffer = s_pool.Rent(webSocketOption.ReceiveBufferSize);
                    var segment  = new ArraySegment <byte>(buffer);
                    var received = await socket
                                   .ReceiveAsync(segment, cancellation)
                                   .ConfigureAwait(false);

                    var json = JsonSerializer.Deserialize <JsonElement>(segment.Slice(0, received.Count), jsonOptions);

                    if (!json.TryGetProperty("messageType", out var messageType))
                    {
                        logger.LogInformation("Web Socket request without messageType");
                        await socket.SendAsync(s_error, WebSocketMessageType.Text, true, cancellation)
                        .ConfigureAwait(false);

                        continue;
                    }

                    if (!json.TryGetProperty("data", out var data))
                    {
                        logger.LogInformation("Web Socket request without data. [Message Type: {messageType}]", messageType.GetString());
                        await socket.SendAsync(s_error, WebSocketMessageType.Text, true, cancellation)
                        .ConfigureAwait(false);

                        continue;
                    }

                    if (!actions.TryGetValue(messageType.GetString(), out var action))
                    {
                        logger.LogInformation("Invalid Message Type: {messageType}", messageType.GetString());
                        await socket.SendAsync(s_error, WebSocketMessageType.Text, true, cancellation)
                        .ConfigureAwait(false);

                        continue;
                    }

                    try
                    {
                        using var scope = service.CreateScope();
                        scope.ServiceProvider.GetRequiredService <ThingObserverResolver>().Observer = observer;
                        await action.ExecuteAsync(socket, thing, data, jsonOptions, scope.ServiceProvider, cancellation)
                        .ConfigureAwait(false);
                    }
                    catch (Exception e)
                    {
                        logger.LogError(e, "Error to execute Web Socket Action: {action}", messageType.GetString());
                    }
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Error to execute WebSocket, going to close connection");

                await socket.CloseAsync(WebSocketCloseStatus.InternalServerError, ex.ToString(),
                                        CancellationToken.None)
                .ConfigureAwait(false);
            }

            thing.ThingContext.Sockets.TryRemove(id, out _);

            if (buffer != null)
            {
                s_pool.Return(buffer, true);
            }

            UnbindActions(thing, observer);
            UnbindPropertyChanged(thing, observer);
            UnbindEvent(thing, observer);
        }
Exemple #4
0
 private static void UnbindPropertyChanged(Thing thing, ThingObserver observer)
 => thing.PropertyChanged -= observer.OnPropertyChanged;