chore(game-server): merge main (emulator fixes: contracts, shop, fortuna, friends, admin, presence) #16

Merged
neckfire merged 35 commits from main into game-server 2026-07-16 08:25:21 +00:00
Showing only changes of commit 0089833b74 - Show all commits
@@ -1,4 +1,6 @@
using Microsoft.Extensions.Options;
using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.Options;
using Prospect.Server.Api.Config;
using Prospect.Server.Api.Services.CloudScript.Models;
@@ -7,20 +9,52 @@ namespace Prospect.Server.Api.Services.CloudScript.Functions;
[CloudScriptFunction("GetSignalRConnection")]
public class GetSignalRConnection : ICloudScriptFunction<FYGetSignalRConnection, FYGetSignalRConnectionResult>
{
private readonly PlayFabSettings _settings;
// LAN address of the homelab host. Clients on the local network get the SignalR URL on
// this IP (which their cert already validates via the IP/DNS SAN), while external clients
// keep the public domain from configuration. This matters because the real-time WebSocket
// (libwebsockets, incl. under Proton/Wine) can't reach the public domain from inside the
// LAN (hairpin NAT), which surfaced as "error code 5" right after the intro.
private const string LanHost = "192.168.1.136";
public GetSignalRConnection(IOptions<PlayFabSettings> settings)
private readonly PlayFabSettings _settings;
private readonly IHttpContextAccessor _httpContextAccessor;
public GetSignalRConnection(IOptions<PlayFabSettings> settings, IHttpContextAccessor httpContextAccessor)
{
_settings = settings.Value;
_httpContextAccessor = httpContextAccessor;
}
public Task<FYGetSignalRConnectionResult> ExecuteAsync(FYGetSignalRConnection request)
{
// The game client connects to SignalR only over HTTPS
// The game client connects to SignalR only over HTTPS.
var url = _settings.SignalRURL;
var remote = _httpContextAccessor.HttpContext?.Connection.RemoteIpAddress;
if (remote != null && IsLan(remote))
{
try
{
url = new UriBuilder(url) { Host = LanHost }.Uri.AbsoluteUri;
}
catch { /* keep the configured URL on any parsing issue */ }
}
return Task.FromResult(new FYGetSignalRConnectionResult
{
Url = _settings.SignalRURL,
Url = url,
AccessToken = _settings.SignalRAccessToken
});
}
private static bool IsLan(IPAddress ip)
{
if (IPAddress.IsLoopback(ip)) return true;
if (ip.IsIPv4MappedToIPv6) ip = ip.MapToIPv4();
if (ip.AddressFamily != AddressFamily.InterNetwork) return false;
var b = ip.GetAddressBytes();
return b[0] == 10
|| (b[0] == 172 && b[1] >= 16 && b[1] <= 31)
|| (b[0] == 192 && b[1] == 168);
}
}