forked from zombieb/galvanic-corrosion-rewrite
changed network log format, player settings
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.env
|
||||
/.env
|
||||
/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 { SignalRSocketHandler } from "./server/socket/signalr/socket.ts";
|
||||
import { PushNotificationId } from "./server/socket/signalr/types.ts";
|
||||
import { genericResponse } from "./util/api.ts";
|
||||
|
||||
LoggingConfiguration.resetTimeFormat = TimeFormat.Unix;
|
||||
LoggingConfiguration.resetLogTiming = LogTiming.Microtask;
|
||||
@@ -40,10 +41,7 @@ await routeImporter(AppRoot.app, 'src/', [
|
||||
|
||||
// deno-lint-ignore require-await
|
||||
AppRoot.app.use('*', async c => {
|
||||
if (!logBlacklist.includes(c.req.url)) log.e(detailedLog([c.get('srcAddr'),
|
||||
`404 ${c.req.method} ${getFullPathFromUrl(new URL(c.req.url))}`
|
||||
]));
|
||||
c.res = new Response("Not Found", { status: 404 });
|
||||
return c.json(genericResponse(false, "Resource Not Found"), 404);
|
||||
});
|
||||
|
||||
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 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 handler = new SignalRSocketHandler(socket, profile);
|
||||
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,
|
||||
`${req.method} ${getFullPathFromUrl(new URL(req.url))}`,
|
||||
const res = await AppRoot.app.fetch(req, { srcAddr });
|
||||
|
||||
const netlog = detailedLog([srcAddr,
|
||||
`${res.status}: ${req.method} ${getFullPathFromUrl(new URL(req.url))}`,
|
||||
formatHeader(req.headers, 'Content-Type'),
|
||||
formatHeader(req.headers, 'Connection'),
|
||||
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 z from "zod";
|
||||
import { typedZValidator } from "../../../util/validators.ts";
|
||||
import Logging from "@proxnet/undead-logging";
|
||||
|
||||
const log = new Logging("AccountDebug");
|
||||
|
||||
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 => {
|
||||
const profile = c.get('profile');
|
||||
|
||||
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 {
|
||||
|
||||
protected profile: Profile;
|
||||
protected kv: KV;
|
||||
constructor(profile: Profile, kv: KV) {
|
||||
this.profile = profile;
|
||||
this.kv = kv;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ProfileContentManager;
|
||||
@@ -2,6 +2,7 @@ import KV from "../persistence/kv.ts";
|
||||
import { ProfileRole } from "../platforms/base.ts";
|
||||
import { type ServerBase } from "../server.ts";
|
||||
import { type SignalRSocketHandler } from "../socket/signalr/socket.ts";
|
||||
import { ProfileSettingsManager } from "./content/Settings.ts";
|
||||
import ProfileManagerBase from "./manager.ts";
|
||||
import { recNetAccountSchema, SelfAccount, type RecNetAccount } from "./types/profile.ts";
|
||||
|
||||
@@ -15,19 +16,23 @@ class Profile {
|
||||
|
||||
#selfAcc: SelfAccount;
|
||||
|
||||
Settings: ProfileSettingsManager;
|
||||
|
||||
constructor(acc: SelfAccount, kv: KV, server: ServerBase) {
|
||||
this.#id = acc.accountId;
|
||||
this.#selfAcc = acc;
|
||||
this.#kv = kv;
|
||||
this.#server = server;
|
||||
|
||||
this.Settings = new ProfileSettingsManager(this, this.#kv);
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
#constructProfilePropertyKey(...keys: (string | undefined)[]) {
|
||||
constructProfilePropertyKey(...keys: (string | undefined)[]) {
|
||||
return [ ProfileManagerBase.profilesKey, this.#id, ...keys.filter(val => typeof val == 'string') ];
|
||||
}
|
||||
|
||||
@@ -51,24 +56,24 @@ class Profile {
|
||||
}
|
||||
|
||||
async getBio(){
|
||||
const key = this.#constructProfilePropertyKey('bio');
|
||||
const key = this.constructProfilePropertyKey('bio');
|
||||
const val = await this.#kv.getKv().get<string>(key);
|
||||
if (!val.value) return null;
|
||||
else return val.value;
|
||||
}
|
||||
async setBio(bio: string) {
|
||||
const key = this.#constructProfilePropertyKey('bio');
|
||||
const key = this.constructProfilePropertyKey('bio');
|
||||
await this.#kv.getKv().set(key, bio);
|
||||
}
|
||||
|
||||
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;
|
||||
else return val;
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,17 @@ export const typedZValidator = <T extends z.ZodSchema>(
|
||||
>;
|
||||
};
|
||||
|
||||
export const transformStringToEnum = <T>(anEnum: { [s: number]: string }) => {
|
||||
return (arg: string, ctx: z.RefinementCtx<string>) => {
|
||||
const int = parseInt(arg);
|
||||
if (isNaN(int)) ctx.addIssue("Must be parseable as a number");
|
||||
else {
|
||||
if (anEnum[int]) return int as T;
|
||||
else ctx.addIssue("Number must be a valid enum member");
|
||||
export const transformStringToEnum = <T>(anEnum: { [s: string]: string | number }, str?: boolean) => {
|
||||
return (arg: string, ctx: z.RefinementCtx<string | number>) => {
|
||||
if (!str) {
|
||||
const int = parseInt(arg);
|
||||
if (isNaN(int) || !Number.isSafeInteger(int)) ctx.addIssue("number was not valid");
|
||||
else if (anEnum[int]) return int as T;
|
||||
else ctx.addIssue("number was not 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