Ejemplo n.º 1
0
        static void Main(string[] args)
        {
            using var newbieContext = new NewbieContext();
            // This works, w/o any Update() statements.
            //var first = newbieContext.UpdateSchedules.First();
            //first.ActiveIndex++;
            //newbieContext.SaveChanges();
            using var newbieContext2 = new NewbieContext();
            var strategy1 = newbieContext.Database.CreateExecutionStrategy();

            strategy1.Execute(() =>
            {
                using var transaction1 = newbieContext.Database.BeginTransaction(IsolationLevel.ReadCommitted);
                using var transaction2 = newbieContext2.Database.BeginTransaction(IsolationLevel.ReadCommitted);
                var first           = newbieContext.UpdateSchedules.First();
                first.ActiveIndex  += 10;
                var first2          = newbieContext2.UpdateSchedules.First();
                first2.ActiveIndex += 20;
                newbieContext2.SaveChanges();
                Task.Run(() =>
                {
                    Task.Delay(10_000).Wait();
                    transaction2.Commit();
                });
                newbieContext.SaveChanges(); // Throws?
            });
        }
Ejemplo n.º 2
0
        private static async Task <List <UserSnapshot> > GetHistories(List <int> osuIds, Bleatingsheep.Osu.Mode mode)
        {
            using var newbieContext = new NewbieContext();
            var now   = DateTimeOffset.Now;
            var snaps = await newbieContext.UserSnapshots
                        .Where(s => now.Subtract(TimeSpan.FromHours(36)) < s.Date && s.Mode == mode && osuIds.Contains(s.UserId))
                        .ToListAsync().ConfigureAwait(false);

            return(snaps
                   .GroupBy(s => s.UserId)
                   .Select(g => g.OrderBy(s => Utilities.DateUtility.GetError(now - TimeSpan.FromHours(24), s.Date)).First())
                   .ToList());
        }
 private static async Task <IExecutingResult <T> > TryExecuteAsync <T>(Func <NewbieContext, Task <T> > func)
 {
     try
     {
         using (var context = new NewbieContext())
         {
             return(new ExecutingResult <T>(await func(context)));
         }
     }
     catch (Exception e)
     {
         return(new ExecutingResult <T>(e));
     }
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Query user play records.
        /// Parameters must have same number of elements,
        /// and there must not be any duplicate <c>userId</c> and <c>mode</c> combination.
        /// </summary>
        /// <param name="context">Database context to use.</param>
        /// <param name="userIds">List of queried user ids. <c>userIds</c>, <c>modes</c> and <c>startIndecies</c> must have same number of elements.</param>
        /// <param name="modes">List of queried modes. <c>userIds</c>, <c>modes</c> and <c>startIndecies</c> must have same number of elements.</param>
        /// <param name="startIndecies">List of first numbers played. <c>userIds</c>, <c>modes</c> and <c>startIndecies</c> must have same number of elements.</param>
        /// <returns>A list of user play records.</returns>
        public static async Task <IList <UserPlayRecord> > GetUserPlayRecordsAsync(
            NewbieContext context,
            IEnumerable <int> userIds,
            IEnumerable <Mode> modes,
            IEnumerable <int> startIndecies)
        {
            var tracking = context.ChangeTracker.QueryTrackingBehavior;

            context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

            // TODO: Verify that there is no repeating conditions (with same userId and mode).
            // If so, select the minimum of StartNumber.
            var filters = userIds.Zip(modes).Zip(startIndecies, (tuple, start) =>
            {
                var(userId, mode) = tuple;
                return(new PlayRecordQueryTemp
                {
                    UserId = userId,
                    Mode = mode,
                    StartNumber = start,
                });
            });

            var result = await context.Database.CreateExecutionStrategy().ExecuteAsync(async() =>
            {
                using (await context.Database.BeginTransactionAsync(IsolationLevel.ReadCommitted).ConfigureAwait(false))
                {
                    await context.PlayRecordQueryTemps.AddRangeAsync(filters).ConfigureAwait(false);
                    await context.SaveChangesAsync().ConfigureAwait(false);
                    return(await(from r in context.UserPlayRecords
                                 join f in context.PlayRecordQueryTemps on new { r.UserId, r.Mode } equals new { f.UserId, f.Mode }
                                 where r.PlayNumber >= f.StartNumber
                                 select r).ToListAsync().ConfigureAwait(false));
                }
            }).ConfigureAwait(false);

            context.ChangeTracker.QueryTrackingBehavior = tracking;
            return(result);
        }
Ejemplo n.º 5
0
        public async Task ProcessAsync(MessageContext superContext, HttpApiClient api)
        {
            var context      = superContext as GroupMessage;
            var groupMembers = await api.GetGroupMemberListAsync(context.GroupId);

            Logger.Debug($"群 {context.GroupId} 开启今日高光,成员共 {groupMembers.Length} 名。");

            var stopwatch = Stopwatch.StartNew();

            using (var dbContext = new NewbieContext())
            {
                //var bindings = await (from b in dbContext.Bindings
                //                      join mi in groupMembers on b.UserId equals mi.UserId
                //                      select new { Info = mi, Binding = b.OsuId }).ToListAsync();
                ////var history = (from bi in bindings.AsQueryable()
                ////               join ui in motherShip.Userinfo on bi.Binding equals ui.UserId into histories
                ////               select new { bi.Info, bi.Binding, History = histories.OrderByDescending(ui => ui.QueryDate).First() }).ToList();
                //var osuIds = bindings.Select(b => b.Binding).Distinct().ToList();
                var qqs    = groupMembers.Select(mi => mi.UserId).ToList();
                var osuIds = await dbContext.Bindings.Where(bi => qqs.Contains(bi.UserId)).Select(bi => bi.OsuId).Distinct().ToListAsync();

                Logger.Debug($"找到 {osuIds.Count} 个绑定信息,耗时 {stopwatch.ElapsedMilliseconds}ms。");

                Bleatingsheep.Osu.Mode mode = 0;
                if (!string.IsNullOrEmpty(ModeString))
                {
                    try
                    {
                        mode = Bleatingsheep.Osu.ModeExtensions.Parse(ModeString);
                    }
                    catch (FormatException)
                    {
                        // ignore
                    }
                }

                stopwatch = Stopwatch.StartNew();
                List <UserSnapshot> history = await GetHistories(osuIds, mode).ConfigureAwait(false);

                Logger.Debug($"找到 {history.Count} 个历史信息,耗时 {stopwatch.ElapsedMilliseconds}ms。");

                // Using ConcurrentBag is enough here. ConcurrentDictionary is unnecessary and costly.
                var nowInfos = new ConcurrentDictionary <int, UserInfo>(10, history.Count);
                var fails    = new BlockingCollection <int>();
                stopwatch = Stopwatch.StartNew();
                var fetchIds          = history.Select(h => (int)h.UserId).Distinct().ToList();
                int completes         = 0;
                var cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(1)).Token;
                var tasks             = fetchIds.Concat(fails.GetConsumingEnumerable()).Select(async bi =>
                {
                    var(success, userInfo) = await GetCachedUserInfo(bi, (Bleatingsheep.Osu.Mode)mode).ConfigureAwait(false);
                    if (!success)
                    {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            fails.CompleteAdding();
                        }
                        if (!fails.IsAddingCompleted)
                        {
                            try
                            {
                                fails.Add(bi);
                            }
                            catch (InvalidOperationException)
                            {
                            }
                        }
                    }
                    else
                    {
                        Interlocked.Increment(ref completes);
                        if (completes == fetchIds.Count)
                        {
                            fails.CompleteAdding();
                        }
                        if (userInfo != null)
                        {
                            nowInfos[bi] = userInfo;
                        }
                    }
                }).ToArray();
                await Task.WhenAll(tasks).ConfigureAwait(false);

                Logger.Debug($"查询 API 花费 {stopwatch.ElapsedMilliseconds}ms,失败 {fails.Count} 个。");

                var cps = (from his in history
                           join now in nowInfos on his.UserId equals now.Key
                           where his.UserInfo.PlayCount != now.Value.PlayCount
                           orderby now.Value.Performance - his.UserInfo.Performance descending
                           select new { Old = his.UserInfo, New = now.Value, Meta = his }).ToList();

                if (fails.Count > 0)
                {
                    await api.SendGroupMessageAsync(context.GroupId, $"失败了 {fails.Count} 人。");
                }
                if (cps.Count == 0)
                {
                    await api.SendMessageAsync(context.Endpoint, "你群根本没有人屙屎。");

                    return;
                }
                else
                {
                    var increase = cps.Find(cp => cp.Old.Performance != 0 && cp.New.Performance != cp.Old.Performance);
                    var mostPlay = cps.OrderByDescending(cp => cp.New.TotalHits - cp.Old.TotalHits).First();
                    var sb       = new StringBuilder(100);
                    sb.AppendLine("最飞升:");
                    if (increase != null)
                    {
                        // sb.AppendLine($"{increase.New.Name} 增加了 {increase.New.Performance - increase.Old.Performance:#.##} PP。")
                        sb.Append(increase.New.Name).Append(" 增加了 ").AppendFormat("{0:#.##}", increase.New.Performance - increase.Old.Performance).AppendLine(" PP。")
                        // .AppendLine($"({increase.Old.Performance:#.##} -> {increase.New.Performance:#.##})");
                        .Append('(').AppendFormat("{0:#.##}", increase.Old.Performance).Append(" -> ").AppendFormat("{0:#.##}", increase.New.Performance).AppendLine(")");
                    }
                    else
                    {
                        sb.AppendLine("你群没有人飞升。");
                    }
                    sb.AppendLine("最肝:")
                    // .Append($"{mostPlay.New.Name} 打了 {mostPlay.New.TotalHits - mostPlay.Old.TotalHits} 下。");
                    .Append(mostPlay.New.Name).Append(" 打了 ").Append(mostPlay.New.TotalHits - mostPlay.Old.TotalHits).Append(" 下。");


                    await api.SendMessageAsync(context.Endpoint, sb.ToString());
                }
            }
        }
Ejemplo n.º 6
0
 public Recommand(IOsuApiClient osuApiClient, NewbieContext newbieContext)
 {
     _osuApiClient  = osuApiClient;
     _newbieContext = newbieContext;
 }
Ejemplo n.º 7
0
 public QueryHelper(IOsuApiClient osuApi, NewbieContext newbieContext)
 {
     _osuApi        = osuApi;
     _newbieContext = newbieContext;
 }
Ejemplo n.º 8
0
 public Clear(NewbieContext newbieContext)
 {
     _newbieContext = newbieContext;
 }
Ejemplo n.º 9
0
 public MyYearly(IDataProvider dataProvider, IOsuApiClient osuApiClient, NewbieContext newbieContext)
 {
     _dataProvider  = dataProvider;
     _osuApiClient  = osuApiClient;
     _newbieContext = newbieContext;
 }