mrfrys-node-server/scripts/serverStats.js
2021-09-22 14:41:09 +02:00

471 lines
10 KiB
JavaScript

// -----------------------------------------------------------------
// CONFIG
// -----------------------------------------------------------------
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'],
}
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]
if (!dir) {
console.log('No params')
process.exit()
}
function getDayIndex(offset) {
if (!offset) {
offset = 0
}
const date = new Date()
if (offset) {
date.setDate(date.getDate() + offset)
}
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) {
switch (day) {
case 0:
case undefined:
return 'Today'
case -1:
return 'Yesterday'
case -2:
return 'Before yesterday'
default:
return `Day ${day.toString()}`
}
}
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.toString() : ''
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)
}
}
// ------------------------------------------------------------------------------
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 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()
}
}
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.toString())
res[i].push(dataCount.subjectCount.toString())
res[i].push(dataCount.questionCount.toString())
})
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').toString(),
countLinesMatching(log, '?up').toString(),
]
}
const installs = [...Array(colsToPrint).keys()].map((x) => {
return getDailyScriptStat(-x)
})
pCols(installs, ['', 'Installs', 'Updates'], false, 'green')
} catch(e) {
console.error(e)
}