refactor: Move slowmodes from the client to the channel (#180)

* refactor: Move slowmodes from the client to the channel

Signed-off-by: Jacob Schlecht <dadadah@echoha.us>

* fix: Format and lint

Signed-off-by: Jacob Schlecht <dadadah@echoha.us>

---------

Signed-off-by: Jacob Schlecht <dadadah@echoha.us>
This commit is contained in:
Jacob Schlecht
2026-08-06 22:32:32 -06:00
committed by GitHub
parent 33e526aa10
commit e90a1496f7
4 changed files with 30 additions and 23 deletions
+1 -20
View File
@@ -1,7 +1,6 @@
import type { Accessor, Setter } from "solid-js";
import { batch, createSignal } from "solid-js";
import { ReactiveMap } from "@solid-primitives/map";
import { AsyncEventEmitter } from "@vladfrangu/async_event_emitter";
import { API } from "stoat-api";
import type { DataLogin, Error, RevoltConfig, Role } from "stoat-api";
@@ -28,7 +27,7 @@ import {
EventClient,
type EventClientOptions,
} from "./events/EventClient.js";
import { ProtocolV1, UserSlowmodes, handleEvent } from "./events/v1.js";
import { ProtocolV1, handleEvent } from "./events/v1.js";
import type { HydratedChannel } from "./hydration/channel.js";
import type { HydratedEmoji } from "./hydration/emoji.js";
import type { HydratedMessage } from "./hydration/message.js";
@@ -183,7 +182,6 @@ export class Client extends AsyncEventEmitter<Events> {
readonly serverMembers;
readonly sessions;
readonly users;
readonly userSlowmodes;
readonly api: API;
readonly options: ClientOptions;
@@ -203,7 +201,6 @@ export class Client extends AsyncEventEmitter<Events> {
readonly connectionFailureCount: Accessor<number>;
#setConnectionFailureCount: Setter<number>;
#reconnectTimeout: number | undefined;
#slowmodeTimers = new Map<string, ReturnType<typeof setTimeout>>();
/**
* Create Stoat.js Client
@@ -278,7 +275,6 @@ export class Client extends AsyncEventEmitter<Events> {
this.serverMembers = new ServerMemberCollection(this);
this.sessions = new SessionCollection(this);
this.users = new UserCollection(this);
this.userSlowmodes = new ReactiveMap<string, UserSlowmodes>();
this.events = new EventClient(1, "json", this.options);
this.events.on("error", (error) => this.emit("error", error));
@@ -611,21 +607,6 @@ export class Client extends AsyncEventEmitter<Events> {
return data.id;
}
setSlowmode(channelId: string, data: UserSlowmodes): void {
const existing = this.#slowmodeTimers.get(channelId);
if (existing) clearTimeout(existing);
this.userSlowmodes.set(channelId, { ...data, receivedAt: Date.now() });
const timer = setTimeout(() => {
this.userSlowmodes.delete(channelId);
this.#slowmodeTimers.delete(channelId);
this.emit("userSlowmodes");
}, data.retry_after * 1000);
this.#slowmodeTimers.set(channelId, timer);
}
/**
* Backend enforced limits for the logged in user
*/
+24 -1
View File
@@ -1,4 +1,4 @@
import { batch } from "solid-js";
import { Accessor, Setter, batch, createSignal } from "solid-js";
import { ReactiveMap } from "@solid-primitives/map";
import type { ReactiveSet } from "@solid-primitives/set";
@@ -17,6 +17,7 @@ import type { APIRoutes } from "stoat-api";
import { decodeTime, ulid } from "ulid";
import { ChannelCollection } from "../collections/index.js";
import { UserSlowmodes } from "../events/v1.js";
import { hydrate } from "../hydration/index.js";
import {
bitwiseAndEq,
@@ -43,6 +44,10 @@ export class Channel {
voiceParticipants = new ReactiveMap<string, VoiceParticipant>();
readonly userSlowmode: Accessor<UserSlowmodes | undefined>;
readonly #setUserSlowmode: Setter<UserSlowmodes | undefined>;
#slowmodeTimeout: NodeJS.Timeout | undefined;
/**
* Construct Channel
* @param collection Collection
@@ -51,6 +56,10 @@ export class Channel {
constructor(collection: ChannelCollection, id: string) {
this.#collection = collection;
this.id = id;
const [slowmode, setSlowmode] = createSignal<UserSlowmodes | undefined>();
this.userSlowmode = slowmode;
this.#setUserSlowmode = setSlowmode;
}
/**
@@ -874,4 +883,18 @@ export class Channel {
return highest;
}
setUserSlowmode(slowmode: UserSlowmodes) {
if (this.#slowmodeTimeout) {
clearTimeout(this.#slowmodeTimeout);
}
this.#setUserSlowmode({ ...slowmode, receivedAt: Date.now() });
this.#slowmodeTimeout = setTimeout(() => {
this.#setUserSlowmode();
this.#slowmodeTimeout = undefined;
this.#collection.client.emit("userSlowmodes");
}, slowmode.retry_after * 1000);
}
}
+1 -1
View File
@@ -125,7 +125,7 @@ export class AccountCollection {
email: newEmail,
current_password: currentPassword,
},
ticket ? { headers: { "X-MFA-Ticket": ticket.token } } : undefined
ticket ? { headers: { "X-MFA-Ticket": ticket.token } } : undefined,
);
}
+4 -1
View File
@@ -1006,7 +1006,10 @@ export async function handleEvent(
}
case "UserSlowmodes": {
for (const slowmode of event.slowmodes) {
client.setSlowmode(slowmode.channel_id, slowmode);
const channel = client.channels.getOrPartial(slowmode.channel_id);
if (channel) {
channel.setUserSlowmode(slowmode);
}
}
client.emit("userSlowmodes");
break;