143 lines
5.6 KiB
TypeScript
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; |