Exemplo n.º 1
0
        private Task ProcessRequestPostGroupRead(HostContext context, string groupsToken)
        {
            string connectionId = Transport.ConnectionId;

            // Get the user id from the request
            string userId = UserIdProvider.GetUserId(context.Request);

            IList <string> signals = GetSignals(userId, connectionId);
            IList <string> groups  = AppendGroupPrefixes(context, connectionId, groupsToken);

            Connection connection = CreateConnection(connectionId, signals, groups);

            Connection = connection;
            string groupName = PrefixHelper.GetPersistentConnectionGroupName(DefaultSignalRaw);

            Groups = new GroupManager(connection, groupName);

            // We handle /start requests after the PersistentConnection has been initialized,
            // because ProcessStartRequest calls OnConnected.
            if (IsStartRequest(context.Request))
            {
                return(ProcessStartRequest(context, connectionId));
            }

            Transport.Connected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnConnected(context.Request, connectionId).OrEmpty()));
            };

            Transport.Reconnected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnReconnected(context.Request, connectionId).OrEmpty()));
            };

            Transport.Received = data =>
            {
                Counters.ConnectionMessagesSentTotal.Increment();
                Counters.ConnectionMessagesSentPerSec.Increment();
                return(TaskAsyncHelper.FromMethod(() => OnReceived(context.Request, connectionId, data).OrEmpty()));
            };

            Transport.Disconnected = clean =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnDisconnected(context.Request, connectionId, stopCalled: clean).OrEmpty()));
            };

            return(Transport.ProcessRequest(connection).OrEmpty().Catch(Trace, Counters.ErrorsAllTotal, Counters.ErrorsAllPerSec));
        }
Exemplo n.º 2
0
 private static void PreserveCultureUnsafeOnCompleted(ICriticalNotifyCompletion notifier,
                                                      Action continuation,
                                                      bool useSyncContext)
 {
     // Rely on the SyncContext to preserve culture if it exists
     if (useSyncContext && SynchronizationContext.Current != null)
     {
         notifier.UnsafeOnCompleted(continuation);
     }
     else
     {
         var preservedCulture = TaskAsyncHelper.SaveCulture();
         notifier.UnsafeOnCompleted(() =>
         {
             TaskAsyncHelper.RunWithPreservedCulture(preservedCulture, continuation);
         });
     }
 }
