create viewcounter

This commit is contained in:
sophie 2022-09-17 22:34:29 +01:00
parent 9d2eb0906f
commit 8f3f92d82b
4 changed files with 108 additions and 1 deletions

4
.gitignore vendored
View File

@ -1,3 +1,6 @@
# view count
.count.json
# ---> Node
# Logs
logs
@ -129,4 +132,3 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

7
conf.json Normal file
View File

@ -0,0 +1,7 @@
{
"port": 8001,
"path": "/viewcounter",
"site": "zvava.org",
"db": ".count.json",
"saveTimeout": 5000
}

94
index.js Normal file
View File

@ -0,0 +1,94 @@
import * as fs from "fs"
import * as http from "http"
import { request } from "https"
// read configuration
let config = readJson("conf.json", {
port: 8001,
path: "/viewcounter",
site: "zvava.org",
db: ".count.json",
saveTimeout: 5000,
})
// read existing view count
let count = readJson(config.db)
// store the save timeout
let saveTimeout
let server = new http.Server((request, response) => {
try {
if (request.url != config.path)
return close(response, 404)
switch (request.method) {
case "GET":
close(response, 200, JSON.stringify(count))
break
case "POST":
const chunks = []
request.on("data", chunk => chunks.push(chunk))
request.on("end", async () => {
let page = Buffer.concat(chunks).toString()
// check if page is a valid url
if (/\/[a-zA-Z0-9_-]+.html/.test(page) && await validateUrl(page)) {
count[page]++
saveCount()
close(response, 200, "counted page view", { views: count[page] })
} else {
close(response, 300, "invalid url provided")
}
})
break
default: resolve(close(response))
}
} catch (e) {
console.log(e)
}
})
server.listen(config.port)
function saveCount() {
// if a timeout
saveTimeout && clearTimeout(saveTimeout)
saveTimeout = setTimeout(() => {
fs.writeFile(config.db, JSON.stringify(count), (err) =>
err && console.error(err))
}, config.saveTimeout)
}
// read file, if it exists return it as an object, otherwise return a default object
function readJson(file, defaultJson = {}) {
try { return JSON.parse(fs.readFileSync(file, "utf-8")) } catch {}
return defaultJson
}
// helper function to close an incoming http request
function close(res, code = 300, message = "", extraData = {}) {
res.setHeader("Content-type", "application/json")
res.writeHead(code)
res.end(JSON.stringify({
code,
message: message || code.toString(),
...extraData
}))
}
// ping the target site and ensure that the url exists
function validateUrl(url) {
console.log(url)
return new Promise((resolve) => {
request({
method: "HEAD",
host: config.site,
path: url,
}, (response) => {
console.log(response.statusCode, response.headers)
resolve(response.statusCode == 200)
}).end()
})
}

4
package.json Normal file
View File

@ -0,0 +1,4 @@
{
"main": "index.js",
"type": "module"
}