refactor: move visit handling code into its own lib file

This commit is contained in:
dusk 2024-11-23 02:53:27 +03:00
parent 6bc35b1629
commit 3e640524e8
Signed by: dusk
SSH Key Fingerprint: SHA256:Abmvag+juovVufZTxyWY8KcVgrznxvBjQpJesv071Aw
3 changed files with 61 additions and 55 deletions

View File

@ -1,7 +1,4 @@
import type { Cookies } from '@sveltejs/kit' import type { Cookies } from '@sveltejs/kit'
import { env } from '$env/dynamic/private'
import { get, writable } from 'svelte/store'
import { existsSync, readFileSync } from 'fs'
export const scopeCookies = (cookies: Cookies, path: string) => { export const scopeCookies = (cookies: Cookies, path: string) => {
return { return {
@ -16,6 +13,3 @@ export const scopeCookies = (cookies: Cookies, path: string) => {
} }
} }
} }
export const visitCountFile = `${env.WEBSITE_DATA_DIR}/visitcount`
export const visitCount = writable(parseInt(existsSync(visitCountFile) ? readFileSync(visitCountFile).toString() : '0'));

57
src/lib/visits.ts Normal file
View File

@ -0,0 +1,57 @@
import { env } from "$env/dynamic/private";
import { scopeCookies } from "$lib";
import type { Cookies } from "@sveltejs/kit";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { get, writable } from "svelte/store";
const visitCountFile = `${env.WEBSITE_DATA_DIR}/visitcount`
const visitCount = writable(parseInt(existsSync(visitCountFile) ? readFileSync(visitCountFile).toString() : '0'));
export const incrementVisitCount = (request: Request, cookies: Cookies) => {
let currentVisitCount = get(visitCount)
// check whether the request is from a bot or not (this doesnt need to be accurate we just want to filter out honest bots)
const ua = request.headers.get('user-agent')
const isBot = ua ? ua.toLowerCase().match(/(bot|crawl|spider|walk)/) !== null : true
if (!isBot) {
const scopedCookies = scopeCookies(cookies, '/')
// parse the last visit timestamp from cookies if it exists
const visitedTimestamp = parseInt(scopedCookies.get('visitedTimestamp') || "0")
// get unix timestamp
const currentTime = new Date().getTime()
const timeSinceVisit = currentTime - visitedTimestamp
// check if this is the first time a client is visiting or if an hour has passed since they last visited
if (visitedTimestamp === 0 || timeSinceVisit > 1000 * 60 * 60 * 24) {
// increment current and write to the store
currentVisitCount += 1; visitCount.set(currentVisitCount)
// update the cookie with the current timestamp
scopedCookies.set('visitedTimestamp', currentTime.toString())
// write the visit count to a file so we can load it later again
writeFileSync(visitCountFile, currentVisitCount.toString())
}
}
return currentVisitCount
}
export const notifyDarkVisitors = (url: URL, request: Request) => {
fetch('https://api.darkvisitors.com/visits', {
method: 'POST',
headers: {
authorization: `Bearer ${env.DARK_VISITORS_TOKEN}`,
'content-type': 'application/json',
},
body: JSON.stringify({
request_path: url.pathname,
request_method: request.method,
request_headers: request.headers,
})
}).catch((why) => {
console.log("failed sending dark visitors analytics:", why)
return null
}).then(async (resp) => {
if (resp !== null) {
const msg = await resp.json()
const host = `(${request.headers.get('host')} ${request.headers.get('x-real-ip')})`
console.log(`sent visitor analytic to dark visitors: ${resp.statusText}; ${msg.message ?? ''}${host}`)
}
})
}

View File

@ -1,7 +1,4 @@
import { env } from '$env/dynamic/private'; import { incrementVisitCount, notifyDarkVisitors } from '$lib/visits.js';
import { scopeCookies, visitCount, visitCountFile } from '$lib';
import { writeFileSync } from 'fs';
import { get } from 'svelte/store';
export const csr = true; export const csr = true;
export const ssr = true; export const ssr = true;
@ -9,54 +6,12 @@ export const prerender = false;
export const trailingSlash = 'always'; export const trailingSlash = 'always';
export async function load({ request, cookies, url, setHeaders, fetch }) { export async function load({ request, cookies, url, setHeaders, fetch }) {
fetch('https://api.darkvisitors.com/visits', { notifyDarkVisitors(url, request) // no await so it doesnt block load
method: 'POST',
headers: {
authorization: `Bearer ${env.DARK_VISITORS_TOKEN}`,
'content-type': 'application/json',
},
body: JSON.stringify({
request_path: url.pathname,
request_method: request.method,
request_headers: request.headers,
})
}).catch((why) => {
console.log("failed sending dark visitors analytics:", why)
return null
}).then(async (resp) => {
if (resp !== null) {
const msg = await resp.json()
const host = `(${request.headers.get('host')} ${request.headers.get('x-real-ip')})`
console.log(`sent visitor analytic to dark visitors: ${resp.statusText}; ${msg.message ?? ''}${host}`)
}
})
let currentVisitCount = get(visitCount)
// check whether the request is from a bot or not (this doesnt need to be accurate we just want to filter out honest bots)
const ua = request.headers.get('user-agent')
const isBot = ua ? ua.toLowerCase().match(/(bot|crawl|spider|walk)/) !== null : true
if (!isBot) {
const scopedCookies = scopeCookies(cookies, '/')
// parse the last visit timestamp from cookies if it exists
const visitedTimestamp = parseInt(scopedCookies.get('visitedTimestamp') || "0")
// get unix timestamp
const currentTime = new Date().getTime()
const timeSinceVisit = currentTime - visitedTimestamp
// check if this is the first time a client is visiting or if an hour has passed since they last visited
if (visitedTimestamp === 0 || timeSinceVisit > 1000 * 60 * 60 * 24) {
// increment current and write to the store
currentVisitCount += 1; visitCount.set(currentVisitCount)
// update the cookie with the current timestamp
scopedCookies.set('visitedTimestamp', currentTime.toString())
// write the visit count to a file so we can load it later again
writeFileSync(visitCountFile, currentVisitCount.toString())
}
}
setHeaders({ 'Cache-Control': 'no-cache' }) setHeaders({ 'Cache-Control': 'no-cache' })
return { return {
route: url.pathname, route: url.pathname,
visitCount: currentVisitCount, visitCount: incrementVisitCount(request, cookies),
} }
} }