'use strict' const cfg = require('./config') const { log, json, parseBody } = require('./helpers') let routrPool = null, identityPool = null function getPool (connStr, label) { const { Pool } = require('pg') const pool = new Pool({ connectionString: connStr, max: 3 }) pool.on('error', e => log(`${label} DB pool error:`, e.message)) return pool } function getRoutrPool () { return routrPool || (routrPool = getPool(cfg.ROUTR_DB_URL, 'Routr')) } function getIdentityPool () { return identityPool || (identityPool = getPool(cfg.FNIDENTITY_DB_URL, 'Identity')) } const ROUTR_TABLES = { trunks: 'trunks', agents: 'agents', credentials: 'credentials', numbers: 'numbers', domains: 'domains', acls: 'access_control_lists', peers: 'peers' } const IDENTITY_TABLES = { workspaces: 'workspaces', users: 'users' } async function handle (req, res, method, path, url) { try { const parts = path.replace('/telephony/', '').split('/').filter(Boolean) const resource = parts[0], ref = parts[1] || null if (resource === 'overview' && method === 'GET') { const rPool = getRoutrPool(), iPool = getIdentityPool() const [trunks, agents, creds, numbers, domains, peers, workspaces] = await Promise.all([ rPool.query('SELECT COUNT(*) FROM trunks'), rPool.query('SELECT COUNT(*) FROM agents'), rPool.query('SELECT COUNT(*) FROM credentials'), rPool.query('SELECT COUNT(*) FROM numbers'), rPool.query('SELECT COUNT(*) FROM domains'), rPool.query('SELECT COUNT(*) FROM peers'), iPool.query('SELECT COUNT(*) FROM workspaces'), ]) return json(res, 200, { trunks: +trunks.rows[0].count, agents: +agents.rows[0].count, credentials: +creds.rows[0].count, numbers: +numbers.rows[0].count, domains: +domains.rows[0].count, peers: +peers.rows[0].count, workspaces: +workspaces.rows[0].count, }) } const isIdentity = !!IDENTITY_TABLES[resource] const tableName = IDENTITY_TABLES[resource] || ROUTR_TABLES[resource] if (!tableName) { return json(res, 404, { error: `Unknown resource: ${resource}. Available: overview, ${[...Object.keys(ROUTR_TABLES), ...Object.keys(IDENTITY_TABLES)].join(', ')}` }) } const pool = isIdentity ? getIdentityPool() : getRoutrPool() if (method === 'GET' && !ref) { const limit = parseInt(url.searchParams.get('limit') || '100', 10) const offset = parseInt(url.searchParams.get('offset') || '0', 10) const result = await pool.query(`SELECT * FROM ${tableName} ORDER BY created_at DESC LIMIT $1 OFFSET $2`, [limit, offset]) const count = await pool.query(`SELECT COUNT(*) FROM ${tableName}`) return json(res, 200, { items: result.rows, total: +count.rows[0].count }) } if (method === 'GET' && ref) { const result = await pool.query(`SELECT * FROM ${tableName} WHERE ref = $1`, [ref]) return result.rows.length ? json(res, 200, result.rows[0]) : json(res, 404, { error: 'Not found' }) } if (method === 'POST' && !ref) { const body = await parseBody(req) if (!body.ref) body.ref = require('crypto').randomUUID() if (!body.api_version) body.api_version = 'v2' if (!body.created_at) body.created_at = new Date() if (!body.updated_at) body.updated_at = new Date() const keys = Object.keys(body), vals = Object.values(body) const result = await pool.query(`INSERT INTO ${tableName} (${keys.join(', ')}) VALUES (${keys.map((_, i) => `$${i + 1}`).join(', ')}) RETURNING *`, vals) log(`Telephony: created ${resource}/${result.rows[0].ref}`) return json(res, 201, result.rows[0]) } if (method === 'PUT' && ref) { const body = await parseBody(req) body.updated_at = new Date(); delete body.ref; delete body.created_at const keys = Object.keys(body), vals = Object.values(body) vals.push(ref) const result = await pool.query(`UPDATE ${tableName} SET ${keys.map((k, i) => `${k} = $${i + 1}`).join(', ')} WHERE ref = $${vals.length} RETURNING *`, vals) if (!result.rows.length) return json(res, 404, { error: 'Not found' }) log(`Telephony: updated ${resource}/${ref}`) return json(res, 200, result.rows[0]) } if (method === 'DELETE' && ref) { const result = await pool.query(`DELETE FROM ${tableName} WHERE ref = $1 RETURNING ref`, [ref]) if (!result.rows.length) return json(res, 404, { error: 'Not found' }) log(`Telephony: deleted ${resource}/${ref}`) return json(res, 200, { ok: true, deleted: ref }) } return json(res, 405, { error: 'Method not allowed' }) } catch (e) { log('Telephony error:', e.message) return json(res, 500, { error: e.message }) } } module.exports = { handle }