Spaces:
Sleeping
Sleeping
/** | |
* Storage handling for offline PMs. | |
* By Mia. | |
* @author mia-pi-git | |
*/ | |
import { type SQL, FS } from '../../lib'; | |
import { MAX_PENDING } from '.'; | |
export const statements = { | |
send: 'INSERT INTO offline_pms (sender, receiver, message, time) VALUES (?, ?, ?, ?)', | |
clear: 'DELETE FROM offline_pms WHERE receiver = ?', | |
fetch: 'SELECT * FROM offline_pms WHERE receiver = ?', | |
fetchNew: 'SELECT * FROM offline_pms WHERE receiver = ? AND seen IS NULL', | |
clearDated: 'DELETE FROM offline_pms WHERE ? - time >= ?', | |
checkSentCount: 'SELECT count(*) as count FROM offline_pms WHERE sender = ? AND receiver = ?', | |
setSeen: 'UPDATE offline_pms SET seen = ? WHERE receiver = ? AND seen IS NULL', | |
clearSeen: 'DELETE FROM offline_pms WHERE ? - seen >= ?', | |
getSettings: 'SELECT * FROM pm_settings WHERE userid = ?', | |
setBlock: 'REPLACE INTO pm_settings (userid, view_only) VALUES (?, ?)', | |
deleteSettings: 'DELETE FROM pm_settings WHERE userid = ?', | |
} as const; | |
type Statement = keyof typeof statements; | |
class StatementMap { | |
env: SQL.TransactionEnvironment; | |
constructor(env: SQL.TransactionEnvironment) { | |
this.env = env; | |
} | |
run(name: Statement, args: any[] | AnyObject) { | |
return this.getStatement(name).run(args); | |
} | |
all(name: Statement, args: any[] | AnyObject) { | |
return this.getStatement(name).all(args); | |
} | |
get(name: Statement, args: any[] | AnyObject) { | |
return this.getStatement(name).get(args); | |
} | |
getStatement(name: Statement) { | |
const source = statements[name]; | |
return this.env.statements.get(source)!; | |
} | |
} | |
export const transactions: { | |
[k: string]: (args: any[], env: SQL.TransactionEnvironment) => any, | |
} = { | |
send: (args, env) => { | |
const statementList = new StatementMap(env); | |
const [sender, receiver, message] = args; | |
const count = statementList.get('checkSentCount', [sender, receiver])?.count; | |
if (count && count > MAX_PENDING) { | |
return { error: `You have already sent the maximum ${MAX_PENDING} offline PMs to that user.` }; | |
} | |
return statementList.run('send', [sender, receiver, message, Date.now()]); | |
}, | |
listNew: (args, env) => { | |
const list = new StatementMap(env); | |
const [receiver] = args; | |
const pms = list.all('fetchNew', [receiver]); | |
list.run('setSeen', [Date.now(), receiver]); | |
return pms; | |
}, | |
}; | |
export function onDatabaseStart(database: import('better-sqlite3').Database) { | |
let version; | |
try { | |
version = database.prepare('SELECT * FROM db_info').get().version; | |
} catch { | |
const schemaContent = FS('databases/schemas/pms.sql').readSync(); | |
database.exec(schemaContent); | |
} | |
const migrations = FS('databases/migrations/pms').readdirIfExistsSync(); | |
if (version !== migrations.length) { | |
for (const migration of migrations) { | |
const num = /(\d+)\.sql$/.exec(migration)?.[1]; | |
if (!num || version >= num) continue; | |
database.exec('BEGIN TRANSACTION'); | |
try { | |
database.exec(FS(`databases/migrations/pms/${migration}`).readSync()); | |
} catch (e: any) { | |
console.log(`Error in PM migration ${migration} - ${e.message}`); | |
console.log(e.stack); | |
database.exec('ROLLBACK'); | |
continue; | |
} | |
database.exec('COMMIT'); | |
} | |
} | |
} | |