changed network log format, player settings
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.env
|
/.env
|
||||||
/persist/
|
/persist/
|
||||||
|
/worklist.txt
|
||||||
22
src/main.ts
22
src/main.ts
@@ -10,6 +10,7 @@ import { verify } from "@hono/hono/jwt";
|
|||||||
import { type ProfileToken } from "./server/profiles/types/profile.ts";
|
import { type ProfileToken } from "./server/profiles/types/profile.ts";
|
||||||
import { SignalRSocketHandler } from "./server/socket/signalr/socket.ts";
|
import { SignalRSocketHandler } from "./server/socket/signalr/socket.ts";
|
||||||
import { PushNotificationId } from "./server/socket/signalr/types.ts";
|
import { PushNotificationId } from "./server/socket/signalr/types.ts";
|
||||||
|
import { genericResponse } from "./util/api.ts";
|
||||||
|
|
||||||
LoggingConfiguration.resetTimeFormat = TimeFormat.Unix;
|
LoggingConfiguration.resetTimeFormat = TimeFormat.Unix;
|
||||||
LoggingConfiguration.resetLogTiming = LogTiming.Microtask;
|
LoggingConfiguration.resetLogTiming = LogTiming.Microtask;
|
||||||
@@ -40,10 +41,7 @@ await routeImporter(AppRoot.app, 'src/', [
|
|||||||
|
|
||||||
// deno-lint-ignore require-await
|
// deno-lint-ignore require-await
|
||||||
AppRoot.app.use('*', async c => {
|
AppRoot.app.use('*', async c => {
|
||||||
if (!logBlacklist.includes(c.req.url)) log.e(detailedLog([c.get('srcAddr'),
|
return c.json(genericResponse(false, "Resource Not Found"), 404);
|
||||||
`404 ${c.req.method} ${getFullPathFromUrl(new URL(c.req.url))}`
|
|
||||||
]));
|
|
||||||
c.res = new Response("Not Found", { status: 404 });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const consoleSockets: Set<SocketConsoleHandler> = new Set();
|
export const consoleSockets: Set<SocketConsoleHandler> = new Set();
|
||||||
@@ -91,7 +89,7 @@ const server = Deno.serve({ hostname: "10.0.1.39", port: 13370, onListen: addr =
|
|||||||
const payload = (await verify(splitHeader, secret)) as ProfileToken;
|
const payload = (await verify(splitHeader, secret)) as ProfileToken;
|
||||||
|
|
||||||
const profile = await Server.Profiles.get(payload.sub);
|
const profile = await Server.Profiles.get(payload.sub);
|
||||||
if (!profile) return new Response("Internal Server Error (profile)", { status: 500 });;
|
if (!profile) return new Response("Internal Server Error (profile)", { status: 500 });
|
||||||
const { response, socket } = Deno.upgradeWebSocket(req);
|
const { response, socket } = Deno.upgradeWebSocket(req);
|
||||||
const handler = new SignalRSocketHandler(socket, profile);
|
const handler = new SignalRSocketHandler(socket, profile);
|
||||||
gameSockets.add(handler);
|
gameSockets.add(handler);
|
||||||
@@ -120,14 +118,20 @@ const server = Deno.serve({ hostname: "10.0.1.39", port: 13370, onListen: addr =
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!logBlacklist.includes(url.pathname)) log.n(detailedLog([srcAddr,
|
const res = await AppRoot.app.fetch(req, { srcAddr });
|
||||||
`${req.method} ${getFullPathFromUrl(new URL(req.url))}`,
|
|
||||||
|
const netlog = detailedLog([srcAddr,
|
||||||
|
`${res.status}: ${req.method} ${getFullPathFromUrl(new URL(req.url))}`,
|
||||||
formatHeader(req.headers, 'Content-Type'),
|
formatHeader(req.headers, 'Content-Type'),
|
||||||
formatHeader(req.headers, 'Connection'),
|
formatHeader(req.headers, 'Connection'),
|
||||||
formatHeader(req.headers, 'User-Agent'),
|
formatHeader(req.headers, 'User-Agent'),
|
||||||
]));
|
]);
|
||||||
|
if (!logBlacklist.includes(url.pathname)) {
|
||||||
|
if (res.status === 404) log.e(netlog);
|
||||||
|
else log.n(netlog);
|
||||||
|
}
|
||||||
|
|
||||||
return await AppRoot.app.fetch(req, { srcAddr });
|
return res;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import { authenticate } from "../../../util/api.ts";
|
|||||||
import Server from "../../../server/server.ts";
|
import Server from "../../../server/server.ts";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
import { typedZValidator } from "../../../util/validators.ts";
|
import { typedZValidator } from "../../../util/validators.ts";
|
||||||
|
import Logging from "@proxnet/undead-logging";
|
||||||
|
|
||||||
|
const log = new Logging("AccountDebug");
|
||||||
|
|
||||||
export const route = createHonoRoute('/account');
|
export const route = createHonoRoute('/account');
|
||||||
|
|
||||||
@@ -29,10 +32,9 @@ route.app.get('/bulk', typedZValidator('query', bulkAccountQuerySchema), async c
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
route.app.use('*', authenticate);
|
route.app.use(authenticate);
|
||||||
|
|
||||||
route.app.get('/me', c => {
|
route.app.get('/me', c => {
|
||||||
const profile = c.get('profile');
|
const profile = c.get('profile');
|
||||||
|
|
||||||
return c.json(profile.selfExport());
|
return c.json(profile.selfExport());
|
||||||
});
|
});
|
||||||
28
src/routes/api/routes/settings.ts
Normal file
28
src/routes/api/routes/settings.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import z from "zod";
|
||||||
|
import { authenticate, genericResponse } from "../../../util/api.ts";
|
||||||
|
import { createHonoRoute } from "../../../util/import.ts";
|
||||||
|
import { transformStringToEnum, typedZValidator } from "../../../util/validators.ts";
|
||||||
|
import { ProfileSetting } from "../../../server/profiles/content/Settings.ts";
|
||||||
|
import { trimTrailingSlash } from "@hono/hono/trailing-slash";
|
||||||
|
|
||||||
|
export const route = createHonoRoute('/settings');
|
||||||
|
|
||||||
|
route.app.use(authenticate, trimTrailingSlash());
|
||||||
|
|
||||||
|
route.app.get('/v2', async c => {
|
||||||
|
const profile = c.get('profile');
|
||||||
|
const settings = await profile.Settings.getAllSettings();
|
||||||
|
c.json(settings);
|
||||||
|
});
|
||||||
|
|
||||||
|
const settingsSetSchema = z.object({
|
||||||
|
Key: z.string().transform(transformStringToEnum<ProfileSetting>(ProfileSetting, true)),
|
||||||
|
Value: z.string()
|
||||||
|
});
|
||||||
|
route.app.post('/v2/set', typedZValidator('json', settingsSetSchema), async c => {
|
||||||
|
const { Key, Value } = c.req.valid('json');
|
||||||
|
if (!Key) return c.json(genericResponse(false, "Internal Server Error"), 500);
|
||||||
|
|
||||||
|
await c.get('profile').Settings.setSetting(Key, Value);
|
||||||
|
return c.status(200);
|
||||||
|
});
|
||||||
45
src/server/profiles/content/Settings.ts
Normal file
45
src/server/profiles/content/Settings.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import z from "zod";
|
||||||
|
import ProfileContentManager from "./base.ts";
|
||||||
|
|
||||||
|
export enum ProfileSetting {
|
||||||
|
Test = "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
const genericSettingSchema = z.object({
|
||||||
|
Key: z.string(),
|
||||||
|
Value: z.string()
|
||||||
|
});
|
||||||
|
const settingsSchema = z.array(genericSettingSchema);
|
||||||
|
type Setting = z.infer<typeof genericSettingSchema>;
|
||||||
|
|
||||||
|
export class ProfileSettingsManager extends ProfileContentManager {
|
||||||
|
|
||||||
|
static settingsKey = "settings";
|
||||||
|
#key = this.profile.constructProfilePropertyKey(ProfileSettingsManager.settingsKey);
|
||||||
|
|
||||||
|
async getAllSettings(): Promise<Setting[]> {
|
||||||
|
const items = await this.kv.getKv().get(this.#key);
|
||||||
|
if (items.value == null) return [];
|
||||||
|
const parsed = settingsSchema.safeParse(items.value);
|
||||||
|
if (parsed.success) return parsed.data;
|
||||||
|
else return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSetting(setting: ProfileSetting) {
|
||||||
|
const settings = await this.getAllSettings();
|
||||||
|
return settings.find(s => s.Key == setting)?.Value || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #updateSettings(settings: Setting[]) {
|
||||||
|
await this.kv.getKv().set(this.#key, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setSetting(Key: ProfileSetting, Value: string) {
|
||||||
|
const settings = await this.getAllSettings();
|
||||||
|
const s = settings.find(setting => setting.Key === Key);
|
||||||
|
if (!s) settings.push({ Key, Value });
|
||||||
|
else s.Value = Value;
|
||||||
|
await this.#updateSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,15 @@
|
|||||||
|
import type KV from "../../persistence/kv.ts";
|
||||||
|
import type Profile from "../profile.ts";
|
||||||
|
|
||||||
class ProfileContentManager {
|
class ProfileContentManager {
|
||||||
|
|
||||||
|
protected profile: Profile;
|
||||||
|
protected kv: KV;
|
||||||
|
constructor(profile: Profile, kv: KV) {
|
||||||
|
this.profile = profile;
|
||||||
|
this.kv = kv;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProfileContentManager;
|
export default ProfileContentManager;
|
||||||
@@ -2,6 +2,7 @@ import KV from "../persistence/kv.ts";
|
|||||||
import { ProfileRole } from "../platforms/base.ts";
|
import { ProfileRole } from "../platforms/base.ts";
|
||||||
import { type ServerBase } from "../server.ts";
|
import { type ServerBase } from "../server.ts";
|
||||||
import { type SignalRSocketHandler } from "../socket/signalr/socket.ts";
|
import { type SignalRSocketHandler } from "../socket/signalr/socket.ts";
|
||||||
|
import { ProfileSettingsManager } from "./content/Settings.ts";
|
||||||
import ProfileManagerBase from "./manager.ts";
|
import ProfileManagerBase from "./manager.ts";
|
||||||
import { recNetAccountSchema, SelfAccount, type RecNetAccount } from "./types/profile.ts";
|
import { recNetAccountSchema, SelfAccount, type RecNetAccount } from "./types/profile.ts";
|
||||||
|
|
||||||
@@ -15,19 +16,23 @@ class Profile {
|
|||||||
|
|
||||||
#selfAcc: SelfAccount;
|
#selfAcc: SelfAccount;
|
||||||
|
|
||||||
|
Settings: ProfileSettingsManager;
|
||||||
|
|
||||||
constructor(acc: SelfAccount, kv: KV, server: ServerBase) {
|
constructor(acc: SelfAccount, kv: KV, server: ServerBase) {
|
||||||
this.#id = acc.accountId;
|
this.#id = acc.accountId;
|
||||||
this.#selfAcc = acc;
|
this.#selfAcc = acc;
|
||||||
this.#kv = kv;
|
this.#kv = kv;
|
||||||
this.#server = server;
|
this.#server = server;
|
||||||
|
|
||||||
|
this.Settings = new ProfileSettingsManager(this, this.#kv);
|
||||||
}
|
}
|
||||||
|
|
||||||
async #saveSelfAcc() {
|
async #saveSelfAcc() {
|
||||||
await this.#kv.getKv().set(this.#constructProfilePropertyKey(), this.#selfAcc);
|
await this.#kv.getKv().set(this.constructProfilePropertyKey(), this.#selfAcc);
|
||||||
this.#server.emit('profile.update', { profile: this });
|
this.#server.emit('profile.update', { profile: this });
|
||||||
}
|
}
|
||||||
|
|
||||||
#constructProfilePropertyKey(...keys: (string | undefined)[]) {
|
constructProfilePropertyKey(...keys: (string | undefined)[]) {
|
||||||
return [ ProfileManagerBase.profilesKey, this.#id, ...keys.filter(val => typeof val == 'string') ];
|
return [ ProfileManagerBase.profilesKey, this.#id, ...keys.filter(val => typeof val == 'string') ];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,24 +56,24 @@ class Profile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getBio(){
|
async getBio(){
|
||||||
const key = this.#constructProfilePropertyKey('bio');
|
const key = this.constructProfilePropertyKey('bio');
|
||||||
const val = await this.#kv.getKv().get<string>(key);
|
const val = await this.#kv.getKv().get<string>(key);
|
||||||
if (!val.value) return null;
|
if (!val.value) return null;
|
||||||
else return val.value;
|
else return val.value;
|
||||||
}
|
}
|
||||||
async setBio(bio: string) {
|
async setBio(bio: string) {
|
||||||
const key = this.#constructProfilePropertyKey('bio');
|
const key = this.constructProfilePropertyKey('bio');
|
||||||
await this.#kv.getKv().set(key, bio);
|
await this.#kv.getKv().set(key, bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRole(): Promise<ProfileRole> {
|
async getRole(): Promise<ProfileRole> {
|
||||||
const val = (await this.#kv.getKv().get<ProfileRole>(this.#constructProfilePropertyKey('role'))).value;
|
const val = (await this.#kv.getKv().get<ProfileRole>(this.constructProfilePropertyKey('role'))).value;
|
||||||
if (!val) return ProfileRole.User;
|
if (!val) return ProfileRole.User;
|
||||||
else return val;
|
else return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setRole(role: ProfileRole) {
|
async setRole(role: ProfileRole) {
|
||||||
await this.#kv.getKv().set(this.#constructProfilePropertyKey('role'), role);
|
await this.#kv.getKv().set(this.constructProfilePropertyKey('role'), role);
|
||||||
this.#server.emit('profile.roleupdate', { profile: this, newRole: role });
|
this.#server.emit('profile.roleupdate', { profile: this, newRole: role });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,13 +18,17 @@ export const typedZValidator = <T extends z.ZodSchema>(
|
|||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const transformStringToEnum = <T>(anEnum: { [s: number]: string }) => {
|
export const transformStringToEnum = <T>(anEnum: { [s: string]: string | number }, str?: boolean) => {
|
||||||
return (arg: string, ctx: z.RefinementCtx<string>) => {
|
return (arg: string, ctx: z.RefinementCtx<string | number>) => {
|
||||||
|
if (!str) {
|
||||||
const int = parseInt(arg);
|
const int = parseInt(arg);
|
||||||
if (isNaN(int)) ctx.addIssue("Must be parseable as a number");
|
if (isNaN(int) || !Number.isSafeInteger(int)) ctx.addIssue("number was not valid");
|
||||||
else {
|
else if (anEnum[int]) return int as T;
|
||||||
if (anEnum[int]) return int as T;
|
else ctx.addIssue("number was not a valid enum member");
|
||||||
else ctx.addIssue("Number must be a valid enum member");
|
} else {
|
||||||
|
const vals = Object.values(anEnum);
|
||||||
|
if (vals.includes(arg)) return arg as T;
|
||||||
|
else ctx.addIssue("string was not a valid enum member");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user