Added server status.
This commit is contained in:
parent
8fb6047dfb
commit
32cb0ab344
7
index.js
7
index.js
|
@ -10,9 +10,9 @@ import njk from 'nunjucks'
|
|||
|
||||
import initLog from './libs/utils/log.js'
|
||||
import routes from './routes/routes.js'
|
||||
|
||||
import { generateDB } from './libs/database/generate.js'
|
||||
import { dbInit } from './libs/database/init.js'
|
||||
import { getStats, setStat } from './libs/serverStats.js'
|
||||
import { downloadEssentialData } from './libs/download/dowload.js'
|
||||
|
||||
const start = Date.now()
|
||||
|
@ -21,10 +21,13 @@ const log = initLog("[ MAIN ]")
|
|||
// Read the .env file
|
||||
dotenv.config()
|
||||
|
||||
dbInit()
|
||||
setStat("startup", start)
|
||||
setStat("lastDBUpdate", start)
|
||||
|
||||
if (process.env.DOWNLOAD_FILES === "enabled")
|
||||
await downloadEssentialData()
|
||||
|
||||
dbInit()
|
||||
generateDB()
|
||||
|
||||
const Server = express()
|
||||
|
|
47
libs/serverStats.js
Normal file
47
libs/serverStats.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { sqlite } from './database/init.js'
|
||||
|
||||
let globStats = {
|
||||
startup: Date.now(),
|
||||
updatingDB: false,
|
||||
lastDBUpdate: Date.now()
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns current server stats.
|
||||
*
|
||||
* @returns {object} Stats for server.
|
||||
* @author BurnyLlama
|
||||
*/
|
||||
export function getStats() {
|
||||
const uptimeMillis = Date.now() - globStats.startup
|
||||
const uptimeSeconds = `${uptimeMillis / 1000} s`
|
||||
|
||||
const dbBytes = sqlite.prepare("SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()").get().size
|
||||
|
||||
const db = {
|
||||
size: {
|
||||
bytes: dbBytes,
|
||||
kbytes: dbBytes / 1024,
|
||||
mbytes: dbBytes / 1024 ** 2,
|
||||
gbytes: dbBytes / 1024 ** 3,
|
||||
},
|
||||
currentlyUpdating: globStats.updatingDB,
|
||||
lastUpdate: new Date(globStats.lastDBUpdate).toLocaleString()
|
||||
}
|
||||
|
||||
const stats = { uptimeMillis, uptimeSeconds, db }
|
||||
console.log(stats)
|
||||
return stats
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets a "global" stat...
|
||||
*
|
||||
* @param {string} stat The stat you want to set.
|
||||
* @param {*} value The calue you want 'stat' to have.
|
||||
*
|
||||
* @author BurnyLlama
|
||||
*/
|
||||
export function setStat(stat, value) {
|
||||
globStats[stat] = value
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { Router } from 'express'
|
||||
import wrapper from '../libs/database/wrapper.js'
|
||||
import tx from '../libs/routex.js'
|
||||
import { getStats } from '../libs/serverStats.js'
|
||||
|
||||
const routes = Router()
|
||||
|
||||
|
@ -33,4 +34,13 @@ routes.get(
|
|||
}
|
||||
)
|
||||
|
||||
routes.get(
|
||||
'/status',
|
||||
(req, res) => {
|
||||
const stats = getStats()
|
||||
|
||||
tx(req, res)('pages/stats.njk', { stats }, true, { currentSection: null })
|
||||
}
|
||||
)
|
||||
|
||||
export default routes
|
|
@ -36,15 +36,6 @@
|
|||
|
||||
.map-info {
|
||||
margin: .25rem 2rem;
|
||||
|
||||
td {
|
||||
padding: .25rem 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
width: 9ch;
|
||||
}
|
||||
}
|
||||
|
||||
a.map-more-info {
|
||||
|
@ -77,10 +68,6 @@ a.map-more-info {
|
|||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
width: 14ch;
|
||||
}
|
||||
}
|
||||
|
||||
.leaderboard {
|
||||
|
|
|
@ -142,6 +142,26 @@ input {
|
|||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// TABLES
|
||||
//
|
||||
tr {
|
||||
width: max-content;
|
||||
|
||||
td {
|
||||
padding: .25rem 0;
|
||||
vertical-align: middle;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
padding: .25rem 1.5rem .25rem 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FOOTER
|
||||
//
|
||||
|
|
|
@ -1 +1 @@
|
|||
.map{background-color:#20203f;border-radius:1rem;box-shadow:.25rem 0 2rem #00001f;display:flex;flex-direction:column;justify-content:center;margin:2rem 1rem;transition:transform .3s,box-shadow .3s}.map:hover{transform:scale(1.05);box-shadow:.5rem 0 4rem #00001f}.map-image{border-radius:1rem 1rem 0 0;width:360px;height:225px}.map-name{font-size:1.2rem;font-weight:bold;margin:1rem 2rem .5rem 2rem}.map-info{margin:.25rem 2rem}.map-info td{padding:.25rem 0;vertical-align:middle}.map-info td:first-child{width:9ch}a.map-more-info{margin:.75rem auto 1.25rem auto;padding:.15rem .5rem;border:.1rem solid #fba7c6;border-radius:.5rem;color:#fba7c6;text-decoration:none transparent;transition:color .3s,background-color .3s}a.map-more-info:hover{color:#10102f;background-color:#fba7c6}.map-detailed{padding-bottom:1rem}.map-detailed:hover{transform:none}.map-detailed .map-image{width:100%;height:auto}.map-detailed td:first-child{width:14ch}.leaderboard{width:max-content;margin:2rem;padding:1.5rem 2rem;background-color:#20203f;border-radius:1rem;box-shadow:.25rem 0 2rem #00001f}.rank{display:flex;margin:1.5rem 0}.rank .country-image{height:1.5rem;margin:auto .5rem auto 0}.rank .rank-position{color:#ee588f;margin:auto .5rem auto 0;font-weight:bold}.rank .rank-player{margin:auto 2rem auto 0}.rank .rank-time{color:#9090af;font-family:"Manrope Light";margin:auto 0 auto auto}.leaderboard-history{width:min(70ch,70vw);margin:2rem;padding:1.5rem 2rem;background-color:#20203f;border-radius:1rem;box-shadow:.25rem 0 2rem #00001f}
|
||||
.map{background-color:#20203f;border-radius:1rem;box-shadow:.25rem 0 2rem #00001f;display:flex;flex-direction:column;justify-content:center;margin:2rem 1rem;transition:transform .3s,box-shadow .3s}.map:hover{transform:scale(1.05);box-shadow:.5rem 0 4rem #00001f}.map-image{border-radius:1rem 1rem 0 0;width:360px;height:225px}.map-name{font-size:1.2rem;font-weight:bold;margin:1rem 2rem .5rem 2rem}.map-info{margin:.25rem 2rem}a.map-more-info{margin:.75rem auto 1.25rem auto;padding:.15rem .5rem;border:.1rem solid #fba7c6;border-radius:.5rem;color:#fba7c6;text-decoration:none transparent;transition:color .3s,background-color .3s}a.map-more-info:hover{color:#10102f;background-color:#fba7c6}.map-detailed{padding-bottom:1rem}.map-detailed:hover{transform:none}.map-detailed .map-image{width:100%;height:auto}.leaderboard{width:max-content;margin:2rem;padding:1.5rem 2rem;background-color:#20203f;border-radius:1rem;box-shadow:.25rem 0 2rem #00001f}.rank{display:flex;margin:1.5rem 0}.rank .country-image{height:1.5rem;margin:auto .5rem auto 0}.rank .rank-position{color:#ee588f;margin:auto .5rem auto 0;font-weight:bold}.rank .rank-player{margin:auto 2rem auto 0}.rank .rank-time{color:#9090af;font-family:"Manrope Light";margin:auto 0 auto auto}.leaderboard-history{width:min(70ch,70vw);margin:2rem;padding:1.5rem 2rem;background-color:#20203f;border-radius:1rem;box-shadow:.25rem 0 2rem #00001f}
|
||||
|
|
|
@ -1 +1 @@
|
|||
*{margin:0;padding:0;border:0 none transparent;box-sizing:border-box;scroll-behavior:smooth;font-family:"Manrope Regular",sans-serif;font-size:1rem;line-height:1.5}html,body{color:#e0e0ff;background-color:#10102f;height:100%}nav{display:flex;align-items:center;background-color:#20203f;border-radius:0 0 2rem 2rem;box-shadow:.5rem 0 4rem #00001f;margin:0 0 2rem 0;padding:1rem 2rem}nav .logo{width:3rem;height:3rem;margin-right:2rem;border-radius:100%;background-color:#ee588f}nav a{color:#fba7c6;border-bottom:.1rem solid transparent;margin:.25rem 1rem .5rem 1rem;padding:.15rem .5rem .25rem .5rem;font-size:1.25rem;text-decoration:none transparent;transition:border .3s}nav a:hover{border-bottom:.1rem solid #fba7c6}nav a.current{color:#ee588f}nav a.current:hover{border-bottom:.1rem solid #ee588f}main.flex-container{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-around;margin:0 10vw}header,h1,h2,h3,h4,h5,h6{color:#fba7c6}header{font-size:4rem}h1{font-size:1.5rem;font-weight:normal}h2{font-size:1.35rem;font-weight:normal}h3{font-size:1.2rem;font-weight:normal}h4{font-size:1.05rem;font-weight:normal}h5{font-size:.9rem;font-weight:normal}a{color:#a3cefa}form{display:flex;flex-direction:column;justify-content:center;align-items:center}input{color:#e0e0ff;background-color:#20203f;margin:1em 0;padding:.75em 1.25em;width:min(80ch,80vw);outline:0 none transparent;border:.2rem solid transparent;border-radius:.5rem;box-shadow:.25rem 0 2rem #00001f;transition:border .3s,background-color .5s,border-radius .5s}input:hover{background-color:#30304f;border-radius:1rem}input:active,input:focus{border:.2rem solid #ee588f}footer{display:flex;flex-direction:column;align-items:center;margin:5vh 2rem}footer a{color:#74b6fb;font-size:.8rem}
|
||||
*{margin:0;padding:0;border:0 none transparent;box-sizing:border-box;scroll-behavior:smooth;font-family:"Manrope Regular",sans-serif;font-size:1rem;line-height:1.5}html,body{color:#e0e0ff;background-color:#10102f;height:100%}nav{display:flex;align-items:center;background-color:#20203f;border-radius:0 0 2rem 2rem;box-shadow:.5rem 0 4rem #00001f;margin:0 0 2rem 0;padding:1rem 2rem}nav .logo{width:3rem;height:3rem;margin-right:2rem;border-radius:100%;background-color:#ee588f}nav a{color:#fba7c6;border-bottom:.1rem solid transparent;margin:.25rem 1rem .5rem 1rem;padding:.15rem .5rem .25rem .5rem;font-size:1.25rem;text-decoration:none transparent;transition:border .3s}nav a:hover{border-bottom:.1rem solid #fba7c6}nav a.current{color:#ee588f}nav a.current:hover{border-bottom:.1rem solid #ee588f}main.flex-container{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-around;margin:0 10vw}header,h1,h2,h3,h4,h5,h6{color:#fba7c6}header{font-size:4rem}h1{font-size:1.5rem;font-weight:normal}h2{font-size:1.35rem;font-weight:normal}h3{font-size:1.2rem;font-weight:normal}h4{font-size:1.05rem;font-weight:normal}h5{font-size:.9rem;font-weight:normal}a{color:#a3cefa}form{display:flex;flex-direction:column;justify-content:center;align-items:center}input{color:#e0e0ff;background-color:#20203f;margin:1em 0;padding:.75em 1.25em;width:min(80ch,80vw);outline:0 none transparent;border:.2rem solid transparent;border-radius:.5rem;box-shadow:.25rem 0 2rem #00001f;transition:border .3s,background-color .5s,border-radius .5s}input:hover{background-color:#30304f;border-radius:1rem}input:active,input:focus{border:.2rem solid #ee588f}tr{width:max-content}tr td{padding:.25rem 0;vertical-align:middle;width:max-content}tr td:first-child{padding:.25rem 1.5rem .25rem 0}footer{display:flex;flex-direction:column;align-items:center;margin:5vh 2rem}footer a{color:#74b6fb;font-size:.8rem}
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
Made with <3 by team qwik
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://git.qwik.space/BurnyLlama/ddstats-server">Source Code</a> • <a href="/api/reference">API Reference</a> • <a href="/instance-info">Instance Info</a>
|
||||
<a href="https://git.qwik.space/BurnyLlama/ddstats-server">Source Code</a> • <a href="/api/reference">API Reference</a> • <a href="/status">Server Status</a>
|
||||
</p>
|
||||
</footer>
|
33
views/pages/stats.njk
Normal file
33
views/pages/stats.njk
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends "../templates/basic.njk" %}
|
||||
{% import "../components/_utils.njk" as utils %}
|
||||
{% set stats = data.stats %}
|
||||
|
||||
{% block body %}
|
||||
<main class="flex-container">
|
||||
<div class="stats">
|
||||
<h1>
|
||||
Current server status
|
||||
</h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Uptime:</td>
|
||||
<td>{{ utils.fancyTime(stats.uptimeMillis / 1000) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Uptime seconds:</td>
|
||||
<td>{{ stats.uptimeSeconds }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Database size:</td>
|
||||
<td>{{ stats.db.size.kbytes }} KB || {{ stats.db.size.mbytes | round(2) }} MB || {{ stats.db.size.gbytes | round(2) }} GB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Database status:</td>
|
||||
<td>{{ "Currently updating the database..." if stats.db.currentlyUpdating else "Last update was at " + stats.db.lastUpdate }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user