Ejemplo n.º 1
0
        public async Task ExecuteAsync <TEndPoint>(string path, HttpContext context) where TEndPoint : EndPoint
        {
            if (context.Request.Path.StartsWithSegments(path + "/getid"))
            {
                await ProcessGetId(context);
            }
            else if (context.Request.Path.StartsWithSegments(path + "/send"))
            {
                await ProcessSend(context);
            }
            else
            {
                // Get the end point mapped to this http connection
                var endpoint = (EndPoint)context.RequestServices.GetRequiredService <TEndPoint>();
                var format   =
                    string.Equals(context.Request.Query["format"], "binary", StringComparison.OrdinalIgnoreCase)
                        ? Format.Binary
                        : Format.Text;

                // Server sent events transport
                if (context.Request.Path.StartsWithSegments(path + "/sse"))
                {
                    // Get the connection state for the current http context
                    var state = GetOrCreateConnection(context);
                    state.Connection.User = context.User;
                    state.Connection.Metadata["transport"] = "sse";
                    state.Connection.Metadata.Format       = format;

                    // TODO: this is wrong. + how does the user add their own metadata based on HttpContext
                    var formatType = (string)context.Request.Query["formatType"];
                    state.Connection.Metadata["formatType"] = string.IsNullOrEmpty(formatType) ? "json" : formatType;

                    var sse = new ServerSentEvents(state.Connection);

                    await DoPersistentConnection(endpoint, sse, context, state.Connection);

                    _manager.RemoveConnection(state.Connection.ConnectionId);
                }
                else if (context.Request.Path.StartsWithSegments(path + "/ws"))
                {
                    // Get the connection state for the current http context
                    var state = GetOrCreateConnection(context);
                    state.Connection.User = context.User;
                    state.Connection.Metadata["transport"] = "websockets";
                    state.Connection.Metadata.Format       = format;

                    // TODO: this is wrong. + how does the user add their own metadata based on HttpContext
                    var formatType = (string)context.Request.Query["formatType"];
                    state.Connection.Metadata["formatType"] = string.IsNullOrEmpty(formatType) ? "json" : formatType;

                    var ws = new WebSockets(state.Connection, format);

                    await DoPersistentConnection(endpoint, ws, context, state.Connection);

                    _manager.RemoveConnection(state.Connection.ConnectionId);
                }
                else if (context.Request.Path.StartsWithSegments(path + "/poll"))
                {
                    bool isNewConnection;
                    var  state = GetOrCreateConnection(context, out isNewConnection);
                    // TODO: this is wrong. + how does the user add their own metadata based on HttpContext
                    var formatType = (string)context.Request.Query["formatType"];
                    state.Connection.Metadata["formatType"] = string.IsNullOrEmpty(formatType) ? "json" : formatType;

                    // Mark the connection as active
                    state.Active = true;

                    RegisterLongPollingDisconnect(context, state.Connection);

                    var longPolling = new LongPolling(state.Connection);

                    // Start the transport
                    var transportTask = longPolling.ProcessRequestAsync(context);

                    Task endpointTask = null;

                    // Raise OnConnected for new connections only since polls happen all the time
                    if (isNewConnection)
                    {
                        state.Connection.Metadata["transport"] = "poll";
                        state.Connection.Metadata.Format       = format;
                        state.Connection.User = context.User;

                        // REVIEW: This is super gross, this all needs to be cleaned up...
                        state.Close = async() =>
                        {
                            state.Connection.Channel.Dispose();

                            await endpointTask;
                        };

                        endpointTask = endpoint.OnConnectedAsync(state.Connection);
                        state.Connection.Metadata["endpoint"] = endpointTask;
                    }
                    else
                    {
                        // Get the endpoint task from connection state
                        endpointTask = state.Connection.Metadata.Get <Task>("endpoint");
                    }

                    var resultTask = await Task.WhenAny(endpointTask, transportTask);

                    if (resultTask == endpointTask)
                    {
                        // Notify the long polling transport to end
                        state.Connection.Channel.Dispose();

                        await transportTask;
                    }

                    // Mark the connection as inactive
                    state.LastSeen = DateTimeOffset.UtcNow;
                    state.Active   = false;
                }
            }
        }