import { Instance } from "../instances/Instance.ts"; import KV from "../persistence/kv.ts"; import { PlatformMask, ProfileRole } from "../platforms/types.ts"; import { type ServerBase } from "../server.ts"; import { type SignalRSocketHandler } from "../socket/signalr/socket.ts"; import { ProfileAvatarManager } from "./content/Avatar.ts"; import ProfileContentManager from "./content/base.ts"; import { ProfileMatchmakingManager } from "./content/Matchmaking.ts"; import { ProfileMessageManager } from "./content/Messages.ts"; import { ProfileProgressionManager } from "./content/Progression.ts"; import { ProfileReputationManager } from "./content/Reputation.ts"; import { ProfileRoomsManager } from "./content/Rooms.ts"; import { ProfileSettingsManager } from "./content/Settings.ts"; import { ProfileSubscriptionsManager } from "./content/Subscriptions.ts"; import ProfileManagerBase from "./manager.ts"; import { recNetAccountSchema, SelfAccount, type RecNetAccount } from "./types/profile.ts"; import { hash, verify } from "@felix/bcrypt"; class Profile { #id: number; #kv: KV; #socket: SignalRSocketHandler | null = null; #instance: Instance | null = null; #server: ServerBase; #selfAcc: SelfAccount; managers: ProfileContentManager[] = []; Settings: ProfileSettingsManager; Avatar: ProfileAvatarManager; Matchmaking: ProfileMatchmakingManager; Reputation: ProfileReputationManager; Subscriptions: ProfileSubscriptionsManager; Messages: ProfileMessageManager; Rooms: ProfileRoomsManager; Progression: ProfileProgressionManager; constructor(acc: SelfAccount, kv: KV, server: ServerBase) { this.#id = acc.accountId; this.#selfAcc = acc; this.#kv = kv; this.#server = server; this.Settings = new ProfileSettingsManager(server, this, this.#kv); this.Avatar = new ProfileAvatarManager(server, this, this.#kv); this.Matchmaking = new ProfileMatchmakingManager(server, this, this.#kv); this.Reputation = new ProfileReputationManager(server, this, this.#kv); this.Subscriptions = new ProfileSubscriptionsManager(server, this, this.#kv); this.Messages = new ProfileMessageManager(server, this, this.#kv); this.Rooms = new ProfileRoomsManager(server, this, this.#kv); this.Progression = new ProfileProgressionManager(server, this, this.#kv); } async #saveSelfAcc() { await this.#kv.getKv().set(this.constructProfilePropertyKey(), this.#selfAcc); this.#server.emit('profile.update', { profile: this }); } constructProfilePropertyKey(...keys: (string | undefined)[]) { return [ProfileManagerBase.profilesKey, this.#id, ...keys.filter(val => typeof val == 'string')]; } getUsername() { return this.#selfAcc.username; } async setUsername(username: string) { this.#kv.getKv().delete([ProfileManagerBase.profilesKey, this.#selfAcc.username]); this.#kv.getKv().set([ProfileManagerBase.profilesKey, username], this.getId()); this.#selfAcc.username = username; await this.#saveSelfAcc(); } getDisplayName() { return this.#selfAcc.displayName; } async setDisplayName(displayName: string) { this.#selfAcc.displayName = displayName; await this.#saveSelfAcc(); } async getBio() { const key = this.constructProfilePropertyKey('bio'); const val = await this.#kv.getKv().get(key); if (!val.value) return null; else return val.value; } async setBio(bio: string) { const key = this.constructProfilePropertyKey('bio'); await this.#kv.getKv().set(key, bio); this.#server.emit('profile.update', { profile: this }); } async getRole(): Promise { const val = (await this.#kv.getKv().get(this.constructProfilePropertyKey('role'))).value; if (!val) return "gameClient"; else return val; } async setRole(role: ProfileRole) { await this.#kv.getKv().set(this.constructProfilePropertyKey('role'), role); this.#server.emit('profile.roleupdate', { profile: this, newRole: role }); } async addPlatform(type: PlatformMask) { const platforms = this.#server.Platforms.getPlatformMask(this.#selfAcc.platforms); this.#selfAcc.platforms = this.#server.Platforms.buildPlatformMask(...[...platforms, type]); await this.#saveSelfAcc(); } async removePlatform(type: PlatformMask) { const platforms = new Set(this.#server.Platforms.getPlatformMask(this.#selfAcc.platforms)); platforms.delete(type); this.#selfAcc.platforms = this.#server.Platforms.buildPlatformMask(...platforms.values().toArray()); await this.#saveSelfAcc(); } async setProfileImg(img: string) { this.#selfAcc.profileImage = img; await this.#saveSelfAcc(); } getProfileImg() { return this.#selfAcc.profileImage; } getCreationDate() { return this.#selfAcc.createdAt; } getPlatforms() { return this.#selfAcc.platforms; } getInstance() { return this.#instance; } updateInstance(inst: Instance | null) { if (inst == null) { if (this.#instance) this.#instance.removePlayer(this); this.#instance = null; return; } if (this.#instance) this.#instance.removePlayer(this); inst.addPlayer(this); this.#instance = inst; this.#server.emit('presence.update', { profile: this, presence: this.#server.Presence.getPresence(this) }); } getId() { return this.#id; } getSocketHandler() { return this.#socket; } setSocketHandler(handler: SignalRSocketHandler | null) { this.#socket = handler; } export(): RecNetAccount | null { const val = recNetAccountSchema.safeParse(this.#selfAcc); if (val.success) return val.data; else return null; } selfExport(): SelfAccount { return this.#selfAcc; } same(profile: Profile) { return profile.getId() == this.getId(); } async setPassword(pass: string) { await this.#kv.getKv().set(this.constructProfilePropertyKey("password"), await hash(pass)); } async verifyPassword(pass: string) { const hash = await this.#kv.getKv().get(this.constructProfilePropertyKey("password")); if (hash.value == null) return false; else return await verify(pass, hash.value); } } export default Profile;