Exemplo n.º 3
0
        /// <summary>
        /// Handles all requests for <see cref="PersistentConnection"/>s.
        /// </summary>
        /// <param name="context">The <see cref="HttpContext"/> for the current request.</param>
        /// <returns>A <see cref="Task"/> that completes when the <see cref="PersistentConnection"/> pipeline is complete.</returns>
        /// <exception cref="T:System.InvalidOperationException">
        /// Thrown if the transport wasn't specified.
        /// Thrown if the connection id wasn't specified.
        /// </exception>
        public virtual async Task ProcessRequestCore(HttpContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (IsNegotiationRequest(context.Request))
            {
                await ProcessNegotiationRequest(context).PreserveCulture();

                return;
            }
            else if (IsPingRequest(context.Request))
            {
                await ProcessPingRequest(context).PreserveCulture();

                return;
            }

            Transport = GetTransport(context);

            if (Transport == null)
            {
                await FailResponse(context.Response, String.Format(CultureInfo.CurrentCulture, Resources.Error_ProtocolErrorUnknownTransport)).PreserveCulture();

                return;
            }

            string connectionToken = context.Request.Query["connectionToken"];

            // If there's no connection id then this is a bad request
            if (String.IsNullOrEmpty(connectionToken))
            {
                await FailResponse(context.Response, String.Format(CultureInfo.CurrentCulture, Resources.Error_ProtocolErrorMissingConnectionToken)).PreserveCulture();

                return;
            }

            string connectionId;
            string message;
            int    statusCode;

            if (!TryGetConnectionId(context, connectionToken, out connectionId, out message, out statusCode))
            {
                await FailResponse(context.Response, message, statusCode).PreserveCulture();

                return;
            }

            // Set the transport's connection id to the unprotected one
            Transport.ConnectionId = connectionId;

            // Get the user id from the request
            string userId = UserIdProvider.GetUserId(context.Request);

            // Get the groups oken from the request
            string groupsToken = await Transport.GetGroupsToken().PreserveCulture();

            IList <string> signals = GetSignals(userId, connectionId);
            IList <string> groups  = AppendGroupPrefixes(context, connectionId, groupsToken);

            Connection connection = CreateConnection(connectionId, signals, groups);

            Connection = connection;
            string groupName = PrefixHelper.GetPersistentConnectionGroupName(DefaultSignalRaw);

            Groups = new GroupManager(connection, groupName);

            // We handle /start requests after the PersistentConnection has been initialized,
            // because ProcessStartRequest calls OnConnected.
            if (IsStartRequest(context.Request))
            {
                await ProcessStartRequest(context, connectionId).PreserveCulture();

                return;
            }

            Transport.Connected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnConnected(context.Request, connectionId).OrEmpty()));
            };

            Transport.Reconnected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnReconnected(context.Request, connectionId).OrEmpty()));
            };

            Transport.Received = data =>
            {
                Counters.ConnectionMessagesSentTotal.Increment();
                Counters.ConnectionMessagesSentPerSec.Increment();
                return(TaskAsyncHelper.FromMethod(() => OnReceived(context.Request, connectionId, data).OrEmpty()));
            };

            Transport.Disconnected = async clean =>
            {
                await OnDisconnected(context.Request, connectionId, stopCalled : clean).OrEmpty().PreserveCulture();

                if (clean)
                {
                    // Only call the old OnDisconnected method for disconnects we know
                    // have *not* been caused by clients switching servers.
                    await OnDisconnected(context.Request, connectionId).OrEmpty().PreserveCulture();
                }
            };

            await Transport.ProcessRequest(connection).OrEmpty().Catch(Counters.ErrorsAllTotal, Counters.ErrorsAllPerSec).PreserveCulture();
        }
