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));
+}