public async Task SubscribeToLedgerStream() { SubscriptionStream stream = await this.client.Subscribe(new Requests.Subscription.SubscriptionRequest { Streams = new List <string>() { "ledger" } }); int i = 0; while (true) { if (i >= 3) { await this.client.Unsubscribe(); break; } IDictionary <string, object> nextItem = await stream.Next(); string json = nextItem.ToString(); i++; } await this.client.Ping(); }
/// <summary> /// 获取时间轴卡片列表 /// </summary> /// <param name="before">起始位置</param> /// <param name="take">获取数量</param> /// <param name="dbContext"><see cref="KeylolDbContext"/></param> /// <param name="cachedData"><see cref="CachedDataProvider"/></param> /// <returns><see cref="TimelineCardList"/></returns> public static async Task <TimelineCardList> GetCards(int before, int take, [Injected] KeylolDbContext dbContext, [Injected] CachedDataProvider cachedData) { var currentUserId = StateTreeHelper.GetCurrentUserId(); return(await TimelineCardList.CreateAsync(SubscriptionStream.Name(currentUserId), currentUserId, take, false, dbContext, cachedData, before)); }
/// <summary> /// 创建 <see cref="TimelinePage"/> /// </summary> /// <param name="currentUserId">当前登录用户 ID</param> /// <param name="dbContext"><see cref="KeylolDbContext"/></param> /// <param name="cachedData"><see cref="CachedDataProvider"/></param> /// <returns><see cref="TimelinePage"/></returns> public static async Task <TimelinePage> CreateAsync(string currentUserId, KeylolDbContext dbContext, CachedDataProvider cachedData) { return(new TimelinePage { Cards = await TimelineCardList.CreateAsync(SubscriptionStream.Name(currentUserId), currentUserId, 18, false, dbContext, cachedData) }); }
private void MessageReceived(string s, WebSocketClient client) { JObject jResponse = JObject.Parse(s); // if the response does not have an id field, it is not a RippleResponse. // it is most likely a stream from the subscribe API if (jResponse["id"] == null) { if (!jResponse.HasValues) { return; } // if there is no active subscriptionStream // disregard the message if (this.subscriptionStream == null) { return; } this.subscriptionStream.Push(this.ConvertJObjectToDictionary(jResponse)); return; } RippleResponse response = jResponse.ToObject <RippleResponse>(); var taskInfoResult = tasks.TryGetValue(response.Id, out var taskInfo); if (taskInfoResult == false) { throw new Exception("Task not found"); } if (response.Status == "success") { if (taskInfo.Type != typeof(SubscriptionStream)) { if (taskInfo.IsUnsubscribe) { this.subscriptionStream = null; } object deserialized = JsonConvert.DeserializeObject(response.Result.ToString(), taskInfo.Type, serializerSettings); MethodInfo setResult = taskInfo.TaskCompletionResult.GetType().GetMethod("SetResult"); setResult.Invoke(taskInfo.TaskCompletionResult, new[] { deserialized }); } else { TaskCompletionSource <SubscriptionStream> taskCompletionSource = taskInfo.TaskCompletionResult as TaskCompletionSource <SubscriptionStream>; this.subscriptionStream = taskCompletionSource.Task.Result; // since subscriptionStream is not null, MessageReceived will push the first subscription to the SubscriptionStream this.MessageReceived(response.Result.ToString(), client); } if (taskInfo.RemoveUponCompletion) { tasks.TryRemove(response.Id, out taskInfo); } } else if (response.Status == "error") { var setException = taskInfo.TaskCompletionResult.GetType().GetMethod("SetException", new Type[] { typeof(Exception) }, null); RippleException exception = new RippleException(response.Error); setException.Invoke(taskInfo.TaskCompletionResult, new[] { exception }); tasks.TryRemove(response.Id, out taskInfo); } }
protected override void OnStart(string[] args) { _mqChannel.BasicQos(0, 5, false); var consumer = new EventingBasicConsumer(_mqChannel); consumer.Received += async(sender, eventArgs) => { try { using (var streamReader = new StreamReader(new MemoryStream(eventArgs.Body))) using (var dbContext = new KeylolDbContext()) { var serializer = new JsonSerializer(); var requestDto = serializer.Deserialize <PushHubRequestDto>(new JsonTextReader(streamReader)); string entryId; FeedEntryType entryType; List <string> pointsToPush; List <UserToPush> usersToPush = new List <UserToPush>(); var count = 0; switch (requestDto.Type) { case ContentPushType.Article: { var article = await dbContext.Articles.Where(a => a.Id == requestDto.ContentId) .Select(a => new { a.Id, a.AuthorId, a.AttachedPoints, a.TargetPointId }).SingleAsync(); usersToPush.Add(new UserToPush { UserId = article.AuthorId, SubscriberTimelineReason = "author" }); entryId = article.Id; entryType = FeedEntryType.ArticleId; pointsToPush = Helpers.SafeDeserialize <List <string> >(article.AttachedPoints) ?? new List <string>(); pointsToPush.Add(article.TargetPointId); break; } case ContentPushType.Activity: { var activity = await dbContext.Activities.Where(a => a.Id == requestDto.ContentId) .Select(a => new { a.Id, a.AuthorId, a.AttachedPoints, a.TargetPointId }).SingleAsync(); usersToPush.Add(new UserToPush { UserId = activity.AuthorId, SubscriberTimelineReason = "author" }); entryId = activity.Id; entryType = FeedEntryType.ActivityId; pointsToPush = Helpers.SafeDeserialize <List <string> >(activity.AttachedPoints) ?? new List <string>(); pointsToPush.Add(activity.TargetPointId); if (await AddOrUpdateFeedAsync(LatestActivityStream.Name, entryId, entryType, null, dbContext)) { count++; } break; } case ContentPushType.Like: { var like = await dbContext.Likes.FindAsync(requestDto.ContentId); entryId = like.TargetId; pointsToPush = new List <string>(); usersToPush.Add(new UserToPush { UserId = like.OperatorId, UserTimelineReason = "like", SubscriberTimelineReason = $"like:{like.OperatorId}" }); switch (like.TargetType) { case LikeTargetType.Article: entryType = FeedEntryType.ArticleId; break; case LikeTargetType.Activity: entryType = FeedEntryType.ActivityId; break; default: _mqChannel.BasicAck(eventArgs.DeliveryTag, false); return; } break; } default: throw new ArgumentOutOfRangeException(); } foreach (var user in usersToPush) { if (await AddOrUpdateFeedAsync(UserStream.Name(user.UserId), entryId, entryType, user.UserTimelineReason, dbContext)) { count++; } foreach (var subscriberId in await dbContext.Subscriptions .Where(s => s.TargetId == user.UserId && s.TargetType == SubscriptionTargetType.User) .Select(s => s.SubscriberId).ToListAsync()) { if (await AddOrUpdateFeedAsync(SubscriptionStream.Name(subscriberId), entryId, entryType, user.SubscriberTimelineReason, dbContext)) { count++; } } } foreach (var pointId in pointsToPush) { var point = await dbContext.Points.Where(p => p.Id == pointId) .Select(p => new { p.Id }).SingleOrDefaultAsync(); if (point == null) { continue; } if (await AddOrUpdateFeedAsync(PointStream.Name(point.Id), entryId, entryType, null, dbContext)) { count++; } foreach (var subscriberId in await dbContext.Subscriptions .Where(s => s.TargetId == point.Id && s.TargetType == SubscriptionTargetType.Point) .Select(s => s.SubscriberId).ToListAsync()) { if (await AddOrUpdateFeedAsync(SubscriptionStream.Name(subscriberId), entryId, entryType, $"point:{point.Id}", dbContext)) { count++; } } } _mqChannel.BasicAck(eventArgs.DeliveryTag, false); _logger.Info($"{count} feeds pushed. Content: ({requestDto.Type}) {requestDto.ContentId}"); } } catch (Exception e) { _mqChannel.BasicNack(eventArgs.DeliveryTag, false, false); _logger.Fatal("RabbitMQ unhandled callback exception.", e); } }; _mqChannel.BasicConsume(MqClientProvider.PushHubRequestQueue, false, consumer); }
public async Task SubscribeToAccountStream() { /*{ * "engine_result": "tesSUCCESS", * "engine_result_code": 0, * "engine_result_message": "The transaction was applied. Only final in a validated ledger.", * "ledger_hash": "A4A35B9C23EFF806BAFAED1D4F63475E10002E40B0A409718F8507320024C0A3", * "ledger_index": 42577394, * "meta": { * "AffectedNodes": [ * { * "ModifiedNode": { * "FinalFields": { * "Account": "rK7D3QnTrYdkp1fGKKzHFNXZpqN8dUCfaf", * "Balance": "1582570858693", * "Flags": 1179648, * "OwnerCount": 5, * "Sequence": 682 * }, * "LedgerEntryType": "AccountRoot", * "LedgerIndex": "56C6890B573E333E7CF18DFA1DAB581595F14C218FA33068D5379B33AC49BA2B", * "PreviousFields": { * "Balance": "1582470858693" * }, * "PreviousTxnID": "FDDBFDE3091B64F3AEFCE522D4DFE55D67F68F168DFA574118DB7086B982EE4C", * "PreviousTxnLgrSeq": 42575220 * } * }, * { * "ModifiedNode": { * "FinalFields": { * "Account": "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv", * "Balance": "2748465618040", * "Flags": 131072, * "OwnerCount": 0, * "Sequence": 636135 * }, * "LedgerEntryType": "AccountRoot", * "LedgerIndex": "C3B625B296E95A21D7BBBB7E3D343AF423B463B87B5D56EE7F79C8E16A47A6F5", * "PreviousFields": { * "Balance": "2748565678040", * "Sequence": 636134 * }, * "PreviousTxnID": "48F4B2D79D1AE3B26D70DE6D26F4988FD9B4643410BDED41F49BCADB9D850875", * "PreviousTxnLgrSeq": 42577122 * } * } * ], * "TransactionIndex": 0, * "TransactionResult": "tesSUCCESS" * }, * "status": "closed", * "transaction": { * "Account": "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv", * "Amount": "100000000", * "Destination": "rK7D3QnTrYdkp1fGKKzHFNXZpqN8dUCfaf", * "DestinationTag": 153, * "Fee": "60000", * "Flags": 2147483648, * "LastLedgerSequence": 42578393, * "Sequence": 636134, * "SigningPubKey": "03D847C2DBED3ABF0453F71DCD7641989136277218DF516AD49519C9693F32727E", * "TransactionType": "Payment", * "TxnSignature": "3045022100BFE470C6E3284808DEB5FE56097E9AD8EE616E3CE250524AEE3D3FC7811E33160220527FDAEAE5D09B2D949E0DF3A2DF2994A4F2FA43A0D17261C4029703CF885052", * "date": 594087992, * "hash": "5510C05D76FBC5259141222623C45D59F5DB50C46D8222516813A35403F65D97" * }, * "type": "transaction", * "validated": true * } */ const string bitstampHotWallet = "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv"; this.client = new RippleClient(mainNetUrl); await this.client.Connect(); SubscriptionStream stream = await this.client.Subscribe(new Requests.Subscription.SubscriptionRequest { Accounts = new List <string>() { bitstampHotWallet } }); int i = 0; while (true) { if (i >= 3) { await this.client.Unsubscribe(); break; } IDictionary <string, object> nextItem = await stream.Next(); string json = JsonConvert.SerializeObject(nextItem); i++; } await this.client.Ping(); }
private static void AutoSubscribe(string userId) { Task.Run(async() => { using (var dbContext = new KeylolDbContext()) using (var userManager = new KeylolUserManager(dbContext)) { var redis = Global.Container.GetInstance <RedisProvider>(); var cachedData = new CachedDataProvider(dbContext, redis); if (await SteamCrawlerProvider.UpdateUserSteamGameRecordsAsync(userId, dbContext, userManager, redis, cachedData)) { var games = await(from record in dbContext.UserSteamGameRecords where record.UserId == userId join point in dbContext.Points on record.SteamAppId equals point.SteamAppId orderby record.TotalPlayedTime select new { PointId = point.Id, record.LastPlayTime }).ToListAsync(); var gamePointIds = games.Select(g => g.PointId).ToList(); var mostPlayedPointIds = gamePointIds.Take(3).ToList(); var recentPlayedPointIds = games.Where(g => !mostPlayedPointIds.Contains(g.PointId)) .OrderByDescending(g => g.LastPlayTime) .Select(g => g.PointId).Take(3).ToList(); var categoryPointIds = await(from relationship in dbContext.PointRelationships where gamePointIds.Contains(relationship.SourcePointId) && (relationship.Relationship == PointRelationshipType.Tag || relationship.Relationship == PointRelationshipType.Series) group 1 by relationship.TargetPointId into g orderby g.Count() descending select g.Key).Take(3).ToListAsync(); var pointIds = mostPlayedPointIds.Concat(recentPlayedPointIds).Concat(categoryPointIds).ToList(); foreach (var pointId in pointIds) { await cachedData.Subscriptions.AddAsync(userId, pointId, SubscriptionTargetType.Point); } var pointFeedStreams = pointIds.Select(PointStream.Name).ToList(); var feeds = await(from feed in dbContext.Feeds where pointFeedStreams.Contains(feed.StreamName) orderby feed.Id descending group new { feed.Id, feed.StreamName } by new { feed.Entry, feed.EntryType } into g orderby g.Max(f => f.Id) select g).Take(120).ToListAsync(); var subscriptionStream = SubscriptionStream.Name(userId); foreach (var feed in feeds) { var properties = new SubscriptionStream.FeedProperties { Reasons = feed.Select(f => f.StreamName.Split(':')[1]).Distinct() .Select(id => $"point:{id}").ToList() }; dbContext.Feeds.Add(new Models.Feed { StreamName = subscriptionStream, Entry = feed.Key.Entry, EntryType = feed.Key.EntryType, Properties = JsonConvert.SerializeObject(properties) }); } await dbContext.SaveChangesAsync(); } } }); }