public override Task ProcessRequestAsync(IRequest req, IResponse res, string operationName) { var feature = HostContext.GetPlugin <ServerEventsFeature>(); res.ContentType = MimeTypes.ServerSentEvents; res.AddHeader(HttpHeaders.CacheControl, "no-cache"); res.UseBufferedStream = false; res.KeepAlive = true; if (feature.OnInit != null) { feature.OnInit(req); } res.Flush(); var serverEvents = req.TryResolve <IServerEvents>(); var session = req.GetSession(); var userAuthId = session != null ? session.UserAuthId : null; var anonUserId = serverEvents.GetNextSequence("anonUser"); var userId = userAuthId ?? ("-" + anonUserId); var displayName = session.GetSafeDisplayName() ?? "user" + anonUserId; var now = DateTime.UtcNow; var subscriptionId = SessionExtensions.CreateRandomSessionId(); var subscription = new EventSubscription(res) { CreatedAt = now, LastPulseAt = now, Channel = req.QueryString["channel"] ?? EventSubscription.UnknownChannel, SubscriptionId = subscriptionId, UserId = userId, UserName = session != null ? session.UserName : null, DisplayName = displayName, SessionId = req.GetPermanentSessionId(), IsAuthenticated = session != null && session.IsAuthenticated, OnPublish = feature.OnPublish, Meta = { { "userId", userId }, { "displayName", displayName }, { AuthMetadataProvider.ProfileUrlKey, session.GetProfileUrl() ?? AuthMetadataProvider.DefaultNoProfileImgUrl }, } }; if (feature.OnCreated != null) { feature.OnCreated(subscription, req); } var heartbeatUrl = req.ResolveAbsoluteUrl("~/".CombineWith(feature.HeartbeatPath)) .AddQueryParam("id", subscriptionId); var unRegisterUrl = req.ResolveAbsoluteUrl("~/".CombineWith(feature.UnRegisterPath)) .AddQueryParam("id", subscriptionId); var privateArgs = new Dictionary <string, string>(subscription.Meta) { { "id", subscriptionId }, { "unRegisterUrl", unRegisterUrl }, { "heartbeatUrl", heartbeatUrl }, { "heartbeatIntervalMs", ((long)feature.HeartbeatInterval.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) } }; if (feature.OnConnect != null) { feature.OnConnect(subscription, privateArgs); } serverEvents.Register(subscription, privateArgs); var tcs = new TaskCompletionSource <bool>(); subscription.OnDispose = _ => { try { res.EndHttpHandlerRequest(skipHeaders: true); } catch { } tcs.SetResult(true); }; return(tcs.Task); }
public override Task ProcessRequestAsync(IRequest req, IResponse res, string operationName) { if (HostContext.ApplyCustomHandlerRequestFilters(req, res)) { return(EmptyTask); } var feature = HostContext.GetPlugin <ServerEventsFeature>(); var session = req.GetSession(); if (feature.LimitToAuthenticatedUsers && !session.IsAuthenticated) { session.ReturnFailedAuthentication(req); return(EmptyTask); } res.ContentType = MimeTypes.ServerSentEvents; res.AddHeader(HttpHeaders.CacheControl, "no-cache"); res.ApplyGlobalResponseHeaders(); res.UseBufferedStream = false; res.KeepAlive = true; if (feature.OnInit != null) { feature.OnInit(req); } res.Flush(); var serverEvents = req.TryResolve <IServerEvents>(); var userAuthId = session != null ? session.UserAuthId : null; var anonUserId = serverEvents.GetNextSequence("anonUser"); var userId = userAuthId ?? ("-" + anonUserId); var displayName = session.GetSafeDisplayName() ?? "user" + anonUserId; var now = DateTime.UtcNow; var subscriptionId = SessionExtensions.CreateRandomSessionId(); //Handle both ?channel=A,B,C or ?channels=A,B,C var channels = new List <string>(); var channel = req.QueryString["channel"]; if (!string.IsNullOrEmpty(channel)) { channels.AddRange(channel.Split(',')); } channel = req.QueryString["channels"]; if (!string.IsNullOrEmpty(channel)) { channels.AddRange(channel.Split(',')); } if (channels.Count == 0) { channels = EventSubscription.UnknownChannel.ToList(); } var subscription = new EventSubscription(res) { CreatedAt = now, LastPulseAt = now, Channels = channels.ToArray(), SubscriptionId = subscriptionId, UserId = userId, UserName = session != null ? session.UserName : null, DisplayName = displayName, SessionId = req.GetPermanentSessionId(), IsAuthenticated = session != null && session.IsAuthenticated, UserAddress = req.UserHostAddress, OnPublish = feature.OnPublish, Meta = { { "userId", userId }, { "displayName", displayName }, { "channels", string.Join(",", channels) }, { AuthMetadataProvider.ProfileUrlKey, session.GetProfileUrl() ?? AuthMetadataProvider.DefaultNoProfileImgUrl }, } }; if (feature.OnCreated != null) { feature.OnCreated(subscription, req); } if (req.Response.IsClosed) { return(EmptyTask); //Allow short-circuiting in OnCreated callback } var heartbeatUrl = req.ResolveAbsoluteUrl("~/".CombineWith(feature.HeartbeatPath)) .AddQueryParam("id", subscriptionId); var unRegisterUrl = req.ResolveAbsoluteUrl("~/".CombineWith(feature.UnRegisterPath)) .AddQueryParam("id", subscriptionId); subscription.ConnectArgs = new Dictionary <string, string>(subscription.Meta) { { "id", subscriptionId }, { "unRegisterUrl", unRegisterUrl }, { "heartbeatUrl", heartbeatUrl }, { "heartbeatIntervalMs", ((long)feature.HeartbeatInterval.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) }, { "idleTimeoutMs", ((long)feature.IdleTimeout.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) } }; if (feature.OnConnect != null) { feature.OnConnect(subscription, subscription.ConnectArgs); } serverEvents.Register(subscription, subscription.ConnectArgs); var tcs = new TaskCompletionSource <bool>(); subscription.OnDispose = _ => { try { res.EndHttpHandlerRequest(skipHeaders: true); } catch { } tcs.SetResult(true); }; return(tcs.Task); }