freepbx-stats/index.js

158 lines
5.6 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()
);
}
/**
* Fetch call statistics
* @returns {Promise<CallStats>}
*/
async function getPreviousDayData() {
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 = {};
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 updatedData = await updateRecords(data, records);
console.log("Saving.");
await records.toJSONFile(JSON_FILE);
const yesterday = getYesterday();
const makeField = (name, value) => ({ name, value: 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", updatedData.totalCallsMade),
makeField("Monthly Total", updatedData.totalCallsThisMonth),
makeField("Total Calls Ever Placed", updatedData.totalCallsEverPlaced),
makeField("System Uptime", getSystemUptime().toString(false, false)),
makeField("All Time Record", updatedData.allTimeRecord)
],
timestamp: new Date(),
footer: {}
}
if (updatedData.isNewRecord) {
embed.color = 0xFFD700; // Gold color for new record
embed.fields.push(makeField("🎉 NEW RECORD! 🎉", `A new record has been set, at ${updatedData.totalCallsMade}!`));
}
const payload = { embeds: [ embed ] };
console.log("Sending Discord message:", payload);
if (hook)
await hook.send(payload);
}
if (process.env.NOOP) {
sendSummary();
return;
}
console.log("Scheduling...");
const schedule = cron.schedule("0 1 * * *", sendSummary);