/* eslint-disable no-inner-declarations */ // ----------------------------------------------------------------- // CONFIG // ----------------------------------------------------------------- // TODO: ep for these values // js script to get from a single & multiple server & sum them const cols = process.stdout.columns // const rows = process.stdout.rows const colWidth = 40 const maxStatLength = colWidth // Math.floor(cols / 4) const statNameSpacing = 4 const beforeRowSpace = 13 const colsToPrint = Math.floor(cols / (colWidth + statNameSpacing + beforeRowSpace / 3 + 5)) || 1 const coloredWords = { red: ['lred', 'thanks'], cyan: [ 'getveteranpw', 'pwrequest', 'getpw', 'availablepws', 'login', 'logout', ], green: [ 'manual', 'todos', 'allquestions', 'subjectbrowser', 'contribute', 'feedback', 'ranklist', 'allqr', 'possibleAnswers', 'faq', '/script', 'listUserDir', 'forumEntries', 'contacts.json', 'patreon', 'donate', 'userfiles', 'hasNewMsg', ], blue: [ 'isadding', 'react', 'ask', 'newUserDir', 'updateQuestion', 'uploadUserFile', 'votetodo', 'registerscript', 'install', ], magenta: [ 'addPost', 'comment', 'postfeedback', 'quickvote', 'getnewdatasince', ], } const filterFromDailyStats = [ 'savedQuestions', 'sio/f', 'sound/', '/img/', '.php', '/wordpress/', '/wp/', '/wp-includes/', 'favicon', 'robots.txt', 'ads.txt', '/f/', '.git', 'apple-touch-icon', '/.env', '/userFiles/', '.min.js', '.xml', '.aspx', '/questionDbs/', '/chatFiles/', 'rss', ] // ----------------------------------------------------------------- const fs = require('fs') // eslint-disable-line const dir = process.argv[2] const startDay = !isNaN(parseInt(process.argv[3])) && parseInt(process.argv[3]) > 0 ? 0 : parseInt(process.argv[3]) if (!dir) { console.log('No params') process.exit() } function getDayIndex(offset) { let os = offset if (!offset) { os = 0 } if (!isNaN(startDay)) { if (!offset) { os = startDay } else { os = startDay + offset } } const date = new Date() if (os) { date.setDate(date.getDate() + os) } return ( date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2) + '-' + ('0' + date.getDate()).slice(-2) ) } function hr(char) { console.log(C('blue') + getLetterNTimes(char || '=', cols) + C()) } function printHeader(text) { hr() console.log(C('green') + text + C()) hr() } function C(color) { if (color !== undefined) { color = color.toLowerCase() } if (color === 'redbg') { return '\x1b[41m' } if (color === 'bluebg') { return '\x1b[44m' } if (color === 'green') { return '\x1b[32m' } if (color === 'red') { return '\x1b[31m' } if (color === 'yellow') { return '\x1b[33m' } if (color === 'blue') { return '\x1b[34m' } if (color === 'magenta') { return '\x1b[35m' } if (color === 'cyan') { return '\x1b[36m' } return '\x1b[0m' } function readJSON(name) { return JSON.parse(fs.readFileSync(name, 'utf8')) } function tail(text, number) { const splitedText = text.split('\n') return splitedText .slice(Math.max(splitedText.length - number, 1)) .join('\n') } function head(text, number) { return text.split('\n').slice(0, number).join('\n') } function countLinesMatching(text, toMatch) { let count = 0 text.split('\n').forEach((line) => { if (line.includes(toMatch.toLowerCase())) { count++ } }) return count } function getDayName(day) { let d = day if (!isNaN(startDay)) { d += startDay } switch (d) { case 0: case undefined: return 'Today' case -1: return 'Yesterday' case -2: return 'Before yesterday' default: const now = new Date() now.setDate(now.getDate() + d) return now.toDateString() } } function readFile(name) { if (fs.existsSync(name)) { return fs.readFileSync(name, 'utf8') } } function getLetterNTimes(letter, number) { let res = '' while (res.length < number) { res += letter } return res } function pCols(cols, rowTitles, colorNames, firstRowColor) { // console.log(cols) let maxLength = 0 cols.reverse().forEach((col, i) => { if (i >= colsToPrint) { return } if (col.length > maxLength) { maxLength = col.length } }) cols.reverse() for (let i = 0; i < maxLength; i++) { const row = [] cols.forEach((val, colIndex) => { if (colIndex >= colsToPrint) { return } if (!val[i]) { row.push( getLetterNTimes(' ', maxStatLength + statNameSpacing + 2) ) return } const keyName = val[i].name || val[i] let slicedName = keyName.slice(0, maxStatLength) const toColor = colorNames ? Object.keys(coloredWords).reduce((acc, key) => { const colorArray = coloredWords[key] const includes = colorArray.some((colorableIdName) => { return keyName .toLowerCase() .includes(colorableIdName.toLowerCase()) }) if (includes) { return key } return acc }, '') : false const sep = (i + 1) % 5 === 0 ? '.' : ' ' while (slicedName.length < maxStatLength) { slicedName = slicedName + sep } let ammount = val[i].val ? val[i].val.toLocaleString() : '' while (ammount.length < 5) { ammount = ammount + ' ' } if (toColor) { row.push(C(toColor) + slicedName + ' ' + ammount + C()) } else { row.push(slicedName + ' ' + ammount) } }) // ROW TITLE --------------------------------------------------- let currRowTitle = rowTitles && rowTitles[i] ? rowTitles[i] : getLetterNTimes(' ', beforeRowSpace) while (currRowTitle.length < beforeRowSpace) { currRowTitle = currRowTitle + ' ' } currRowTitle = C('blue') + currRowTitle + C() // COLORING ---------------------------------------------------- let res = '' if (firstRowColor && i === 0) { res = currRowTitle + C('green') + row.join(getLetterNTimes(' ', statNameSpacing)) + C() } else { res = currRowTitle + row.join(getLetterNTimes(' ', statNameSpacing)) } // SHOW DIFF --------------------------------------------------- console.log(res) } } function preProcessUIdTestSolving(obj, minLength) { if (!obj) { return '0' } if (minLength) { return Object.keys(obj) .filter((key) => { return obj[key] > minLength }) .length.toString() } else { return Object.keys(obj).length.toString() } } // ------------------------------------------------------------------------------ printHeader('Daily stats') try { const dailyStats = readJSON(`${dir}stats/vstats`) function preProcessDailyStats(obj) { const formatted = Object.keys(obj).reduce((acc, key) => { const includes = filterFromDailyStats.some((keyword) => { return key.toLowerCase().includes(keyword.toLowerCase()) }) if (!includes) { acc.push({ name: key.replace(/\.html/g, ''), val: obj[key] }) } return acc }, []) const merged = formatted.reduce((acc, x) => { const index = acc.findIndex((y) => { return x.name === y.name }) if (index !== -1) { acc = acc.map((z, i) => { if (i === index) { return { ...x, val: z.val + x.val, } } return z }) } else { acc.push(x) } return acc }, []) return merged.sort((a, b) => { if (a.name > b.name) { return 1 } else if (a.name < b.name) { return -1 } else { return 0 } }) } function getDailyStat(day) { return preProcessDailyStats(dailyStats[getDayIndex(day)]) } pCols( [ ...[...Array(colsToPrint).keys()].map((x) => { return getDailyStat(-x) }), ], null, true ) } catch (e) { console.error(e) } // ------------------------------------------------------------------------------ printHeader('User id test solving') try { const userIdTestSolving = readJSON(`${dir}stats/idvstats`) function getUserIdTestSolving(day) { return [ getDayName(day), preProcessUIdTestSolving(userIdTestSolving[getDayIndex(day)]), ] } pCols( [ ...[...Array(colsToPrint).keys()].map((x) => { return getUserIdTestSolving(-x) }), ], null, false, 'green' ) } catch (e) { console.error(e) } // ------------------------------------------------------------------------------ printHeader('User id requests') try { const clientIdTestSolving = readJSON(`${dir}stats/uvstats`) function getUserIdRequests(day) { return [ getDayName(day), preProcessUIdTestSolving(clientIdTestSolving[getDayIndex(day)]), preProcessUIdTestSolving(clientIdTestSolving[getDayIndex(day)], 5), ] } pCols( [ ...[...Array(colsToPrint).keys()].map((x) => { return getUserIdRequests(-x) }), ], ['', 'All', 'More than 5'], false, 'green' ) // ------------------------------------------------------------------------------ printHeader('Daily data count') const dailyDataCount = readFile(`${dir}stats/dailyDataCount`) function getDailyDataCount(count) { return [...Array(count).keys()].map((x) => { return JSON.parse(head(tail(dailyDataCount, x + 1), 1)) }) } printLastDataCount(getDailyDataCount(colsToPrint)) function printLastDataCount(data) { const res = [...Array(colsToPrint).keys()].map((x) => { return [getDayName(-x)] }) data.forEach((dataCount, i) => { res[i].push(dataCount.userCount.toLocaleString()) res[i].push(dataCount.subjectCount.toLocaleString()) res[i].push(dataCount.questionCount.toLocaleString()) }) pCols(res, ['', 'Users', 'Subjects', 'Questions'], false, 'green') } } catch (e) { console.error(e) } // ------------------------------------------------------------------------------ printHeader('Daily script install / update check count') try { function getDailyScriptStat(day) { const log = !day || day === 0 ? readFile(`${dir}stats/vlogs/log`) : readFile(`${dir}stats/vlogs/${getDayIndex(day)}`) if (!log) { return [getDayName(day), 0, 0] } return [ getDayName(day), countLinesMatching(log, '?install').toLocaleString(), countLinesMatching(log, '?up').toLocaleString(), ] } const installs = [...Array(colsToPrint).keys()].map((x) => { return getDailyScriptStat(-x) }) pCols(installs, ['', 'Installs', 'Updates'], false, 'green') } catch (e) { console.error(e) }