Replace all async reads and writes to the JSON database with the sync reads and writes to prevent a data corruption race condition where two requests are processed at the same time and write to the same file, or one reads while the other writes causing read of partially written data.
64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
/*
|
|
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
|
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
import {
|
|
readUsers, readSessions, readSubscriptions,
|
|
writeUsers, writeSessions, writeSubscriptions,
|
|
nextEventId,
|
|
} from "~/server/database";
|
|
import { broadcastEvent, cancelAccountStreams } from "~/server/streams";
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const serverSession = await requireServerSessionWithUser(event);
|
|
let users = readUsers();
|
|
|
|
// Expire sessions for this user
|
|
const expiredSessionIds = new Set<number>();
|
|
let sessions = readSessions();
|
|
const nowMs = Date.now();
|
|
for (const session of sessions) {
|
|
if (
|
|
session.successor !== undefined
|
|
&& (session.expiresAtMs === undefined || session.expiresAtMs < nowMs)
|
|
&& session.accountId === serverSession.accountId
|
|
) {
|
|
session.expiresAtMs = nowMs;
|
|
broadcastEvent({
|
|
id: nextEventId(),
|
|
type: "session-expired",
|
|
sessionId: session.id,
|
|
});
|
|
expiredSessionIds.add(session.id);
|
|
}
|
|
}
|
|
cancelAccountStreams(serverSession.accountId);
|
|
writeSessions(sessions);
|
|
await deleteCookie(event, "session");
|
|
|
|
// Remove subscriptions for this user
|
|
let subscriptions = readSubscriptions();
|
|
subscriptions = subscriptions.filter(
|
|
subscription => !expiredSessionIds.has(subscription.sessionId)
|
|
);
|
|
writeSubscriptions(subscriptions);
|
|
|
|
// Remove the user
|
|
const account = users.find(user => user.id === serverSession.accountId)!;
|
|
const now = new Date(nowMs).toISOString();
|
|
account.deleted = true;
|
|
account.updatedAt = now;
|
|
writeUsers(users);
|
|
await broadcastEvent({
|
|
id: nextEventId(),
|
|
type: "user-update",
|
|
data: {
|
|
id: account.id,
|
|
updatedAt: now,
|
|
deleted: true,
|
|
}
|
|
});
|
|
|
|
// Update Schedule counts.
|
|
await updateScheduleInterestedCounts(users);
|
|
})
|