This commit is contained in:
nito9999
2026-06-12 15:35:10 -04:00
parent f5716c7160
commit 6706b6f478
60 changed files with 48656 additions and 0 deletions
+339
View File
@@ -0,0 +1,339 @@
using Microsoft.AspNetCore.Mvc;
using FemRec2023.Classes;
using FemRec2023.Classes.DBs;
using FemRec2023.Classes.DBs.DBClasses;
using FemRec2023.Auth;
using System.Text.Json;
namespace FemRec2023.Controllers
{
[ApiController]
public class APIController : ControllerBase
{
[HttpGet("/")]
public IActionResult GetNS()
{
string url = ServerConfig.BaseURL;
return Ok(new
{
Accounts = url + "/acc",
API = url,
Auth = url + "/auth",
BugReporting = url,
Cards = url,
CDN = url + "/cdn",
Chat = url,
Clubs = url,
CMS = url,
Commerce = url,
Data = url,
DataCollection = url,
Discovery = url,
Econ = url,
GameLogs = url,
Geo = url,
Images = url + "/imageserver",
Leaderboard = url,
Link = url,
Lists = url,
Matchmaking = url + "/match",
Moderation = url,
Notifications = url + "/noti",
PlatformNotifications = url,
PlayerSettings = url,
RoomComments = url,
Rooms = url + "/roomserver",
Storage = url,
Strings = url,
StringsCDN = url,
Studio = url,
Thorn = url,
Videos = url,
WWW = url
});
}
[HttpGet("api/versioncheck/v4")]
public IActionResult VersionCheck()
{
return Ok(new
{
ValidVersion = 0,
VersionStatus = 0,
UpdateNotificationStage = 0,
IsVersionIslanded = false,
IsCrossPlayDisabled = false
});
}
[HttpGet("api/gameconfigs/v1/all")]
public IActionResult GetGameConfigs()
{
string path = Path.Combine(Program.dataDir, "APIS", "GameConfigs.json");
return System.IO.File.Exists(path) ? Content(System.IO.File.ReadAllText(path), "application/json") : NotFound();
}
[HttpGet("api/config/v1/amplitude")]
public IActionResult GetAmplitude()
{
return Ok(new
{
AmplitudeKey = "cb2fb2ecb9953512c29af5bca58f2b4a",
UseRudderStack = true,
RudderStackKey = "23NiJHIgu3koaGNCZIiuYvIQNCu",
UseStatSig = true,
StatSigKey = "client-SBZkOrjD3r1Cat3f3W8K6sBd11WKlXZXIlCWj6l4Aje",
StatSigEnvironment = 0
});
}
[HttpGet("api/avatar/v1/defaultunlocked")]
public IActionResult GetDefaultUnlocked()
{
return Ok(ServerConfig.Bracket);
}
[HttpGet("api/avatar/v1/defaultbaseavataritems")]
public IActionResult GetDefaultBaseAvatarItems()
{
return Ok(ServerConfig.Bracket);
}
[HttpGet("/api/objectives/v1/myprogress")]
public IActionResult GetMyObjectiveProgress()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
return Ok(new
{
Objectives = new List<object>(),
ObjectiveGroups = new List<object>()
});
}
[HttpGet("/api/avatar/v2")]
public IActionResult GetMyAvatar()
{
var player = AuthStuff.GetCurrentPlayer(Request);
if (player == null)
return Unauthorized();
return Ok(player.Player.PlayerExtra.Avatar);
}
[HttpPost("/api/avatar/v2/set")]
public IActionResult SetMyAvatar([FromBody] PlayerDBClasses.Avatar request)
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
return Ok(PlayerDB.SetAvatar((long)id, request));
}
[HttpGet("/api/avatar/v4/items")]
public IActionResult GetMyAvatarItems()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
string path = Path.Combine(Program.dataDir, "APIS", "Items", "AvatarItems.json");
return System.IO.File.Exists(path) ? Content(System.IO.File.ReadAllText(path), "application/json") : NotFound();
}
[HttpGet("/api/PlayerReporting/v1/moderationBlockDetails")]
public IActionResult GetMyModerationBlockDetails()
{
var player = AuthStuff.GetCurrentPlayer(Request);
if (player == null)
return Unauthorized();
return Ok(player.Player.PlayerExtra.ModerationBlockDetails);
}
[HttpGet("/api/relationships/v2/get")]
public IActionResult GetMyRelationships()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
return Ok(ServerConfig.Bracket);
}
[HttpGet("/api/messages/v2/get")]
public IActionResult GetMyMessages()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
return Ok(ServerConfig.Bracket);
}
[HttpGet("/playersettings")]
public IActionResult GetMySettings()
{
var player = AuthStuff.GetCurrentPlayer(Request);
if (player == null)
return Unauthorized();
return Ok(player.Player.PlayerExtra.Settings);
}
[HttpPut("/playersettings")]
public IActionResult SetMySettings([FromForm] string key, [FromForm] string value)
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
PlayerDB.SetPlayerSetting(key, value ?? "", (long)id);
return NoContent();
}
[HttpGet("/econ/customAvatarItems/v1/owned")]
public IActionResult GetMyOwnedCustomAvatarItems([FromQuery] int skip, [FromQuery] int take)
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
return Ok(new
{
Results = Array.Empty<object>(),
TotalResults = 0
});
}
[HttpGet("/api/checklist/v1/current")]
public IActionResult GetMyChecklist()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
return Ok(ServerConfig.Bracket);
}
[HttpGet("/api/players/v2/progression/bulk")]
public IActionResult GetProgressionForPlayers([FromQuery] List<long> id)
{
var authId = AuthStuff.GetPlayerId(Request);
if (authId == null)
return Unauthorized();
if (id == null || id.Count == 0)
return Ok(new List<PlayerDBClasses.PlayerProgressionDTO>());
var progressions = PlayerDB.GetProgressionBulk(id);
return Ok(progressions);
}
[HttpGet("/api/playerReputation/v2/bulk")]
public IActionResult GetReputationBulk([FromQuery] List<long> id)
{
var authId = AuthStuff.GetPlayerId(Request);
if (authId == null)
return Unauthorized();
if (id == null || id.Count == 0)
return Ok(new List<PlayerDBClasses.Reputation>());
var results = PlayerDB.GetReputationBulk(id);
return Ok(results);
}
[HttpPost("/api/PlayerReporting/v1/hile")] // todo log to channel
public IActionResult PlayerReportingHile()
{
var authId = AuthStuff.GetPlayerId(Request);
if (authId == null)
return Unauthorized();
return Ok(false);
}
[HttpGet("api/config/v2")]
public IActionResult GetConfigV2()
{
string path = Path.Combine(Program.dataDir, "APIS", "ConfigV2.json");
return System.IO.File.Exists(path) ? Content(System.IO.File.ReadAllText(path), "application/json") : NotFound();
}
[HttpGet("/api/announcement/v1/get")]
[HttpGet("/api/PlayerReporting/v1/voteToKickReasons")]
[HttpGet("/api/avatar/v3/saved")]
[HttpGet("/api/equipment/v2/getUnlocked")]
[HttpGet("/api/consumables/v2/getUnlocked")]
[HttpGet("/api/images/v2/named")]
[HttpGet("/api/avatar/v2/gifts")]
[HttpGet("/api/gamerewards/v1/pending")]
[HttpGet("/api/roomkeys/v1/mine")]
[HttpGet("/cdn/config/LoadingScreenTipData")]
[HttpGet("/api/roomcurrencies/v1/currencies")]
[HttpGet("/api/inventions/v2/mine")]
public IActionResult TodoImplement()
{
return Ok(ServerConfig.Bracket);
}
[HttpGet("/api/playerevents/v1/all")]
public IActionResult GetAllPlayerEvents()
{
return Ok(new
{
Created = Array.Empty<object>(),
Responses = Array.Empty<object>()
});
}
[HttpGet("/api/customAvatarItems/v1/isCreationAllowedForAccount")]
public IActionResult GetCustomAvatarItemsIsCreationAllowedForAccount()
{
return Ok(new
{
success = true,
value = (object?)null
});
}
[HttpGet("/api/customAvatarItems/v1/isCreationEnabled")]
[HttpGet("/api/customAvatarItems/v1/isRenderingEnabled")]
public IActionResult CustomAvatarItemsIsEnabled()
{
return Ok(true);
}
[HttpGet("/api/roomconsumables/v1/roomConsumable/room/{roomId}")]
public IActionResult GetRoomConsumablesForRoom(long roomId)
{
return Ok(ServerConfig.Bracket);
}
[HttpPost("/api/sanitize/v1")]
public IActionResult SanitizeV1([FromBody] SanitizeRequest request)
{
return Ok(JsonSerializer.Serialize(request.Value));
}
[HttpPost("/api/sanitize/v1/isPure")]
public IActionResult SanitizeV1IsPure()
{
return Ok(new
{
IsPure = true
});
}
public class SanitizeRequest
{
public string Value { get; set; } = string.Empty;
}
}
}
+30
View File
@@ -0,0 +1,30 @@
using Microsoft.AspNetCore.Mvc;
using FemRec2023.Classes;
using FemRec2023.Classes.DBs;
using FemRec2023.Classes.DBs.DBClasses;
using FemRec2023.Auth;
namespace FemRec2023.Controllers
{
[ApiController]
[Route("/acc")]
public class AccountController : ControllerBase
{
[HttpGet("account/bulk")]
public IActionResult GetAccountsBulk([FromQuery] List<long> id)
{
return Ok(PlayerDB.GetAccountsBulk(id));
}
[HttpGet("account/me")]
public IActionResult GetAccountMe()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
var account = PlayerDB.GetAccountMe(id.Value);
return account != null ? Ok(account) : NotFound();
}
}
}
+85
View File
@@ -0,0 +1,85 @@
using Microsoft.AspNetCore.Mvc;
using FemRec2023.Classes;
using FemRec2023.Classes.DBs;
using FemRec2023.Classes.DBs.DBClasses;
using FemRec2023.Auth;
namespace FemRec2023.Controllers
{
[ApiController]
[Route("/auth")]
public class AuthController : ControllerBase
{
[HttpGet("eac/challenge")]
public IActionResult GetEACChallenge()
{
string challenge = $"\"e\"";
return Ok(challenge);
}
[HttpGet("cachedlogin/forplatformid/{platform}/{platformId}")]
public IActionResult GetCachedLogins(PlayerDBClasses.Platforms platform, ulong platformId)
{
if (PlayerDB.GetLogins(platform, platformId, out var accounts) && accounts.Count > 0)
{
return Ok(accounts);
}
var newPlayer = PlayerDB.CreateAccount(platform, platformId, false); // todo use connect token create acc grant type instead but ts is for now
var newCachedLogin = new List<PlayerDBClasses.CachedLogins>
{
new PlayerDBClasses.CachedLogins
{
accountId = newPlayer.PlayerId,
lastLoginTime = newPlayer.Player.LastLoginAt,
platform = platform,
platformId = platformId.ToString(),
requirePassword = false
}
};
return Ok(newCachedLogin);
}
[HttpPost("connect/token")]
public async Task<IActionResult> ConnectToken(
[FromForm] string grant_type,
[FromForm] long account_id,
[FromForm] string client_id,
[FromForm] string client_secret,
[FromForm] PlayerDBClasses.Platforms platform,
[FromForm] ulong platform_id,
[FromForm] string device_id,
[FromForm] PlayerDBClasses.DeviceClasses? device_class,
[FromForm] DateTime? time,
[FromForm] int? ver,
[FromForm] string build_key,
[FromForm] string asid,
[FromForm] string eac_challenge,
[FromForm] string eac_response,
[FromForm] string platform_auth
)
{
switch (grant_type)
{
case "cached_login":
{
string token = AuthStuff.Encode(account_id);
Console.WriteLine("bitch try to login: who? here: " + account_id);
return Ok(new
{
access_token = token,
error = "",
error_description = "",
refresh_token = "eeeeeeeeeeee",
key = ""
});
}
default:
return BadRequest();
}
}
}
}
+155
View File
@@ -0,0 +1,155 @@
using Microsoft.AspNetCore.Mvc;
using static System.Net.Mime.MediaTypeNames;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
namespace FemRec2023.Controllers
{
[ApiController]
public class ImageController : ControllerBase
{
[Route("/imageserver/{*img_path}")]
public async Task<IActionResult> ImgServer(string img_path, int width = 0, int height = 0, string sig = "p1")
{
img_path = Uri.UnescapeDataString(img_path ?? "").TrimStart('/');
HttpContext.Response.Headers.Append("content-signature", "key-id=KEY:RSA:p1.rec.net; data=IWwe/pZ5vWWqNSkSM/54isgDxlZkdrP0sUrppKCbNktO2yCOTjq746xWiiLsueGuVcAGQqkjeRTimxolHckS/YXSYkEJxtiCXbLlsRia2DyAqtWVkGWsfczzFhp/56U66FVzolTspPCvjScOVlGO7dDIK7sJ+ndcRauWjsQsC6g3e7rUc6uwY099a6gy7sw6xr5BFZQSz8wg+fqyHYD/Sc4nQQVOTFZNNASqbJYhpNhEMXRnafCMuLl8a3mkGwvy3t4q2D/7SM48xrGZjEV47qNx1A91KCe28XVToFh4BzwEUU8nZ0d+KwV79MGarLo1cY8igc8FcoThKcovI4ClOg==");
HttpContext.Response.Headers.Append("Content-Disposition", $"inline; filename=\"{Path.GetFileName(img_path)}\"");
HttpContext.Response.Headers.Append("Access-Control-Allow-Origin", "*");
HttpContext.Response.Headers.Append("Access-Control-Allow-Headers", "Content-Type, Authorization, Cache-Control");
HttpContext.Response.Headers.Append("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
Response.Headers["Cache-Control"] = "public, max-age=14400";
var etag = $"\"{img_path.GetHashCode()}\"";
HttpContext.Response.Headers.Append("ETag", etag);
bool cropSquare = HttpContext.Request.Query.ContainsKey("cropsquare") &&
(HttpContext.Request.Query["cropsquare"].ToString().ToLower() == "true" ||
HttpContext.Request.Query["cropsquare"].ToString() == "1");
string baseImagesPath = Path.Combine(Program.dataDir, "Images");
string foundLocalPath = null;
if (Directory.Exists(baseImagesPath))
{
string directPath = Path.Combine(baseImagesPath, img_path);
if (System.IO.File.Exists(directPath))
{
foundLocalPath = directPath;
}
else
{
var subDirectories = Directory.EnumerateDirectories(baseImagesPath, "*", SearchOption.AllDirectories);
foreach (var dir in subDirectories)
{
string testPath = Path.Combine(dir, img_path);
if (System.IO.File.Exists(testPath))
{
foundLocalPath = testPath;
break;
}
}
}
}
if (foundLocalPath != null)
{
try
{
var imageBytes = await System.IO.File.ReadAllBytesAsync(foundLocalPath);
imageBytes = await ProcessImageAsync(imageBytes, cropSquare, width, height);
return File(imageBytes, "image/png");
}
catch
{
var fallbackBytes = await System.IO.File.ReadAllBytesAsync(foundLocalPath);
return File(fallbackBytes, "image/png");
}
}
string recNetLocalPath = Path.Combine(baseImagesPath, "RecNet", img_path);
try
{
using HttpClient client = new();
byte[] data = await client.GetByteArrayAsync($"https://img.rec.net/{img_path}");
Directory.CreateDirectory(Path.GetDirectoryName(recNetLocalPath)!);
await System.IO.File.WriteAllBytesAsync(recNetLocalPath, data);
try
{
var processed = await ProcessImageAsync(data, cropSquare, width, height);
return File(processed, GetMimeType(img_path));
}
catch
{
return File(data, GetMimeType(img_path));
}
}
catch (HttpRequestException ex)
{
Console.WriteLine($"[rec_net fetch failed] {ex.Message}");
}
return NotFound();
}
private static string GetMimeType(string filePath)
{
var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
if (!provider.TryGetContentType(filePath, out var contentType))
{
contentType = "image/png";
}
return contentType;
}
private static async Task<byte[]> ProcessImageAsync(byte[] imageBytes, bool cropSquare, int width, int height)
{
using var ms = new MemoryStream(imageBytes);
using var image = await SixLabors.ImageSharp.Image.LoadAsync<Rgba32>(ms);
if (cropSquare)
{
int size = Math.Min(image.Width, image.Height);
int x = (image.Width - size) / 2;
int y = (image.Height - size) / 2;
image.Mutate(ctx => ctx.Crop(new Rectangle(x, y, size, size)));
int targetSize = width > 0 ? width : height;
if (targetSize > 0)
{
image.Mutate(ctx => ctx.Resize(new ResizeOptions
{
Size = new Size(targetSize, targetSize),
Mode = ResizeMode.Max,
Sampler = KnownResamplers.Lanczos3
}));
}
}
else if (width > 0 || height > 0)
{
int resizeWidth = width;
int resizeHeight = height;
if (width > 0 && height == 0)
{
resizeHeight = (int)((double)image.Height / image.Width * width);
}
else if (height > 0 && width == 0)
{
resizeWidth = (int)((double)image.Width / image.Height * height);
}
image.Mutate(ctx => ctx.Resize(resizeWidth, resizeHeight));
}
using var output = new MemoryStream();
await image.SaveAsync(output, new PngEncoder());
return output.ToArray();
}
}
}
+76
View File
@@ -0,0 +1,76 @@
using Microsoft.AspNetCore.Mvc;
using FemRec2023.Classes;
using FemRec2023.Classes.DBs;
using FemRec2023.Classes.DBs.DBClasses;
using FemRec2023.Auth;
namespace FemRec2023.Controllers
{
[ApiController]
[Route("/match")]
public class MatchController : ControllerBase
{
[HttpGet("player")]
public IActionResult GetPlayerHeartbeatBulk(List<long> id)
{
var playerId = AuthStuff.GetPlayerId(Request);
if (playerId == null)
return Unauthorized();
return Ok(PlayerDB.GetPlayerHeartbeatsBulk(id));
}
[HttpPost("player/login")]
[HttpPost("player/exclusivelogin")]
public IActionResult PlayerLogin()
{
return Ok();
}
[HttpPost("player/logout")]
public IActionResult PlayerLogout()
{
return Ok();
}
[HttpPost("player/heartbeat")]
public IActionResult GetPlayerHeartbeat()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
return Ok(PlayerDB.GetPlayerHeartbeat((long)id));
}
[HttpPost("matchmake/none")]
public IActionResult MatchmakeNone()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
return Ok(PlayerDB.GetPlayerHeartbeat((long)id));
}
[HttpPost("matchmake/dorm")]
public IActionResult MatchmakeDorm()
{
var player = AuthStuff.GetCurrentPlayer(Request);
if (player == null)
return Unauthorized();
return Ok(Sessions.CreateDorm((long)player.PlayerId, player.Player.Username));
}
[HttpPost("matchmake/room/{roomId}")]
public IActionResult MatchmakeRoomRoomId(long roomId)
{
var player = AuthStuff.GetCurrentPlayer(Request);
if (player == null)
return Unauthorized();
return Ok(Sessions.CreateRoom((long)player.PlayerId, roomId));
}
}
}
+211
View File
@@ -0,0 +1,211 @@
using Microsoft.AspNetCore.Mvc;
using FemRec2023.Classes;
using FemRec2023.Classes.DBs;
using FemRec2023.Classes.DBs.DBClasses;
using FemRec2023.Auth;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Concurrent;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using static FemRec2023.Classes.DBs.DBClasses.PlayerDBClasses;
namespace FemRec2023.Controllers
{
[ApiController]
[Route("/noti")]
public class NotiController : ControllerBase
{
public static ConcurrentDictionary<string, WebSocket> WebSockets { get; } = new();
public static ConcurrentDictionary<long, HashSet<string>> PlayerConnections { get; } = new();
[HttpPost("hub/v1/negotiate")]
public IActionResult Negotiate()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
string connectionId = Guid.NewGuid().ToString("N");
var response = new
{
negotiateVersion = 0,
connectionId = connectionId,
availableTransports = new[]
{
new
{
transport = "WebSockets",
transferFormats = new[] { "Text", "Binary" }
}
}
};
return Ok(response);
}
[Route("hub/v1")]
public async Task HandleHub([FromQuery] string id)
{
var playerId = AuthStuff.GetPlayerId(Request);
if (playerId == null)
{
Console.WriteLine($"[WebSocket] Player is unauthorized");
HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
if (!HttpContext.WebSockets.IsWebSocketRequest)
{
Console.WriteLine($"[WebSocket] IsWebSocketRequest is false");
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
return;
}
using var socket = await HttpContext.WebSockets.AcceptWebSocketAsync();
Console.WriteLine($"[WebSocket] Player {playerId} connected with connection {id}");
PlayerConnections.AddOrUpdate(
(long)playerId,
_ => new HashSet<string> { id },
(_, hs) =>
{
lock (hs) { hs.Add(id); }
return hs;
}
);
await HandleConnectionAsync((long)playerId, id, socket);
}
private static async Task HandleConnectionAsync(long playerId, string connectionId, WebSocket socket)
{
using var pingCts = new CancellationTokenSource();
try
{
WebSockets[connectionId] = socket;
await SendHandshakeAsync(socket);
_ = Task.Run(() => PingLoopAsync(socket, pingCts.Token));
var buffer = new byte[4096];
while (socket.State == WebSocketState.Open)
{
var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
break;
var message = Encoding.UTF8.GetString(buffer, 0, result.Count).TrimEnd('\x1e');
Console.WriteLine($"Player ({playerId}) sent: {message}");
await HandleClientMessageAsync(socket, message);
}
}
catch (Exception ex)
{
Console.WriteLine($"[Error:{connectionId}] {ex.Message}");
}
finally
{
pingCts.Cancel();
WebSockets.TryRemove(connectionId, out _);
if (PlayerConnections.TryGetValue(playerId, out var connections))
{
lock (connections)
{
connections.Remove(connectionId);
if (connections.Count == 0)
PlayerConnections.TryRemove(playerId, out _);
}
}
if (socket.State is WebSocketState.Open or WebSocketState.CloseReceived)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing connection", CancellationToken.None);
}
Console.WriteLine($"[WebSocket] Player {playerId} disconnected from connection {connectionId}");
}
}
private static async Task HandleClientMessageAsync(WebSocket socket, string message)
{
try
{
using var doc = JsonDocument.Parse(message);
var root = doc.RootElement;
if (root.TryGetProperty("type", out var typeProp) && typeProp.GetInt32() == 1)
{
string target = root.GetProperty("target").GetString() ?? string.Empty;
string invocationId = root.GetProperty("invocationId").GetString() ?? string.Empty;
if (target == "SubscribeToPlayers")
{
var response = new
{
type = 3,
invocationId = invocationId,
result = (object?)null
};
await SendJsonAsync(socket, response);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"[ParseError] {ex.Message}");
}
}
private static async Task SendHandshakeAsync(WebSocket socket)
{
var handshake = new { protocol = "json", version = 1 };
await SendJsonAsync(socket, handshake);
}
private static async Task PingLoopAsync(WebSocket socket, CancellationToken token)
{
try
{
while (!token.IsCancellationRequested && socket.State == WebSocketState.Open)
{
var ping = new { type = 6 };
await SendJsonAsync(socket, ping);
await Task.Delay(10000, token);
}
}
catch (TaskCanceledException) { }
catch (Exception ex)
{
Console.WriteLine($"[PingError] {ex.Message}");
}
}
public static async Task SendNotificationToPlayer(long playerId, object message)
{
if (!PlayerConnections.TryGetValue(playerId, out var connections))
return;
foreach (var connectionId in connections)
{
if (WebSockets.TryGetValue(connectionId, out var socket) && socket.State == WebSocketState.Open)
{
await SendJsonAsync(socket, message);
}
}
}
private static async Task SendJsonAsync(WebSocket socket, object obj)
{
var json = JsonSerializer.Serialize(obj) + "\x1e";
var bytes = Encoding.UTF8.GetBytes(json);
await socket.SendAsync(bytes, WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}
+95
View File
@@ -0,0 +1,95 @@
using Microsoft.AspNetCore.Mvc;
using FemRec2023.Classes;
using FemRec2023.Classes.DBs;
using FemRec2023.Classes.DBs.DBClasses;
using FemRec2023.Auth;
namespace FemRec2023.Controllers
{
[ApiController]
[Route("/roomserver")]
public class RoomController : ControllerBase
{
[HttpGet("rooms")]
public async Task<IActionResult> GetRoomBy([FromQuery] string? name)
{
if (!string.IsNullOrEmpty(name))
{
var room = RoomDB.GetRoomByName(name);
return room != null ? Ok(room) : NotFound();
}
return NotFound();
}
[HttpGet("rooms/{roomId}")]
public async Task<IActionResult> GetRoomById(long roomId)
{
var room = RoomDB.GetRoom(roomId);
return room != null ? Ok(room) : NotFound();
}
[HttpGet("rooms/bulk")]
public async Task<IActionResult> GetRoomsByNames([FromQuery] List<string> name)
{
var rooms = RoomDB.GetRoomsByNames(name);
return Ok(rooms);
}
[HttpGet("photon_access_token")]
public async Task<IActionResult> GetPhotonAccessToken()
{
var id = AuthStuff.GetPlayerId(Request);
if (id == null)
return Unauthorized();
var permissions = new List<object>
{
new { Override = true, Permission = "CAN_USE_ROOM_RESET_BUTTON", Role = 0, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_USE_DELETE_ALL_BUTTON", Role = 0, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_SAVE_INVENTIONS", Role = 0, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_SPAWN_INVENTIONS", Role = 0, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_USE_PLAY_GIZMOS_TOGGLE", Role = 0, Type = 0, Value = "True" },
new { Override = false, Permission = "CAN_USE_MAKER_PEN", Role = 30, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_USE_ROOM_RESET_BUTTON", Role = 30, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_USE_DELETE_ALL_BUTTON", Role = 30, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_SAVE_INVENTIONS", Role = 30, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_SPAWN_INVENTIONS", Role = 30, Type = 0, Value = "True" },
new { Override = true, Permission = "CAN_USE_PLAY_GIZMOS_TOGGLE", Role = 30, Type = 0, Value = "True" }
};
var heartbeat = PlayerDB.GetPlayerHeartbeat((long)id);
var response = new
{
Permissions = permissions.ToArray(),
PhotonAccessToken = "",
RoomInstanceId = heartbeat?.roomInstance?.roomInstanceId
};
return Ok(response);
}
[HttpGet("rooms/hot")]
public IActionResult HotRooms(string tag, int skip = 0, int take = 30)
{
var (results, total) = RoomDB.GetHotRooms(tag, skip, take);
return Ok(new
{
Results = results ?? new List<RoomDBClasses.Room>(),
TotalResults = total
});
}
[HttpGet("rooms/{roomId}/interactionby/me")]
public IActionResult GetInteractionByMe(long roomId)
{
return Ok(new
{
Cheered = false,
Favorited = false,
LastVisitedAt = DateTime.UtcNow
});
}
}
}