1import { updateLastPosts } from '$lib/bluesky';
2import { lastFmReadLast, lastFmUpdateNowPlaying } from '$lib/lastfm';
3import { steamReadLastGame, steamUpdateNowPlaying } from '$lib/steam';
4import { updateCommits } from '$lib/activity';
5import { cancelJob, scheduleJob, scheduledJobs } from 'node-schedule';
6import {
7 incrementFakeVisitCount,
8 incrementLegitVisitCount,
9 pushMetric,
10 sendAllMetrics
11} from '$lib/metrics';
12import {
13 addLastVisitor,
14 decrementVisitCount,
15 incrementVisitCount,
16 notifyDarkVisitors,
17 removeLastVisitor
18} from '$lib/visits';
19import { testUa } from '$lib/robots';
20import { error } from '@sveltejs/kit';
21import { _fetchEntries } from './routes/(site)/guestbook/+page.server';
22
23const UPDATE_LAST_JOB_NAME = 'update steam game, lastfm track, bsky posts, git activity';
24
25if (UPDATE_LAST_JOB_NAME in scheduledJobs) {
26 console.log(`${UPDATE_LAST_JOB_NAME} is already running, cancelling so we can start a new one`);
27 cancelJob(UPDATE_LAST_JOB_NAME);
28}
29
30await steamReadLastGame();
31await lastFmReadLast();
32
33console.log(`starting ${UPDATE_LAST_JOB_NAME} job...`);
34scheduleJob(UPDATE_LAST_JOB_NAME, '*/1 * * * *', async () => {
35 console.log(`running ${UPDATE_LAST_JOB_NAME} job...`);
36 try {
37 await Promise.all([
38 steamUpdateNowPlaying(),
39 lastFmUpdateNowPlaying(),
40 updateLastPosts(),
41 _fetchEntries(),
42 updateCommits(),
43 sendAllMetrics() // send all metrics every minute
44 ]);
45 } catch (err) {
46 console.log(`error while running ${UPDATE_LAST_JOB_NAME} job: ${err}`);
47 }
48}).invoke(); // invoke once immediately
49
50export const handle = async ({ event, resolve }) => {
51 notifyDarkVisitors(event.url, event.request); // no await so it doesnt block
52
53 const isPrefetch = () => {
54 return (
55 event.request.headers.get('Sec-Purpose')?.includes('prefetch') ||
56 event.request.headers.get('Purpose')?.includes('prefetch') ||
57 event.request.headers.get('x-purpose')?.includes('preview') ||
58 event.request.headers.get('x-moz')?.includes('prefetch')
59 );
60 };
61 const isApi = () => {
62 return event.url.pathname.startsWith('/_api');
63 };
64 const isRss = () => {
65 return event.url.pathname.endsWith('/_rss');
66 };
67
68 // block any requests if the user agent is disallowed by our robots txt
69 const isFakeVisit =
70 (await testUa(event.url.toString(), event.request.headers.get('user-agent') ?? '')) === false;
71 if (isFakeVisit) {
72 pushMetric({ gazesys_visit_fake_total: await incrementFakeVisitCount() });
73 throw error(403, 'get a better user agent silly');
74 }
75
76 // only push metric if legit page visit (still want rss to count here though)
77 const isPageVisit = !isApi() && !isPrefetch();
78 if (isPageVisit) pushMetric({ gazesys_visit_real_total: await incrementLegitVisitCount() });
79
80 // only add visitors if its a "legit" page visit
81 let id = null;
82 let valid = false;
83 if (isPageVisit && !isRss()) {
84 id = addLastVisitor(event.request, event.cookies);
85 valid = await incrementVisitCount(event.request, event.cookies);
86 }
87
88 // actually resolve event
89 const resp = await resolve(event);
90 // remove visitors if it was a 404
91 if (resp.status === 404) {
92 if (id !== null) removeLastVisitor(id);
93 if (valid) decrementVisitCount();
94 }
95
96 return resp;
97};