Skip to content

Commit 7ee0912

Browse files
authored
fix: Race condition on init & add method for overriding config options (#172)
* fix: Race condition on init & add method for overriding config options before configured() is set Signed-off-by: Pecacheu <3608878+Pecacheu@users.noreply.github.com> * fix: Cleanup lock when finished Signed-off-by: Pecacheu <3608878+Pecacheu@users.noreply.github.com> * fix: Improve comments Signed-off-by: Pecacheu <3608878+Pecacheu@users.noreply.github.com> * fix: Add config param to preConfig Signed-off-by: Pecacheu <3608878+Pecacheu@users.noreply.github.com> --------- Signed-off-by: Pecacheu <3608878+Pecacheu@users.noreply.github.com>
1 parent 30b8505 commit 7ee0912

1 file changed

Lines changed: 27 additions & 15 deletions

File tree

src/Client.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ export class Client extends AsyncEventEmitter<Events> {
189189
readonly options: ClientOptions;
190190
readonly events: EventClient<1>;
191191

192-
configuration: RevoltConfig | undefined;
192+
readonly configuration: RevoltConfig | undefined;
193+
#configLock?: Promise<void>;
193194
#session: Session | undefined;
194195
user: User | undefined;
195196

@@ -203,8 +204,10 @@ export class Client extends AsyncEventEmitter<Events> {
203204
#setConnectionFailureCount: Setter<number>;
204205
#reconnectTimeout: number | undefined;
205206
#slowmodeTimers = new Map<string, ReturnType<typeof setTimeout>>();
207+
206208
/**
207209
* Create Stoat.js Client
210+
* @param configuration Deprecated - Please use `Client.initConfig` if you need to override config.
208211
*/
209212
constructor(options?: Partial<ClientOptions>, configuration?: RevoltConfig) {
210213
super();
@@ -256,8 +259,6 @@ export class Client extends AsyncEventEmitter<Events> {
256259
this.configured = configured;
257260
this.#setConfigured = setConfigured;
258261

259-
this.#fetchConfiguration();
260-
261262
const [ready, setReady] = createSignal(false);
262263
this.ready = ready;
263264
this.#setReady = setReady;
@@ -343,13 +344,28 @@ export class Client extends AsyncEventEmitter<Events> {
343344
}
344345

345346
/**
346-
* Fetches the configuration of the server if it has not been already fetched.
347+
* Fetches the server config. This is called automatically by `login()` or `loginBot()`,
348+
* but you can call it first manually if you need to override any config options.
349+
*
350+
* Override example:
351+
* ```ts
352+
* await client.initConfig((config) => {
353+
* config.ws = "wss://example.com";
354+
* });
355+
* ```
347356
*/
348-
async #fetchConfiguration(): Promise<void> {
349-
if (!this.configuration) {
350-
this.configuration = await this.api.get("/");
351-
this.#setConfigured(true);
357+
async initConfig(preConfig?: (config: RevoltConfig) => void): Promise<void> {
358+
if (!this.#configLock && !this.configuration) {
359+
//Create promise lock to avoid race condition
360+
this.#configLock = (async () => {
361+
//@ts-expect-error readonly override
362+
this.configuration = await this.api.get("/");
363+
preConfig?.(this.configuration);
364+
this.#setConfigured(true);
365+
this.#configLock = undefined;
366+
})();
352367
}
368+
return this.#configLock;
353369
}
354370

355371
/**
@@ -370,7 +386,7 @@ export class Client extends AsyncEventEmitter<Events> {
370386
* @returns An on-boarding function if on-boarding is required, undefined otherwise
371387
*/
372388
async login(details: DataLogin): Promise<void> {
373-
await this.#fetchConfiguration();
389+
await this.initConfig();
374390
const data = await this.api.post("/auth/session/login", details);
375391
if (data.result === "Success") {
376392
this.#session = data;
@@ -393,7 +409,7 @@ export class Client extends AsyncEventEmitter<Events> {
393409
* @param token Bot token
394410
*/
395411
async loginBot(token: string): Promise<void> {
396-
await this.#fetchConfiguration();
412+
await this.initConfig();
397413
this.#session = token;
398414
this.#updateHeaders();
399415
this.connect();
@@ -614,10 +630,6 @@ export class Client extends AsyncEventEmitter<Events> {
614630
* Backend enforced limits for the logged in user
615631
*/
616632
get limits(): UserLimits | undefined {
617-
if (!this.configured() || !this.user) {
618-
return;
619-
}
620-
621-
return this.user.limits;
633+
if (this.configured() && this.user) return this.user.limits;
622634
}
623635
}

0 commit comments

Comments
 (0)