Some code was converting the customs object to an array with millions of elements, which caused iteration and ipc transport (json serialize) to hang the client for many minutes at a time. This is probably because incorrect lodash functions were used on the customs. Lodash would convert it to array and then it would get stored and turn up as array every time, corrupting storage and ensuring client denial of service. This fixes that bug by avoiding using incorrect lodash functions that convert things to arrays with millions of elements. It also retroactively fixes profiles that were stored with array customs, so the client won't crash.
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
import {Character as ComplexCharacter, CharacterGroup, Guestbook} from '../../site/character_page/interfaces';
|
|
import { PermanentIndexedStore, ProfileRecord } from './types';
|
|
import { CharacterImage, SimpleCharacter } from '../../interfaces';
|
|
|
|
import { WorkerClient } from './worker/client';
|
|
|
|
|
|
export class WorkerStore implements PermanentIndexedStore {
|
|
// @ts-ignore
|
|
private _isVue = true;
|
|
|
|
protected readonly workerClient: WorkerClient;
|
|
|
|
constructor(jsEndpointFile: string) {
|
|
this.workerClient = new WorkerClient(jsEndpointFile);
|
|
}
|
|
|
|
|
|
static async open(jsEndpointFile: string, dbName?: string): Promise<WorkerStore> {
|
|
const store = new WorkerStore(jsEndpointFile);
|
|
|
|
await store.workerClient.request('init', { dbName });
|
|
|
|
return store;
|
|
}
|
|
|
|
|
|
async getProfile(name: string): Promise<ProfileRecord | undefined> {
|
|
const record: ProfileRecord | undefined = await this.workerClient.request('get', { name });
|
|
|
|
// fix custom kinks to prevent hangs
|
|
|
|
if (record && Array.isArray(record.profileData.character.customs)) {
|
|
// fix customs because it will crash the client
|
|
const customsObject: ProfileRecord['profileData']['character']['customs'] = {};
|
|
|
|
for (const [key, value] of Object.entries(record.profileData.character.customs)) {
|
|
if (value !== undefined) customsObject[key] = value;
|
|
}
|
|
|
|
record.profileData.character.customs = customsObject;
|
|
}
|
|
|
|
return record;
|
|
}
|
|
|
|
|
|
async storeProfile(character: ComplexCharacter): Promise<void> {
|
|
return this.workerClient.request('store', { character });
|
|
}
|
|
|
|
|
|
async updateProfileMeta(
|
|
name: string,
|
|
images: CharacterImage[] | null,
|
|
guestbook: Guestbook | null,
|
|
friends: SimpleCharacter[] | null,
|
|
groups: CharacterGroup[] | null
|
|
): Promise<void> {
|
|
return this.workerClient.request('update-meta', { name, images, guestbook, friends, groups });
|
|
}
|
|
|
|
async start(): Promise<void> {
|
|
return this.workerClient.request('start');
|
|
}
|
|
|
|
async stop(): Promise<void> {
|
|
return this.workerClient.request('stop');
|
|
}
|
|
|
|
|
|
async flushProfiles(daysToExpire: number): Promise<void> {
|
|
return this.workerClient.request('flush', { daysToExpire });
|
|
}
|
|
}
|