Files
galvanic-corrosion-rewrite/src/server/profiles/manager.ts
zombieb f19552929e galvanic corrosion rewrite
commit this before something goes horribly wrong
2025-08-12 21:04:52 -04:00

143 lines
5.6 KiB
TypeScript

import { ServerContentBase } from "../ContentBase.ts";
import NameDictionary from "./dict.ts";
import Profile from "./profile.ts";
import { SelfAccount, type RecNetAccount } from "./types/profile.ts";
import Command from "./../commands/command.ts";
import z from "zod";
import { PlatformMask, PlatformType, ProfileRole } from "../platforms/types.ts";
const profiles: Map<number, Profile> = new Map();
class ProfileManagerBase extends ServerContentBase {
static profilesKey = "profiles";
static profileByNameKey = "profileName";
async #getUnusedId() {
let id = Math.round(Math.random() * 2_147_483_647);
if (await this.get(id)) id = await this.#getUnusedId();
return id;
}
getActiveProfileReferences() {
return profiles.values().toArray();
}
async #getUnusedUsername() {
const adjective = NameDictionary.Adjectives[Math.floor(Math.random() * NameDictionary.Adjectives.length)];
const noun = NameDictionary.Nouns[Math.floor(Math.random() * NameDictionary.Nouns.length)];
const discriminator = Math.round(Math.random() * 1000);
let username = `${adjective}${noun}#${discriminator}`;
if (await this.getByUsername(username)) username = await this.#getUnusedUsername();
return username;
}
async #getUsernameDefault(username: string) {
const prof = await this.getByUsername(username);
if (!prof) return username;
else return await this.#getUnusedUsername();
}
async create(platform: PlatformType, platformId: string, username?: string) {
const id = await this.#getUnusedId();
const newUsername = username ? await this.#getUsernameDefault(username) : await this.#getUnusedUsername();
const newProfile: RecNetAccount = {
accountId: id,
username: newUsername,
displayName: newUsername,
platforms: PlatformMask.None,
profileImage: "DefaultProfileImage.png",
createdAt: new Date()
}
await this.kv.getKv().set([ ProfileManagerBase.profilesKey, id ], newProfile);
await this.kv.getKv().set([ ProfileManagerBase.profilesKey, newUsername ], id);
await this.server.Platforms.addCachedLogin(platform, platformId, id);
return this.get(id);
}
async get(id: number) {
const profile = profiles.get(id);
if (!profile) {
const info = await this.kv.getKv().get<SelfAccount>([ ProfileManagerBase.profilesKey, id ]);
if (!info.value) return null;
const prof = new Profile(info.value, this.kv, this.server);
profiles.set(id, prof);
return prof;
}
return profile;
}
async getMany(...ids: number[]) {
return (await Promise.all(ids.map(id => this.get(id)))).filter(prof => prof !== null);
}
async getAll() {
const keys = this.kv.getKv().list({ prefix: [ ProfileManagerBase.profilesKey ] });
const awaitedKeys = await Array.fromAsync(keys);
return awaitedKeys.map(entry => entry.key).map(val => val[1]).filter(val => typeof val == 'number');
}
async getByUsername(username: string) {
const id = (await this.kv.getKv().get<number>([ ProfileManagerBase.profilesKey, username ])).value;
if (typeof id == 'number') return this.get(id);
else return id;
}
override start() {
this.server.Commands.addRootCommand(new Command({
key: ['account', 'profile', 'acc', 'prof'],
subcommands: [
new Command({
key: ['get', 'g', 'fetch', 'f'],
exec: async (id: number) => {
const prof = await this.get(id);
if (!prof) return prof;
else return await prof.export();
},
zod: z.tuple([
z.string().transform(Number)
]),
help: 'Fetch a profile: <id: number>'
}),
new Command({
key: ['getall', 'listall', 'fetchall', 'all', 'a'],
exec: async () => {
const ids = await this.getAll();
return ids;
},
zod: z.tuple([]),
help: 'Fetch all profile IDs'
}),
new Command({
key: ['getrole', 'gr'],
exec: async (id: number) => {
const profile = await this.get(id);
if (!profile) return new Error("No such profile");
else return await profile.getRole();
},
zod: z.tuple([
z.string().transform(Number)
]),
help: 'Set the profile role: <id: number>'
}),
new Command({
key: ['setrole', 'sr'],
exec: async (id: number, role: ProfileRole) => {
const profile = await this.get(id);
if (!profile) return new Error("No such profile");
else return await profile.setRole(role);
},
zod: z.tuple([
z.string().transform(Number),
z.string()
]),
help: 'Set the profile role: <id: number, role: "developer" | "moderator" | "screenshare" | "user">'
})
]
}));
}
}
export default ProfileManagerBase;