forked from LiteNet/freepbx-stats
219 lines
7.7 KiB
JavaScript
219 lines
7.7 KiB
JavaScript
require("dotenv").config();
|
|
const cron = require("node-cron");
|
|
const os = require("os");
|
|
const Discord = require('discord.js');
|
|
const mysql = require('mysql');
|
|
const { TimeSpan } = require("./timeSpan");
|
|
const { DateBuilder } = require("./dateBuilder");
|
|
const { CallStats } = require("./callStats");
|
|
const { CallRecord, Records } = require("./records");
|
|
const fs = require('fs').promises;
|
|
const fsSync = require('fs');
|
|
|
|
const hook = !!process.env.DISCORD_WEBHOOK_URL ? new Discord.WebhookClient({ url: process.env.DISCORD_WEBHOOK_URL }) : null;
|
|
|
|
const JSON_FILE = process.env.JSON_FILE || "records.json";
|
|
const records = fsSync.existsSync(JSON_FILE) ? Records.fromJSONFile(JSON_FILE) : new Records();
|
|
|
|
function getYesterday() {
|
|
return new TimeSpan(
|
|
new DateBuilder().addDays(-1).atStartOfDay().build().getTime(),
|
|
new DateBuilder().addDays(-1).atEndOfDay().build().getTime()
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param {string} query
|
|
* @param {any} params
|
|
* @returns {Promise<int>}
|
|
*/
|
|
async function queryScalarAsync(query, ...params) {
|
|
const connection = await mysql.createConnection({
|
|
host: process.env.DATABASE_HOST,
|
|
user: process.env.DATABASE_USER,
|
|
password: process.env.DATABASE_PASSWORD,
|
|
database: process.env.DATABASE_NAME
|
|
});
|
|
await connection.connect();
|
|
return new Promise((resolve, reject) => {
|
|
connection.query(query, params, (err, results) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve(results[0][Object.keys(results[0])[0]]);
|
|
}
|
|
connection.end();
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Fetch call statistics
|
|
* @returns {Promise<CallStats>}
|
|
*/
|
|
async function getPreviousDayData() {
|
|
const [ callsYesterday, callsThisMonth, callsTotal ] = await Promise.all([
|
|
queryScalarAsync(`
|
|
SELECT COUNT(DISTINCT uniqueid) AS call_count
|
|
FROM cdr
|
|
WHERE calldate BETWEEN ? AND ?;
|
|
`, getYesterday().startDate, getYesterday().endDate),
|
|
queryScalarAsync(`
|
|
SELECT COUNT(DISTINCT uniqueid) AS call_count
|
|
FROM cdr
|
|
WHERE MONTH (calldate) = MONTH (?) AND YEAR (calldate) = YEAR (?);
|
|
`, getYesterday().startDate, getYesterday().startDate),
|
|
queryScalarAsync(`
|
|
SELECT COUNT(DISTINCT uniqueid) AS call_count
|
|
FROM cdr;
|
|
`)
|
|
]);
|
|
const stats = new CallStats({
|
|
totalCallsMade: callsYesterday,
|
|
totalCallsThisMonth: callsThisMonth,
|
|
totalCallsEverPlaced: callsTotal
|
|
});
|
|
console.log("Got stats:", stats, "built from query results:", { callsYesterday, callsThisMonth, callsTotal });
|
|
return stats;
|
|
// return new Promise(async (resolve, reject) => {
|
|
// const yesterday = getYesterday();
|
|
// const connection = await mysql.createConnection({
|
|
// host: process.env.DATABASE_HOST,
|
|
// user: process.env.DATABASE_USER,
|
|
// password: process.env.DATABASE_PASSWORD,
|
|
// database: process.env.DATABASE_NAME,
|
|
// multipleStatements: true
|
|
// });
|
|
// await connection.connect();
|
|
// await connection.query(`
|
|
// SELECT COUNT(DISTINCT uniqueid) AS call_count
|
|
// FROM cdr
|
|
// WHERE calldate BETWEEN ? AND ?;
|
|
//
|
|
// SELECT COUNT(DISTINCT uniqueid) AS call_count
|
|
// FROM cdr
|
|
// WHERE MONTH (calldate) = MONTH (?) AND YEAR (calldate) = YEAR (?);
|
|
//
|
|
// SELECT COUNT(DISTINCT uniqueid) AS call_count
|
|
// FROM cdr;
|
|
// `, [ yesterday.start, yesterday.end, yesterday.start, yesterday.start ], (err, res) => {
|
|
// if (err) {
|
|
// reject(err);
|
|
// }
|
|
// connection.end();
|
|
// // let output = {
|
|
// // "Calls Made": res[0][0].call_count,
|
|
// // "Monthly Total": res[1][0].call_count,
|
|
// // "Total Calls Ever Placed": res[2][0].call_count,
|
|
// // "System Uptime": getSystemUptime().toString(false, false),
|
|
// // "All Time Record": null, // Placeholder
|
|
// // }
|
|
//
|
|
// const stats = new CallStats({
|
|
// callsMadeToday: res[0][0].call_count,
|
|
// totalCallsThisMonth: res[1][0].call_count,
|
|
// totalCallsEverPlaced: res[2][0].call_count,
|
|
// allTimeRecord: null // Placeholder
|
|
// });
|
|
//
|
|
// console.log(stats);
|
|
// resolve(stats);
|
|
// });
|
|
// });
|
|
}
|
|
|
|
function getSystemUptime() {
|
|
const uptime = os.uptime();
|
|
const now = new Date();
|
|
return new TimeSpan(now - (uptime * 1000), now.getTime());
|
|
}
|
|
|
|
/**
|
|
* Update records with new data
|
|
* @param {CallStats} callStats
|
|
* @param {Records} records
|
|
* @returns {CallStats}
|
|
*/
|
|
function updateRecords(callStats, records) {
|
|
const yesterday = getYesterday().startDate;
|
|
const yesterdayDateString = yesterday.toISOString().split('T')[0];
|
|
let isNewRecord = false;
|
|
|
|
// Update all-time record
|
|
const allTimeRecord = records.callRecord || new CallRecord({ date: yesterdayDateString, count: 0 });
|
|
if (!records.callRecord) {
|
|
records.callRecord = { date: yesterdayDateString, count: callStats.totalCallsMade };
|
|
isNewRecord = true;
|
|
} else if (allTimeRecord.count < callStats.totalCallsThisMonth) {
|
|
allTimeRecord.count = callStats.totalCallsThisMonth;
|
|
isNewRecord = true;
|
|
}
|
|
callStats.allTimeRecord = `${allTimeRecord.count} calls on ${allTimeRecord.date}`;
|
|
|
|
// Update total calls ever placed
|
|
records.totalCallsEverPlaced = callStats.totalCallsEverPlaced;
|
|
|
|
// Update monthly totals
|
|
if (!records.monthlyTotals) records.monthlyTotals = {};
|
|
if (!records.monthlyTotals[yesterday.getFullYear().toString()]) records.monthlyTotals[yesterday.getFullYear().toString()] = {};
|
|
records.monthlyTotals[yesterday.getFullYear().toString()][yesterday.getMonth().toString()] = callStats.totalCallsThisMonth;
|
|
|
|
if (isNewRecord) {
|
|
callStats.isNewRecord = true;
|
|
}
|
|
return callStats;
|
|
}
|
|
|
|
async function sendSummary() {
|
|
console.log("Preparing summary.");
|
|
const data = await getPreviousDayData();
|
|
console.log("Updating records...");
|
|
const stats = await updateRecords(data, records);
|
|
console.log("Saving.");
|
|
await records.toJSONFile(JSON_FILE);
|
|
|
|
const yesterday = getYesterday();
|
|
|
|
await sendSummaryDiscord(yesterday, stats)
|
|
}
|
|
|
|
async function sendSummaryDiscord(yesterday, stats) {
|
|
const makeField = (name, value) => ({
|
|
name,
|
|
value: value === undefined ? "***ERR: UNDEFINED***" : value.toString(),
|
|
inline: false
|
|
});
|
|
|
|
let embed = {
|
|
title: `Summary from <t:${Math.floor(yesterday.start / 1000)}:f> to <t:${Math.floor(yesterday.end / 1000)}:f>`,
|
|
color: 0x1E90FF,
|
|
fields: [
|
|
makeField("Calls Made", stats.totalCallsMade),
|
|
makeField("Monthly Total", stats.totalCallsThisMonth),
|
|
makeField("Total Calls Ever Placed", stats.totalCallsEverPlaced),
|
|
makeField("System Uptime", getSystemUptime().toString(false, false)),
|
|
makeField("All Time Record", stats.allTimeRecord)
|
|
],
|
|
timestamp: new Date(),
|
|
footer: {}
|
|
}
|
|
|
|
if (stats.isNewRecord) {
|
|
embed.color = 0xFFD700; // Gold color for new record
|
|
embed.fields.push(makeField("🎉 NEW RECORD! 🎉", `A new record has been set, at ${stats.totalCallsMade}!`));
|
|
}
|
|
|
|
const payload = { embeds: [ embed ] };
|
|
console.log("Sending Discord message:", JSON.stringify(payload, null, 2));
|
|
if (hook)
|
|
await hook.send(payload);
|
|
}
|
|
|
|
if (process.env.NOOP) {
|
|
sendSummary();
|
|
return;
|
|
}
|
|
console.log("Scheduling...");
|
|
const schedule = cron.schedule("0 1 * * *", sendSummary);
|