You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
7.0 KiB
C#

using System.Text;
using EmbedIO;
using EmbedIO.Routing;
using EmbedIO.WebApi;
using Kyubey.Database;
using Kyubey.Interop;
namespace Kyubey;
public class ServiceController : WebApiController
{
[Route(HttpVerbs.Get, "/GameEntry")]
public async Task GameEntry()
{
var maybeUsername = Request.QueryString.Get("id");
var maybePassword = Request.QueryString.Get("pass");
var maybeVersion = Request.QueryString.Get("ver");
if (maybeUsername is not { } username ||
maybePassword is not { } password ||
maybeVersion is not "1.32")
{
throw HttpException.BadRequest();
}
var hashedPass = Utils.ComputeHash(password);
var loginUser = JewelDbContext.Users.FindOne(e => e.Username == username && e.Password == hashedPass);
var response = loginUser is not null ? "0" : "1";
var buf = Encoding.ASCII.GetBytes(response);
Response.ContentType = "text/plain";
Response.ContentEncoding = Encoding.ASCII;
Response.ContentLength64 = buf.Length;
await Response.OutputStream.WriteAsync(buf, 0, buf.Length);
}
[Route(HttpVerbs.Get, "/GetName")]
public async Task GetName()
{
var maybeId = Request.QueryString.Get("id");
if (maybeId is not { } id)
{
throw HttpException.BadRequest();
}
var rankingUser = JewelDbContext.Users.FindOne(e => e.Username == id);
if (rankingUser is null) throw HttpException.NotFound("No such userid");
var response = rankingUser.RankingName;
var buf = Encoding.ASCII.GetBytes(response);
Response.ContentType = "text/plain";
Response.ContentEncoding = Encoding.ASCII;
Response.ContentLength64 = buf.Length;
await Response.OutputStream.WriteAsync(buf, 0, buf.Length);
}
[Route(HttpVerbs.Get, "/GetMessage")]
public async Task GetMessage()
{
var responses = new[]
{
"jewelry master lives, but why",
"did you know this game sends your password in cleartext? it's hashed server-side though!",
"this is not an entirely serious project",
"powered by IDA - The Interactive Disassembler",
$"powered by Microsoft .NET version {Environment.Version}",
"powered by anime music",
"greetz 2 mihara, your EULA can't stop me",
"did you know i can make this text say anything i want",
"i wonder how many of these scrolling messages there are"
};
var responseIdx = Random.Shared.Next(responses.Length);
var response = $"the server says: {responses[responseIdx]}";
var buf = Encoding.ASCII.GetBytes(response);
Response.ContentType = "text/plain";
Response.ContentEncoding = Encoding.ASCII;
Response.ContentLength64 = buf.Length;
await Response.OutputStream.WriteAsync(buf, 0, buf.Length);
}
[Route(HttpVerbs.Get, "/GetRanking")]
public async Task GetRanking()
{
// view = -1 means top 10, 0 and above mean pages in the global ranking
var view = int.Parse(Request.QueryString.Get("view")!);
var mode = (JewelryMode)int.Parse(Request.QueryString.Get("mode")!);
var userId = Request.QueryString.Get("id");
var response = "";
if (userId is not null && view == -1 || userId is null) // ?????? this game makes no sense dude
{
var factor = view == -1 ? 0 : view;
if (factor > 0 && JewelDbContext.Scores.Count() < 11)
{
response = "";
}
else
{
var globalRanking = JewelDbContext.Scores
.Find(e => e.GameMode == mode)
.OrderByDescending(e => e.Points)
.Skip(factor*view)
.Take(10)
.ToList();
if (globalRanking.Any())
{
response = $"{factor}\n";
}
foreach (var score in globalRanking) response += score.ToString();
}
} else // personal ranking
{
var personalRanking = JewelDbContext.Scores
.Find(e => e.User.Username == userId && e.GameMode == mode)
.OrderByDescending(e => e.Points)
.Take(10)
.ToList();
if (personalRanking.Any())
{
response = "0\n";
}
foreach (var score in personalRanking) response += score.ToString();
}
var buf = Encoding.ASCII.GetBytes(response);
Response.ContentType = "text/plain";
Response.ContentEncoding = Encoding.ASCII;
Response.ContentLength64 = buf.Length;
await Response.OutputStream.WriteAsync(buf, 0, buf.Length);
}
[Route(HttpVerbs.Post, "/ScoreEntry")]
public async Task ScoreEntry()
{
var id = Request.QueryString.Get("id")!;
var mode = (JewelryMode)int.Parse(Request.QueryString.Get("mode")!);
var score = uint.Parse(Request.QueryString.Get("score")!);
var jewel = uint.Parse(Request.QueryString.Get("jewel")!);
var rank = int.Parse(Request.QueryString.Get("class")!); // probably title
var time = uint.Parse(Request.QueryString.Get("time")!);
var level = uint.Parse(Request.QueryString.Get("level")!);
var maybeUser = JewelDbContext.Users.FindOne(e => e.Username == id);
if (maybeUser is not {} user)
{
throw HttpException.NotFound("No such userid");
}
// TODO: add compression to replay data
var rawReplay = await HttpContext.GetRequestBodyAsByteArrayAsync();
var replay = Convert.ToBase64String(rawReplay);
var scoreRecord = new Score()
{
Id = Utils.GenerateCheapGuid(),
User = user,
GameMode = mode,
Points = score,
Class = rank,
Time = time,
Jewels = jewel,
Level = level,
Replay = replay,
Timestamp = DateTime.Now
};
JewelDbContext.Scores.Insert(scoreRecord);
JewelDbContext.Scores.EnsureIndex(e => e.Points);
Response.ContentType = "text/plain";
Response.ContentEncoding = Encoding.ASCII;
}
[Route(HttpVerbs.Get, "/GetReplay")]
public async Task GetReplay()
{
Response.ContentType = "application/octet-stream";
var replayId = Request.QueryString.Get("id")!;
var score = JewelDbContext.Scores.FindOne(e => e.Id == replayId);
if (score is null)
{
throw HttpException.NotFound("No such replay");
}
// deconvert the replay
var replayBytes = Convert.FromBase64String(score.Replay);
// fire it down the byte hole
await Response.OutputStream.WriteAsync(replayBytes, 0, replayBytes.Length);
}
}