Exemplo n.º 4
0
        /// <summary>
        /// Handles all requests for <see cref="PersistentConnection"/>s.
        /// </summary>
        /// <param name="context">The <see cref="HostContext"/> for the current request.</param>
        /// <returns>A <see cref="Task"/> that completes when the <see cref="PersistentConnection"/> pipeline is complete.</returns>
        /// <exception cref="T:System.InvalidOperationException">
        /// Thrown if connection wasn't initialized.
        /// Thrown if the transport wasn't specified.
        /// Thrown if the connection id wasn't specified.
        /// </exception>
        public virtual Task ProcessRequest(HostContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (!_initialized)
            {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.Error_ConnectionNotInitialized));
            }

            if (IsNegotiationRequest(context.Request))
            {
                return(ProcessNegotiationRequest(context));
            }
            else if (IsPingRequest(context.Request))
            {
                return(ProcessPingRequest(context));
            }

            Transport = GetTransport(context);

            if (Transport == null)
            {
                return(FailResponse(context.Response, String.Format(CultureInfo.CurrentCulture, Resources.Error_ProtocolErrorUnknownTransport)));
            }

            string connectionToken = context.Request.QueryString["connectionToken"];

            // If there's no connection id then this is a bad request
            if (String.IsNullOrEmpty(connectionToken))
            {
                return(FailResponse(context.Response, String.Format(CultureInfo.CurrentCulture, Resources.Error_ProtocolErrorMissingConnectionToken)));
            }

            string connectionId;
            string message;
            int    statusCode;

            if (!TryGetConnectionId(context, connectionToken, out connectionId, out message, out statusCode))
            {
                return(FailResponse(context.Response, message, statusCode));
            }

            // Set the transport's connection id to the unprotected one
            Transport.ConnectionId = connectionId;

            IList <string> signals = GetSignals(connectionId);
            IList <string> groups  = AppendGroupPrefixes(context, connectionId);

            Connection connection = CreateConnection(connectionId, signals, groups);

            Connection = connection;
            string groupName = PrefixHelper.GetPersistentConnectionGroupName(DefaultSignalRaw);

            Groups = new GroupManager(connection, groupName);

            Transport.TransportConnected = () =>
            {
                var command = new ServerCommand
                {
                    ServerCommandType = ServerCommandType.RemoveConnection,
                    Value             = connectionId
                };

                return(_serverMessageHandler.SendCommand(command));
            };

            Transport.Connected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnConnected(context.Request, connectionId).OrEmpty()));
            };

            Transport.Reconnected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnReconnected(context.Request, connectionId).OrEmpty()));
            };

            Transport.Received = data =>
            {
                Counters.ConnectionMessagesSentTotal.Increment();
                Counters.ConnectionMessagesSentPerSec.Increment();
                return(TaskAsyncHelper.FromMethod(() => OnReceived(context.Request, connectionId, data).OrEmpty()));
            };

            Transport.Disconnected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnDisconnected(context.Request, connectionId).OrEmpty()));
            };

            return(Transport.ProcessRequest(connection).OrEmpty().Catch(Counters.ErrorsAllTotal, Counters.ErrorsAllPerSec));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Handles all requests for <see cref="PersistentConnection"/>s.
        /// </summary>
        /// <param name="context">The <see cref="HostContext"/> for the current request.</param>
        /// <returns>A <see cref="Task"/> that completes when the <see cref="PersistentConnection"/> pipeline is complete.</returns>
        /// <exception cref="T:System.InvalidOperationException">
        /// Thrown if connection wasn't initialized.
        /// Thrown if the transport wasn't specified.
        /// Thrown if the connection id wasn't specified.
        /// </exception>
        public virtual Task ProcessRequestAsync(HostContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (!_initialized)
            {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.Error_ConnectionNotInitialized));
            }

            if (IsNegotiationRequest(context.Request))
            {
                return(ProcessNegotiationRequest(context));
            }

            Transport = GetTransport(context);

            if (Transport == null)
            {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.Error_ProtocolErrorUnknownTransport));
            }

            string connectionId = Transport.ConnectionId;

            // If there's no connection id then this is a bad request
            if (String.IsNullOrEmpty(connectionId))
            {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.Error_ProtocolErrorMissingConnectionId));
            }

            IEnumerable <string> signals = GetSignals(connectionId);
            IEnumerable <string> groups  = OnRejoiningGroups(context.Request, Transport.Groups, connectionId);

            Connection connection = CreateConnection(connectionId, signals, groups);

            Connection = connection;
            Groups     = new GroupManager(connection, DefaultSignal);

            Transport.TransportConnected = () =>
            {
                var command = new ServerCommand
                {
                    ServerCommandType = ServerCommandType.RemoveConnection,
                    Value             = connectionId
                };

                return(_serverMessageHandler.SendCommand(command));
            };

            Transport.Connected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnConnectedAsync(context.Request, connectionId).OrEmpty()));
            };

            Transport.Reconnected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnReconnectedAsync(context.Request, connectionId).OrEmpty()));
            };

            Transport.Received = data =>
            {
                Counters.ConnectionMessagesSentTotal.Increment();
                Counters.ConnectionMessagesSentPerSec.Increment();
                return(TaskAsyncHelper.FromMethod(() => OnReceivedAsync(context.Request, connectionId, data).OrEmpty()));
            };

            Transport.Disconnected = () =>
            {
                return(TaskAsyncHelper.FromMethod(() => OnDisconnectAsync(context.Request, connectionId).OrEmpty()));
            };

            return(Transport.ProcessRequest(connection).OrEmpty().Catch(Counters.ErrorsAllTotal, Counters.ErrorsAllPerSec));
        }