UNPKG

@cocalc/server

Version:

CoCalc server functionality: functions used by either the hub and the next.js server

63 lines (58 loc) 1.84 kB
/* Returns users of the sandbox that are idle. */ import getPool from "@cocalc/database/pool"; import { is_valid_uuid_string as isValid } from "@cocalc/util/misc"; export default async function idleSandboxUsers( project_id: string, idleTimeoutSeconds: number = 60 * 10 ): Promise<string[]> { if (!isValid(project_id)) { throw Error("invalid project_id"); } const pool = getPool("long"); // long cache makes sense here. const { rows } = await pool.query( `SELECT users, last_active, sandbox FROM projects WHERE project_id=$1`, [project_id] ); if (rows.length == 0) { // no such project -- nothing to do return []; } if (!rows[0].sandbox) { // not a sandbox, so nothing to do return []; } const idleUsers: string[] = []; const { users, last_active } = rows[0]; const now = new Date().valueOf(); const cutoff = now - idleTimeoutSeconds * 1000; const addToLastActive: string[] = []; // these got added to sandbox but no activity being tracked yet, so we initialize it. for (const account_id in users ?? {}) { const active = new Date(last_active?.[account_id] ?? 0).valueOf(); if (!active) { addToLastActive.push(account_id); } else if (active <= cutoff && users[account_id]?.["group"] != "owner") { idleUsers.push(account_id); } } if (addToLastActive.length > 0) { await updateLastActive(project_id, addToLastActive); } return idleUsers; } async function updateLastActive( project_id: string, users: string[] ): Promise<void> { const pool = getPool(); const now = new Date(); const X: any = {}; for (const account_id of users) { X[account_id] = now; } await pool.query( `UPDATE projects SET last_active = COALESCE(last_active, '{}') || '${JSON.stringify( X )}' WHERE project_id=$1`, [project_id] ); }