PronounsPage/server/analyseLinks.ts

56 lines
2.1 KiB
TypeScript

import './setup.ts';
import SQL from 'sql-template-strings';
import { newDate, random } from '../src/helpers.ts';
import { LinkAnalyser } from '../src/links.ts';
import dbConnection from './db.ts';
import copyImage from './imageCopy.ts';
const timer = (ms: number) => new Promise((res) => setTimeout(res, ms));
(async () => {
const analyser = new LinkAnalyser();
const db = await dbConnection();
while (true) {
const chunk = await db.all(
SQL`SELECT url
FROM links
WHERE (expiresAt IS NULL OR expiresAt <= ${newDate().getTime() / 1000})
ORDER BY RANDOM()
LIMIT 64`,
);
console.log(`Fetching ${chunk.length} links: (${chunk.map((l) => l.url).join(', ')})`);
if (chunk.length === 0) {
await timer(1000);
continue;
}
const results = await Promise.all(
chunk.map(({ url }) => Promise.race([
analyser.analyse(url).then(async (result) => ({
...result,
faviconCache: result.favicon ? await copyImage('favicon-cache', result.favicon!, 30) : null,
})),
new Promise((resolve) => setTimeout(() => resolve({ url, error: new Error('timeout') }), 12000)),
])),
) as { [k: string]: string }[];
for (const result of results) {
// random TTL (0-30 days) in order to spread out the legacy load
const expireAt = (newDate().getTime() / 1000) + Math.floor(30 * 24 * 60 * 60 * random());
if (result.error) {
console.error(result);
await db.get(SQL`UPDATE links SET expiresAt = ${expireAt} WHERE url=${result.url}`);
} else {
await db.get(SQL`UPDATE links
SET expiresAt = ${expireAt},
favicon = ${result.favicon},
faviconCache = ${result.faviconCache},
relMe = ${JSON.stringify(result.relMe)},
nodeinfo = ${JSON.stringify(result.nodeinfo)}
WHERE url=${result.url}`);
}
}
}
})();