Many changes. Commit before I break down.

- Authentication middleware uses Zod
- PhotonRegionId in config
- DB key changes and additions
- WebSocket for SignalR mock
- Presence additions
  * Needs modification for playerIds (do not store `Profile` in a set, this will cause sync issues)
- Profile settings
- Profile Device Class
- Zod properly checks for issuer in token
- Room scene type bug
- Setting key import started
- Instancing changes
- PlayerReporting API route
- Deduplicated auth/connect/token
- match/player/login begin
- WebSocket hands off connection to SignalR handler
This commit is contained in:
2025-03-27 00:44:58 -04:00
parent 3538321487
commit c920dbe88a
23 changed files with 792 additions and 194 deletions

50
src/socket/handoff.ts Normal file
View File

@@ -0,0 +1,50 @@
const handoffs: Set<SocketHandoff> = new Set();
function randomId(length: number) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
counter += 1;
}
return result;
}
// Lots of this is redundant. The WebSocket request already contains an access token for the profile, but I'd
// like to make sure that connectionIds are freed automatically.
export class SocketHandoff {
static generateId() {
let id = randomId(48);
while (handoffs.values().find(handoff => handoff.id == id)) id = randomId(48);
return id;
}
static find(id: string) {
return handoffs.values().find(handoff => handoff.id === id);
}
id: string;
#timeout: number;
constructor() {
this.id = SocketHandoff.generateId();
this.#timeout = setTimeout(() => {
handoffs.delete(this);
});
handoffs.add(this);
}
delete() {
clearTimeout(this.#timeout);
handoffs.delete(this);
}
complete() {
this.delete();
}
}

18
src/socket/route.ts Normal file
View File

@@ -0,0 +1,18 @@
import { APIUtils } from "../apiutils.ts";
import { SocketHandoff } from "./handoff.ts";
export const route = APIUtils.createRouter('/notify');
route.router.post('/hub/v1/negotiate',
APIUtils.Authentication,
(_rq, rs) => {
const handoff = new SocketHandoff();
rs.json({
connectionId: handoff.id,
availableTransports: [{transport:"WebSockets",transferFormats:["Text"]}]
});
},
);

32
src/socket/socket.ts Normal file
View File

@@ -0,0 +1,32 @@
import WebSocket from "ws";
import Profile from "../data/profiles.ts";
import { IncomingMessage } from "node:http";
import Logging from "@proxnet/undead-logging";
export class SignalRSocketHandler {
log: Logging = new Logging("SignalMock-");
#socket: WebSocket;
#profile: Profile;
constructor(socket: WebSocket, player: Profile) {
this.#socket = socket;
this.#profile = player;
player.setSocketHandler(this);
this.log.source += player.getId().toString();
// log: we connected!!
Deno.addSignalListener('SIGINT', this.destroy);
}
destroy() {
this.#socket.close();
Deno.removeSignalListener('SIGINT', this.destroy);
}
}

22
src/socket/types.ts Normal file
View File

@@ -0,0 +1,22 @@
export enum MessageTypes {
CancelInvocation,
Close,
Completion,
Handshake,
Invocation,
Ping,
StreamInvocation,
StreamItem,
Ack
}
export interface SignalRMessage {
arguments: object[],
error?: string,
invocationId?: string,
item?: object,
nonblocking: boolean,
result?: object,
target: string,
type: MessageTypes
}