Files
aaaa/src/server/profiles/profile.ts
2025-09-11 19:47:33 -04:00

191 lines
6.5 KiB
TypeScript

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<string>(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<ProfileRole> {
const val = (await this.#kv.getKv().get<ProfileRole>(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<string>(this.constructProfilePropertyKey("password"));
if (hash.value == null) return false;
else return await verify(pass, hash.value);
}
}
export default Profile;