summaryrefslogtreecommitdiff
path: root/src/services/fetch-nodeinfo.ts
blob: e5d652a6b37ab9cf7239fd72211c42b6e448ce2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import * as request from 'request-promise-native';
import { Instance } from '../models/entities/instance';
import { Instances } from '../models';
import config from '../config';
import { getNodeinfoLock } from '../misc/app-lock';
import Logger from '../services/logger';

export const logger = new Logger('nodeinfo', 'cyan');

export async function fetchNodeinfo(instance: Instance) {
	const unlock = await getNodeinfoLock(instance.host);

	const _instance = await Instances.findOne({ host: instance.host });
	const now = Date.now();
	if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) {
		unlock();
		return;
	}

	logger.info(`Fetching nodeinfo of ${instance.host} ...`);

	try {
		const wellknown = await request({
			url: 'https://' + instance.host + '/.well-known/nodeinfo',
			proxy: config.proxy,
			timeout: 1000 * 10,
			forever: true,
			headers: {
				'User-Agent': config.userAgent,
				Accept: 'application/json, */*'
			},
			json: true
		}).catch(e => {
			if (e.statusCode === 404) {
				throw 'No nodeinfo provided';
			} else {
				throw e.statusCode || e.message;
			}
		});

		if (wellknown.links == null || !Array.isArray(wellknown.links)) {
			throw 'No wellknown links';
		}

		const links = wellknown.links as any[];

		const lnik1_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/1.0');
		const lnik2_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.0');
		const lnik2_1 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.1');
		const link = lnik2_1 || lnik2_0 || lnik1_0;

		if (link == null) {
			throw 'No nodeinfo link provided';
		}

		const info = await request({
			url: link.href,
			proxy: config.proxy,
			timeout: 1000 * 10,
			forever: true,
			headers: {
				'User-Agent': config.userAgent,
				Accept: 'application/json, */*'
			},
			json: true
		}).catch(e => {
			throw e.statusCode || e.message;
		});

		await Instances.update(instance.id, {
			infoUpdatedAt: new Date(),
			softwareName: info.software.name.toLowerCase(),
			softwareVersion: info.software.version,
			openRegistrations: info.openRegistrations,
			name: info.metadata ? (info.metadata.nodeName || info.metadata.name || null) : null,
			description: info.metadata ? (info.metadata.nodeDescription || info.metadata.description || null) : null,
			maintainerName: info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.name || null) : null : null,
			maintainerEmail: info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.email || null) : null : null,
		});

		logger.succ(`Successfuly fetched nodeinfo of ${instance.host}`);
	} catch (e) {
		logger.error(`Failed to fetch nodeinfo of ${instance.host}: ${e}`);

		await Instances.update(instance.id, {
			infoUpdatedAt: new Date(),
		});
	} finally {
		unlock();
	}
}