public void Publish <T>(String DocumentId, T Payload, ChangeType Type = ChangeType.CHANGE) { var interested = _subscriptions.Where(x => x.DocumentId == DocumentId && x.Document == typeof(T).FullName); if (Type == ChangeType.NEW) { var interestedNew = _subscriptions.Where(x => x.Document == typeof(T).FullName && x.DocumentId.IsNullOrEmpty()); foreach (var sub in interestedNew) { Manage <T>(sub.CacheKey, DocumentId, sub.SubscriptionId, sub.Session); } interested = interested.Concat(interestedNew); } interested = interested.Distinct(x => x.SubscriptionId); // Delete entries from cache (new data == old data stale) _cache.RemoveAll(interested.Select(x => x.CacheKey).Distinct()); foreach (var sub in interested) { _sse.NotifySession(sub.Session, "forte.Update", new Responses.Update <T> { Payload = Payload, Type = Type, //Etag = ETag, SubscriptionId = sub.SubscriptionId }); } }
public async Task Flush() { // Copy and empty the bag var updates = _updates.Values.ToList(); _updates.Clear(); var notifies = new Dictionary <String, IList <Responses.Update> >(); foreach (var doc in updates) { var interested = await RetrieveInterested(doc.Document, doc.DocumentId); foreach (var interest in interested.Distinct(x => new { x.Session, x.SubscriptionId })) { if (!notifies.ContainsKey(interest.Session)) { notifies[interest.Session] = new List <Responses.Update>(); } notifies[interest.Session].Add(new Responses.Update { Payload = doc.Payload, Etag = doc.Etag, Stamp = doc.Stamp, SubscriptionId = interest.SubscriptionId, Type = doc.Type }); } // Delete entries from cache (new data == old data stale) var keys = interested.Select(x => x.CacheKey).Distinct(); if (keys.Count() != 0) { _cache.RemoveAll(keys.ToArray()); } } foreach (var job in notifies) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Notifying session {0} of {1} values", job.Key, job.Value.Count); } _sse.NotifySession(job.Key, "Demo.Update", job.Value.ToArray()); } await _storage.Clean(); }
public void Publish(Guid QueryId, Int32 Version, Object Payload) { IDictionary <String, Listener> listeners; if (!_subscriptions.TryGetValue(QueryId, out listeners)) { return; } foreach (var listener in listeners) { if (listener.Value.Timeout < DateTime.UtcNow) { RemoveTracked(listener.Key, QueryId); return; } _sse.NotifySession(listener.Key, new { Version = Version, Payload = Payload }); } }
public static void NotifySession(this IServerEvents server, string sspid, object message, string channel = null) { server.NotifySession(sspid, Selector.Id(message.GetType()), message, channel); }
public async Task Flush() { // Copy and empty the bag var updates = _updates.Values.ToList(); _updates.Clear(); var notifies = new Dictionary<string, IList<Responses.Update>>(); foreach (var doc in updates.GroupBy(x => x.Document)) { var interested = await _storage.Retreive(x => x.Document == doc.Key).ConfigureAwait(false); var indirect = interested.Where(x => x.DocumentId == ""); foreach (var indv in doc) { var all = interested.Where(x => x.DocumentId == indv.DocumentId).ToList(); // Don't foreach over all the indirect because indirect contains all the open list subscriptions // and the doc we are looking at might already be subscribed to which would be weeded out by the Union above foreach (var paged in indirect) { if (all.Any(x => x.Session == paged.Session && x.SubscriptionId == paged.SubscriptionId)) continue; // Deserialize the original query that generated the list of data // Run the dto through the query to test if the conditions are satisfied // If so, add a new subscription and notify client of new element on list // Todo: using a bit of reflection to call open generic IChange.Satisfied can replace once IChange is implemented more like FluentValidation than a generic interface see PUL-5 var queryType = Type.GetType(paged.SerializedQueryType); var query = JsonConvert.DeserializeObject(paged.SerializedQuery, queryType); var pagedType = queryType.GetInterfaces().Single(x => x.IsInterface && x.GetInterfaces().Contains(typeof(IPaged))); var changeType = typeof(IChange<,>).MakeGenericType(indv.Payload.GetType(), pagedType); var satisfiedChange = changeType.GetMethod("Satisfied", BindingFlags.Public | BindingFlags.Instance); var change = _container.TryGetInstance(changeType); if (query == null || change == null || !(bool)satisfiedChange.Invoke(change, new[] { indv.Payload, query })) continue; var subscription = new Subscription { SerializedQuery = paged.SerializedQuery, SubscriptionId = paged.SubscriptionId, Document = indv.Document, DocumentId = indv.DocumentId, CacheKey = paged.CacheKey, Expires = paged.Expires, Session = paged.Session, Type = paged.Type }; all.Add(subscription); await _storage.Store(subscription).ConfigureAwait(false); } foreach (var interest in all) { var key = interest.Session; if (!notifies.ContainsKey(key)) notifies[key] = new List<Responses.Update>(); notifies[key].Add(new Responses.Update { Payload = indv.Payload, Etag = indv.Etag, Stamp = indv.Stamp, SubscriptionId = interest.SubscriptionId, Type = indv.Type }); } } // Delete entries from cache (new data == old data stale) var keys = interested.Select(x => x.CacheKey).Distinct(); if (keys.Count() != 0) _cache.RemoveAll(keys.ToArray()); } foreach (var job in notifies) { if (Logger.IsDebugEnabled) Logger.DebugFormat("Notifying session {0} of {1} values", job.Key, job.Value.Count); _sse.NotifySession(job.Key, "Demo.Update", job.Value.ToArray()); } await _storage.Clean().ConfigureAwait(false); }