Further login process
* APIUtils addition: query validation * Coach and Server accounts are now properly created if they do not exist * Profiles now cannot be IDs 1 or 2 (reservedIds) * Fixed profile username exists bug * Added relationship manager * Started relationship management * DeviceClass and VRMovementMode enum defaults for reserved profiles * Presence update simplification * Progression fixes * Relationship query and object fixes * Base configuration is now rate limited * Progression route no longer requires authentication, instead is rate limited * Base relationships with reserved profiles (Coach and Server) * DeviceClass required for login * Get presence route * Socket route no longer logs * Socket target base finished
This commit is contained in:
@@ -2,7 +2,6 @@ import { APIUtils } from "../apiutils.ts";
|
||||
import { Config } from "../config.ts";
|
||||
import { AuthType } from "../data/users.ts";
|
||||
import { SocketHandoff } from "./handoff.ts";
|
||||
import express from "express";
|
||||
|
||||
const config = Config.getConfig();
|
||||
|
||||
@@ -12,8 +11,6 @@ route.router.post('/hub/v1/negotiate',
|
||||
|
||||
APIUtils.Authentication,
|
||||
APIUtils.AuthenticationType(AuthType.Game),
|
||||
express.urlencoded({ extended: true }),
|
||||
APIUtils.logBody,
|
||||
|
||||
(_rq, rs) => {
|
||||
const handoff = new SocketHandoff();
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
import { Profile } from "../data/profiles.ts";
|
||||
import Logging from "@proxnet/undead-logging";
|
||||
import { Message, MessageKind, SignalMessageType, SignalRMessage, SignalRMessageSchema, TargetResult, TargetResultFailure, TargetResultSuccess, TargetResultType } from "./types.ts";
|
||||
import {
|
||||
CompletionMessage,
|
||||
Message,
|
||||
MessageKind,
|
||||
SignalMessageType,
|
||||
SignalRMessage,
|
||||
SignalRMessageSchema,
|
||||
TargetResult,
|
||||
TargetResultFailure,
|
||||
TargetResultNotATarget,
|
||||
TargetResultSuccess,
|
||||
TargetResultType
|
||||
} from "./types.ts";
|
||||
import { SocketTarget } from "./targets/targetbase.ts";
|
||||
import { PlayerSocketSubscriptionTarget } from "./targets/SubscribeToPlayers.ts";
|
||||
|
||||
@@ -26,22 +38,55 @@ export class SignalRSocketHandler {
|
||||
|
||||
}
|
||||
|
||||
async #dispatchTarget<T = unknown>(target: string, args: object[]): Promise<TargetResult> {
|
||||
async #dispatchTarget<T = unknown>(target: string, args: unknown): Promise<TargetResult> {
|
||||
const targetExec = this.#Targets.get(target);
|
||||
if (!targetExec) return { type: TargetResultType.Failure } as TargetResultFailure;
|
||||
else return { type: TargetResultType.Success, data: await targetExec.exec(args) } as TargetResultSuccess<T>;
|
||||
if (!targetExec) return { type: TargetResultType.NotATarget } as TargetResultNotATarget;
|
||||
else {
|
||||
try {
|
||||
return { type: TargetResultType.Success, data: await targetExec.exec(args) } as TargetResultSuccess<T>;
|
||||
} catch (err) {
|
||||
this.#log.w(`Target '${target}' function error: ${err}`);
|
||||
if (err instanceof Error) return { type: TargetResultType.Failure, err: err } as TargetResultFailure;
|
||||
else return { type: TargetResultType.Failure, err: `${err}` } as TargetResultFailure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#onMessage(message: Message) {
|
||||
async #onMessage(message: Message) {
|
||||
if (message.kind == MessageKind.Protocol) {
|
||||
this.sendRaw({});
|
||||
return;
|
||||
} else {
|
||||
this.#log.d(`CLIENT MESSAGE\n Type: ${message.data.type} (${SignalMessageType[message.data.type]})\n ${JSON.stringify(message.data)}`);
|
||||
if (message.data.type == SignalMessageType.Invocation && message.data.invocationId) { // don't send completion messages for nonblocking invocations
|
||||
const res = await this.#dispatchTarget(message.data.target, message.data.arguments[0]); // rec room only uses the first index
|
||||
if (res.type == TargetResultType.Success) {
|
||||
const signalRes: CompletionMessage = {
|
||||
type: SignalMessageType.Completion,
|
||||
invocationId: message.data.invocationId,
|
||||
result: JSON.stringify(res.data)
|
||||
}
|
||||
this.sendRaw(signalRes);
|
||||
} else if (res.type == TargetResultType.Failure) {
|
||||
const signalRes: CompletionMessage = {
|
||||
type: SignalMessageType.Completion,
|
||||
invocationId: message.data.invocationId,
|
||||
error: res.err instanceof Error ? res.err.message : res.err
|
||||
}
|
||||
this.sendRaw(signalRes);
|
||||
} else {
|
||||
const signalRes: CompletionMessage = {
|
||||
type: SignalMessageType.Completion,
|
||||
invocationId: message.data.invocationId,
|
||||
error: "Target not found"
|
||||
}
|
||||
this.sendRaw(signalRes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async #init() {
|
||||
#init() {
|
||||
this.#log.source += this.#profile.getId().toString();
|
||||
|
||||
this.#log.i(`Created hub socket`);
|
||||
@@ -82,6 +127,9 @@ export class SignalRSocketHandler {
|
||||
|
||||
sendRaw(data: object) {
|
||||
this.#socket.send(`${JSON.stringify(data)}\u001e`);
|
||||
// todo sometime: make this less confusing
|
||||
const type = `Type: ${JSON.stringify(data) == '{}' ? 'Protocol Message' : `${(data as SignalRMessage).type} (${SignalMessageType[(data as SignalRMessage).type]})`}`;
|
||||
this.#log.d(`SERVER MESSAGE\n ${type}\n ${JSON.stringify(data as SignalRMessage)}`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
import { z } from "zod";
|
||||
import { SocketTarget } from "./targetbase.ts";
|
||||
|
||||
const ArgumentSchema = z.object({
|
||||
PlayerIds: z.array(z.number())
|
||||
});
|
||||
|
||||
export class PlayerSocketSubscriptionTarget extends SocketTarget {
|
||||
|
||||
subscriptions: number[] = [];
|
||||
@@ -9,8 +14,12 @@ export class PlayerSocketSubscriptionTarget extends SocketTarget {
|
||||
}
|
||||
|
||||
// deno-lint-ignore require-await
|
||||
override async exec(_args: (object | string | number | boolean)[]) {
|
||||
return;
|
||||
override async exec(args: unknown) {
|
||||
const parsed = ArgumentSchema.safeParse(args);
|
||||
if (parsed.success) {
|
||||
this.setSubscriptions(parsed.data.PlayerIds);
|
||||
return;
|
||||
} else throw new Error("Invalid arguments");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ export class SocketTarget {
|
||||
}
|
||||
|
||||
// deno-lint-ignore require-await
|
||||
async exec(_args: (object | string | number | boolean)[]) {
|
||||
async exec(_args: unknown) {
|
||||
throw new Error("Execution for this target is not set.");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ export enum MessageKind {
|
||||
Protocol,
|
||||
Data
|
||||
}
|
||||
interface MessageBase {
|
||||
export interface MessageBase {
|
||||
kind: MessageKind
|
||||
}
|
||||
interface DataMessage extends MessageBase {
|
||||
export interface DataMessage extends MessageBase {
|
||||
kind: MessageKind.Data,
|
||||
data: SignalRMessage
|
||||
}
|
||||
interface ProtocolMessage extends MessageBase {
|
||||
export interface ProtocolMessage extends MessageBase {
|
||||
kind: MessageKind.Protocol
|
||||
}
|
||||
export type Message = ProtocolMessage | DataMessage;
|
||||
@@ -34,68 +34,68 @@ export enum SignalMessageType {
|
||||
Close
|
||||
}
|
||||
|
||||
interface BaseMessage {
|
||||
export interface BaseMessage {
|
||||
type: SignalMessageType;
|
||||
}
|
||||
|
||||
interface InvocationMessage extends BaseMessage {
|
||||
export interface InvocationMessage extends BaseMessage {
|
||||
type: SignalMessageType.Invocation;
|
||||
target: string;
|
||||
arguments: unknown[];
|
||||
invocationId?: string;
|
||||
}
|
||||
|
||||
interface StreamItemMessage extends BaseMessage {
|
||||
export interface StreamItemMessage extends BaseMessage {
|
||||
type: SignalMessageType.StreamItem;
|
||||
invocationId: string;
|
||||
item: unknown;
|
||||
}
|
||||
|
||||
interface CompletionMessage extends BaseMessage {
|
||||
export interface CompletionMessage extends BaseMessage {
|
||||
type: SignalMessageType.Completion;
|
||||
invocationId: string;
|
||||
result?: unknown;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface PingMessage extends BaseMessage {
|
||||
export interface PingMessage extends BaseMessage {
|
||||
type: SignalMessageType.Ping;
|
||||
}
|
||||
|
||||
interface CloseMessage extends BaseMessage {
|
||||
export interface CloseMessage extends BaseMessage {
|
||||
type: SignalMessageType.Close;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
const BaseMessageSchema = z.object({
|
||||
export const BaseMessageSchema = z.object({
|
||||
type: z.nativeEnum(SignalMessageType),
|
||||
});
|
||||
|
||||
const InvocationMessageSchema = BaseMessageSchema.extend({
|
||||
export const InvocationMessageSchema = BaseMessageSchema.extend({
|
||||
type: z.literal(SignalMessageType.Invocation),
|
||||
target: z.string(),
|
||||
arguments: z.array(z.unknown()),
|
||||
invocationId: z.string().optional(),
|
||||
});
|
||||
|
||||
const StreamItemMessageSchema = BaseMessageSchema.extend({
|
||||
export const StreamItemMessageSchema = BaseMessageSchema.extend({
|
||||
type: z.literal(SignalMessageType.StreamItem),
|
||||
invocationId: z.string(),
|
||||
item: z.unknown(),
|
||||
});
|
||||
|
||||
const CompletionMessageSchema = BaseMessageSchema.extend({
|
||||
export const CompletionMessageSchema = BaseMessageSchema.extend({
|
||||
type: z.literal(SignalMessageType.Completion),
|
||||
invocationId: z.string(),
|
||||
result: z.unknown().optional(),
|
||||
error: z.string().optional(),
|
||||
});
|
||||
|
||||
const PingMessageSchema = BaseMessageSchema.extend({
|
||||
export const PingMessageSchema = BaseMessageSchema.extend({
|
||||
type: z.literal(SignalMessageType.Ping),
|
||||
});
|
||||
|
||||
const CloseMessageSchema = BaseMessageSchema.extend({
|
||||
export const CloseMessageSchema = BaseMessageSchema.extend({
|
||||
type: z.literal(SignalMessageType.Close),
|
||||
error: z.string().optional(),
|
||||
});
|
||||
@@ -113,7 +113,7 @@ export enum TargetResultType {
|
||||
Failure,
|
||||
NotATarget
|
||||
}
|
||||
interface TargetResultBase {
|
||||
export interface TargetResultBase {
|
||||
type: TargetResultType
|
||||
}
|
||||
export interface TargetResultSuccess<T = unknown> extends TargetResultBase {
|
||||
@@ -122,6 +122,7 @@ export interface TargetResultSuccess<T = unknown> extends TargetResultBase {
|
||||
}
|
||||
export interface TargetResultFailure extends TargetResultBase {
|
||||
type: TargetResultType.Failure
|
||||
err: string | Error
|
||||
}
|
||||
export interface TargetResultNotATarget extends TargetResultBase {
|
||||
type: TargetResultType.NotATarget
|
||||
|
||||
Reference in New Issue
Block a user