diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index 679424f34..25a33f069 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -16,7 +16,7 @@ along with this program. If not, see . */ -import { arrayDistinctBy, arrayGroupBy, Config, EmbedCache, emitEvent, Message, MessageUpdateEvent, normalizeUrl, OrmUtils } from "@spacebar/util"; +import { arrayDistinctBy, arrayGroupBy, Config, EmbedCache, emitEvent, Message, MessageUpdateEvent, normalizeUrl, OrmUtils, sleep } from "@spacebar/util"; import { Embed, EmbedImage, EmbedType } from "@spacebar/schemas"; import * as cheerio from "cheerio"; import crypto from "crypto"; @@ -572,10 +572,6 @@ export async function dropDuplicateCacheEntries(entries: EmbedCache[]): Promise< ); } -async function sleep(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - // hack to make nodejs not die function getSlowdownFactor(off: number) { if (off < 10) return off; diff --git a/src/gateway/util/Utils.ts b/src/gateway/util/Utils.ts index c54c4980a..ebf7ae023 100644 --- a/src/gateway/util/Utils.ts +++ b/src/gateway/util/Utils.ts @@ -1,4 +1,4 @@ -import { Event, VoiceState } from "@spacebar/util"; +import { Event, Session, sleep, TimeSpan, VoiceState } from "@spacebar/util"; import { WebSocket } from "./WebSocket"; import { OPCODES } from "./Constants"; import { Send } from "./Send"; @@ -60,6 +60,21 @@ export async function cleanupOnStartup(): Promise { VoiceState.clear() .then(() => console.log("[Gateway] Successfully cleaned voice states")) .catch((e) => console.error("[Gateway] Error cleaning voice states on startup:", e)); + + console.log("[Gateway] Starting async presence expiry..."); + expireOldPresenceStates() + .then(() => console.log("[Gateway] Successfully cleaned expired presence states")) + .catch((e) => console.error("[Gateway] Error cleaning expired presence states on startup:", e)); +} + +async function expireOldPresenceStates() { + for await (const session of await Session.createQueryBuilder("session").where("last_seen >= '2000/01/01' AND status != 'offline'").select().stream()) { + // session object has all fields prefixed with `session_`... thanks typeorm + if (TimeSpan.fromDates((session.session_last_seen as Date).getTime(), new Date().getTime()).totalMinutes > 30) { + console.log(`[Gateway/util/Utils.ts] Expiring presence for session ${session.session_session_id} last seen at ${session.session_last_seen}`); + await Session.update({ session_id: session.session_session_id }, { status: "offline" }); + } + } } export async function handleOffloadedGatewayRequest(socket: WebSocket, url: string, body: unknown) { diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts index 8bd45bcbd..601fb275b 100644 --- a/src/util/util/Token.ts +++ b/src/util/util/Token.ts @@ -96,21 +96,6 @@ export const checkToken = ( return rejectAndLog(reject, 401, "User not found"); } - if (decoded.did && !session) { - // temporary hack: create new session - session = Session.create({ - session_id: decoded.did, - user_id: user.id, - is_admin_session: false, - client_status: {}, - status: "online", - client_info: {}, - }); - await session.save(); - logAuth("validateUser rejected: Session not found"); - return rejectAndLog(reject, 401, "Invalid Token"); - } - // we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds if (decoded.iat * 1000 < new Date(user.data.valid_tokens_since).setSeconds(0, 0)) { logAuth("validateUser rejected: Token not yet valid"); @@ -183,7 +168,7 @@ export async function generateToken(id: string, isAdminSession: boolean = false) user_id: id, is_admin_session: isAdminSession, client_status: {}, - status: "online", + status: "offline", // will be set to online upon IDENTIFY client_info: {}, }); } while (await Session.findOne({ where: { session_id: newSession.session_id } })); diff --git a/src/util/util/extensions/index.ts b/src/util/util/extensions/index.ts index e1946bb38..0ec969f4a 100644 --- a/src/util/util/extensions/index.ts +++ b/src/util/util/extensions/index.ts @@ -1 +1,6 @@ export * from "./Array"; + +// TODO: move to a separate file +export async function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +}