import getPool from "@cocalc/database/pool" ; import { delay } from "awaiting" ; import { getLogger } from "@cocalc/backend/logger" ; import type { Action , Key } from "./types" ; import notify from "./notify" ; const logger = getLogger ( "mentions - handle" ) ; const minEmailInterval = "6 hours" ; const maxPerInterval = 50 ; const polIntervalSeconds = 15 ; export default async function init ( ) { while ( true ) { try { await handleAllMentions ( ) ; } catch ( err ) { logger . warn ( `WARNING -- error handling mentions -- ${ err }` ) ; } await delay ( polIntervalSeconds * 1000 ) ; } } async function handleAllMentions ( ) { const pool = getPool ( ) ; const { rows } = await pool . query ( "SELECT time, project_id, path, source, target, description FROM mentions WHERE action IS null" ) ; for ( const row of rows ) { const { time , project_id , path , source , target , description } = row ; try { await handleMention ( { project_id , path , time , target } , source , description ?? "" ) ; } catch ( err ) { logger . warn ( `WARNING -- error handling mention (will try later) -- ${ err }` ) ; } } } async function handleMention ( key , source , description ) { const action = await determineAction ( key ) ; try { switch ( action ) { case "ignore" : await setAction ( key , action ) ; return ; case "notify" : let whatDid = await notify ( key , source , description ) ; await setAction ( key , whatDid ) ; return ; default : throw Error ( `BUG: unknown action "${ action }"` ) ; } } catch ( err ) { await setError ( key , action , `${ err }` ) ; } } async function determineAction ( key ) { const pool = getPool ( ) ; const { rows } = await pool . query ( `SELECT COUNT(*) FROM mentions WHERE project_id=$1 AND path=$2 AND target=$3 AND action = 'email' AND time >= NOW() - INTERVAL '${ parseInt ( minEmailInterval ) }'` , [ key . project_id , key . path , key . target ] ) ; const count = parseInt ( rows [ 0 ] ?. count ?? 0 ) ; if ( count >= maxPerInterval ) { return "ignore" ; } return "notify" ; } async function setAction ( key , action ) { const pool = getPool ( ) ; await pool . query ( "UPDATE mentions SET action=$1 WHERE project_id=$2 AND path=$3 AND time=$4 AND target=$5" , [ action , key . project_id , key . path , key . time , key . target ] ) ; } async function setError ( key , action , error ) { const pool = getPool ( ) ; await pool . query ( "UPDATE mentions SET action=$1, error=$2 WHERE project_id=$3 AND path=$4 AND time=$5 AND target=$6" , [ action , error , key . project_id , key . path , key . time , key . target ] ) ; }