예제 #1
0
        public IActionResult CheckUpdates(
            [FromQuery] string action,
            [FromQuery(Name = "stream")] string qstream,
            [FromQuery] ulong time,
            [FromServices] Cache cache)
        {
            if (cache.TryGet("sora:updater:" + action + qstream, out string answer))
            {
                return(Ok(answer));
            }

            var request = (HttpWebRequest)WebRequest.Create(
                $"https://1.1.1.1/web/check-updates.php?action={action}&stream={qstream}&time={time}"
                );

            request.AutomaticDecompression = DecompressionMethods.GZip;
            request.Host      = "osu.ppy.sh";
            request.UserAgent = "osu";

            using var response = (HttpWebResponse)request.GetResponse();
            using var stream   = response.GetResponseStream();
            using var reader   = new StreamReader(stream ?? throw new Exception("Request Failed!"));

            var result = reader.ReadToEnd();

            cache.Set("sora:updater:" + action + qstream, result, TimeSpan.FromDays(1));
            return(Ok(result));
        }
예제 #2
0
        public async Task OnLoginRequest(BanchoLoginRequestArgs args)
        {
            try
            {
                var sw = new Stopwatch();
                sw.Start();

                var loginData = LoginParser.ParseLogin(args.Reader);
                if (loginData == null)
                {
                    Exception(args.Writer);
                    return;
                }

                var cacheKey = $"sora:user:{loginData.GetHashCode()}";

                if (!_cache.TryGet(cacheKey, out Presence presence))
                {
                    var dbUser = await DbUser.GetDbUser(_ctx, loginData.Username);

                    if (dbUser == null)
                    {
                        LoginFailed(args.Writer);
                        return;
                    }

                    if (!dbUser.IsPassword(loginData.Password))
                    {
                        _logger.Log(LogLevel.Warning, $"{LCOL.RED}{dbUser.UserName} " +
                                    $"{LCOL.PURPLE}({dbUser.Id}) " +
                                    $"{LCOL.RED}Failed {LCOL.WHITE}to Login!");
                        LoginFailed(args.Writer);
                        return;
                    }

                    if (args.IpAddress != "127.0.0.1" && args.IpAddress != "0.0.0.0")
                    {
                        try
                        {
                            var data = Localisation.GetData(args.IpAddress);

                            args.Pr.Info.Longitude = data.Location.Longitude ?? 0;
                            args.Pr.Info.Latitude  = data.Location.Latitude ?? 0;
                            args.Pr.Info.CountryId = Localisation.StringToCountryId(data.Country.IsoCode);
                        }
                        catch
                        {
                            // Ignored.. doesn't matter too much
                        }
                    }

                    args.Pr.User = dbUser;

                    args.Pr.Info.TimeZone = (byte)loginData.Timezone;

                    var lb = await DbLeaderboard.GetLeaderboardAsync(_ctx, dbUser);

                    args.Pr["LB"] = lb;

                    args.Pr.Stats.TotalScore        = lb.TotalScoreOsu;
                    args.Pr.Stats.RankedScore       = lb.RankedScoreOsu;
                    args.Pr.Stats.PerformancePoints = (ushort)lb.PerformancePointsOsu;
                    args.Pr.Stats.PlayCount         = (uint)lb.PlayCountOsu;
                    args.Pr.Stats.Accuracy          = (float)lb.GetAccuracy(_ctx, PlayMode.Osu);
                    args.Pr.Stats.Position          = lb.GetPosition(_ctx, PlayMode.Osu);

                    //args.pr["BLOCK_NON_FRIENDS_DM"] = loginData.BlockNonFriendDMs;

                    _cache.Set(cacheKey, args.Pr, TimeSpan.FromMinutes(30));
                }
                else
                {
                    var t = args.Pr.Token;
                    args.Pr       = presence;
                    args.Pr.Token = t;
                }

                if (_pcs.TryGet(args.Pr.User.Id, out var oldPresence))
                {
                    oldPresence.ActiveMatch?.Leave(args.Pr);
                    oldPresence.Spectator?.Leave(args.Pr);
                    _pcs.Leave(oldPresence);
                }

                _pcs.Join(args.Pr);

                Success(args.Writer, args.Pr.User.Id);

                args.Pr.Push(new ProtocolNegotiation());
                args.Pr.Push(new UserPresence(args.Pr));

                args.Pr.Push(new HandleUpdate(args.Pr));
                args.Pr.Info.ClientPermission = LoginPermissions.User;

                if (args.Pr.User.Permissions == Permission.GROUP_DONATOR)
                {
                    args.Pr.Info.ClientPermission |= LoginPermissions.Supporter;
                }
                if (args.Pr.User.Permissions == Permission.GROUP_ADMIN)
                {
                    args.Pr.Info.ClientPermission |=
                        LoginPermissions.BAT | LoginPermissions.Administrator | LoginPermissions.Moderator;
                }
                if (args.Pr.User.Permissions == Permission.GROUP_DEVELOPER)
                {
                    args.Pr.Info.ClientPermission |= LoginPermissions.Developer;
                }

                if (!args.Pr.User.Permissions.HasPermission(Permission.GROUP_DONATOR))
                {
                    if (_cfg.Server.FreeDirect)
                    {
                        args.Pr.Push(new LoginPermission(LoginPermissions.User | LoginPermissions.Supporter |
                                                         args.Pr.Info.ClientPermission));
                    }
                }
                else
                {
                    args.Pr.Push(new LoginPermission(args.Pr.Info.ClientPermission));
                }

                args.Pr.Push(new FriendsList(DbFriend.GetFriends(_ctx, args.Pr.User.Id).ToList()));
                args.Pr.Push(new PresenceBundle(_pcs.GetUserIds(args.Pr).ToList()));

                foreach (var chanAuto in _cs.ChannelsAutoJoin)
                {
                    if ((chanAuto.Status & ChannelStatus.AdminOnly) != 0 &&
                        args.Pr.User.Permissions == Permission.ADMIN_CHANNEL)
                    {
                        args.Pr.Push(new ChannelAvailableAutojoin(chanAuto));
                    }
                    else if ((chanAuto.Status & ChannelStatus.AdminOnly) == 0)
                    {
                        args.Pr.Push(new ChannelAvailableAutojoin(chanAuto));
                    }

                    args.Pr.Push(new ChannelJoinSuccess(chanAuto));
                    chanAuto.Join(args.Pr);
                }

                foreach (var channel in _cs.Channels)
                {
                    if ((channel.Status & ChannelStatus.AdminOnly) != 0 &&
                        args.Pr.User.Permissions == Permission.ADMIN_CHANNEL)
                    {
                        args.Pr.Push(new ChannelAvailable(channel));
                    }
                    else if ((channel.Status & ChannelStatus.AdminOnly) == 0)
                    {
                        args.Pr.Push(new ChannelAvailable(channel));
                    }
                }

                _pcs.Push(new PresenceSingle(args.Pr.User.Id));
                _pcs.Join(args.Pr);

                args.Pr.WritePackets(args.Writer.BaseStream);

                sw.Stop();
                _logger.Log(LogLevel.Debug, "Login Time:\nMS: ", sw.Elapsed.TotalMilliseconds);

                _logger.Log(LogLevel.Information,
                            $"{LCOL.RED}{args.Pr.User.UserName} {LCOL.PURPLE}( {args.Pr.User.Id} ) {LCOL.WHITE}has logged in!"
                            );

                args.Pr["LAST_PONG"] = DateTime.Now;
            }
            catch (Exception ex)
            {
                Logger.Err(ex);
                Exception(args.Writer);
            }
        }
