import knex from "knex"; import knexConfig from "./db"; import { Sonar, gql } from "./sonar"; import { SDK } from "@ringcentral/sdk"; import { ticketize } from "./ticketize"; function checkEnv() { [ "SONAR_URL", "SONAR_TOKEN", "RC_APP_KEY", "RC_APP_SECRET", "RC_LOGIN_USERNAME", "RC_LOGIN_EXT", "RC_LOGIN_PASSWORD", "EXTENSION_TICKET_GROUPS", ].forEach((env) => { if (process.env[env] === undefined) { throw new Error(`${env} environment variable is not set.`); } }); } function getExtensionToTicketGroupMapping() { const mapping: { [key: string]: number } = {}; process.env.EXTENSION_TICKET_GROUPS!.split(",").forEach((entry) => { const [extension, ticketGroupId] = entry.split(":"); mapping[extension] = parseInt(ticketGroupId); }); return mapping; } const DEFAULT_FIRST_RUN_AGE = 86400; function getTicketizeConfig() { const firstRunAge = process.env.FIRST_RUN_AGE ? parseInt(process.env.FIRST_RUN_AGE) : DEFAULT_FIRST_RUN_AGE; if (isNaN(firstRunAge) || firstRunAge <= 0) { throw new Error("FIRST_RUN_AGE must be a valid positive integer"); } return { firstRunAge, extensionToTicketGroup: getExtensionToTicketGroupMapping(), }; } async function initSonar() { const sonar = new Sonar(process.env.SONAR_URL!, process.env.SONAR_TOKEN!); // simple query to test API cedentials const user = await sonar.request( gql` { me { name } } ` ); console.log(`Authenticated to Sonar as '${user.me.name}'.`); return sonar; } async function initRingCentralSDK() { const sdk = new SDK({ server: SDK.server[process.env.RC_SANDBOX ? "sandbox" : "production"], clientId: process.env.RC_APP_KEY, clientSecret: process.env.RC_APP_SECRET, }); const login = () => sdk.login({ username: process.env.RC_LOGIN_USERNAME, extension: process.env.RC_LOGIN_EXT, password: process.env.RC_LOGIN_PASSWORD, }); const platform = sdk.platform(); platform.on(platform.events.refreshError, async (err) => { console.error("Refresh token error:", err); await login(); console.log("RingCentral re-authentication successful."); }); await login(); console.log("Authenticated to RingCentral."); return sdk; } async function initDB() { const db = knex(knexConfig); if (!process.env.DB_SKIP_MIGRATIONS) { await db.migrate.latest(); console.log("Database migrations run successfully."); } return db; } async function main() { try { checkEnv(); const sonar = await initSonar(); const rcsdk = await initRingCentralSDK(); const db = await initDB(); console.log("Starting ticketizer..."); const intervals = ticketize(sonar, rcsdk, db, getTicketizeConfig()); ["SIGINT", "SIGTERM", "SIGQUIT"].forEach((sig) => { process.on(sig, async () => { console.log(`\nCaught ${sig}, shutting down...`); const results = await Promise.allSettled( intervals.map((interval) => interval.clear()) ); let errors = false; results.forEach((result) => { if (result.status === "rejected") { errors = true; console.error(result.reason); } }); console.log("exiting now"); process.exit(errors ? 1 : 0); }); }); } catch (err) { console.error(err); } } main();