예제 #3
0
        public async Task <IActionResult> GetScoreResult(
            [FromQuery(Name = "v")] ScoreboardType type,
            [FromQuery(Name = "c")] string fileMd5,
            [FromQuery(Name = "f")] string f,
            [FromQuery(Name = "m")] PlayMode playMode,
            [FromQuery(Name = "i")] int i,
            [FromQuery(Name = "mods")] Mod mods,
            [FromQuery(Name = "us")] string us,
            [FromQuery(Name = "ha")] string pa,
            [FromServices] IServiceProvider serviceProvider,
            [FromServices] SoraDbContext ctx,
            [FromServices] DbContextPool <SoraDbContext> ctxPool,
            [FromServices] Pisstaube pisstaube,
            [FromServices] Cache cache)
        {
            try
            {
                var dbUser = await DbUser.GetDbUser(ctx, us);

                if (dbUser?.IsPassword(pa) != true)
                {
                    return(Ok("error: pass"));
                }

                var cacheHash =
                    Hex.ToHex(
                        Crypto.GetMd5(
                            $"{fileMd5}{playMode}{mods}{type}{dbUser.Id}{dbUser.UserName}"
                            )
                        );

                if (cache.TryGet($"sora:Scoreboards:{cacheHash}", out string cachedData))
                {
                    return(Ok(cachedData));
                }

                var scores = DbScore.GetScores(ctx, fileMd5, dbUser, playMode,
                                               type == ScoreboardType.Friends,
                                               type == ScoreboardType.Country,
                                               type == ScoreboardType.Mods,
                                               mods);

                BeatmapSet set      = null;
                DbScore    ownScore = null;

                var beatmap = DbBeatmap.GetBeatmap(ctx, fileMd5);
                if (beatmap == null)
                {
                    var apiSet = await pisstaube.FetchBeatmapSetAsync(fileMd5);

                    if (apiSet == null)
                    {
                        goto JustContinue;
                    }

                    var beatmaps         = DbBeatmap.FromBeatmapSet(apiSet).ToList();
                    var beatmapChecksums = beatmaps.Select(s => s.FileMd5);
                    var dbBeatmaps       =
                        ctx.Beatmaps.Where(rset => beatmapChecksums.Any(lFileMd5 => rset.FileMd5 == lFileMd5))
                        .ToList();

                    var pool = serviceProvider.GetRequiredService <DbContextPool <SoraDbContext> >();
                    Task.WaitAll(beatmaps.Select(rawBeatmap => Task.Run(async() =>
                    {
                        var context = pool.Rent();

                        try
                        {
                            var dbBeatmap = dbBeatmaps.FirstOrDefault(s => s.FileMd5 == rawBeatmap.FileMd5);

                            if (dbBeatmap != null && (dbBeatmap.Flags & DbBeatmapFlags.RankedFreeze) != 0)
                            {
                                rawBeatmap.RankedStatus = dbBeatmap.RankedStatus;
                                rawBeatmap.Flags        = dbBeatmap.Flags;
                            }

                            context.Beatmaps.AddOrUpdate(rawBeatmap);
                            await context.SaveChangesAsync();
                        }
                        finally
                        {
                            pool.Return(context);
                        }
                    })).ToArray());

                    beatmap = beatmaps.FirstOrDefault(s => s.FileMd5 == fileMd5);
                }

                await foreach (var score in DbScore.GetScores(ctx, fileMd5, dbUser, playMode, false, false, false, mods, true))
                {
                    ownScore = score;
                    break;
                }

                if (beatmap != null)
                {
                    set = new BeatmapSet
                    {
                        SetID        = beatmap.Id,
                        Artist       = beatmap.Artist,
                        Title        = beatmap.Title,
                        RankedStatus = beatmap.RankedStatus,

                        ChildrenBeatmaps = new List <Beatmap>
                        {
                            new Beatmap
                            {
                                FileMD5     = beatmap.FileMd5,
                                DiffName    = beatmap.DiffName,
                                ParentSetID = beatmap.SetId,
                                BeatmapID   = beatmap.Id,
                                Mode        = beatmap.PlayMode,
                            },
                        },
                    }
                }
                ;

JustContinue:
                var sboard = new Scoreboard(set?.ChildrenBeatmaps.FirstOrDefault(bm => bm.FileMD5 == fileMd5),
                                            set, scores, ownScore);

                cache.Set($"sora:Scoreboards:{cacheHash}", cachedData = await sboard.ToOsuString(ctxPool), TimeSpan.FromSeconds(30));
                return(Ok(cachedData));
            }
            catch (Exception ex)
            {
                Logger.Err(ex);
                return(Ok("Failed"));
            }
        }