2026-02-26 14:41:00 -05:00
|
|
|
'use strict';
|
|
|
|
|
|
2026-04-08 12:12:53 -04:00
|
|
|
const db = require('../../database');
|
2026-02-26 14:41:00 -05:00
|
|
|
const activitypub = require('../../activitypub');
|
2026-04-01 13:39:47 -04:00
|
|
|
const analytics = require('../../analytics');
|
2026-02-26 14:41:00 -05:00
|
|
|
|
|
|
|
|
const federationController = module.exports;
|
|
|
|
|
|
|
|
|
|
federationController.general = function (req, res) {
|
|
|
|
|
res.render(`admin/federation/general`, {
|
|
|
|
|
title: '[[admin/menu:federation/general]]',
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-26 15:43:02 -05:00
|
|
|
federationController.content = function (req, res) {
|
|
|
|
|
res.render(`admin/federation/content`, {
|
|
|
|
|
title: '[[admin/menu:federation/content]]',
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-26 14:41:00 -05:00
|
|
|
federationController.rules = async function (req, res) {
|
|
|
|
|
const rules = await activitypub.rules.list();
|
|
|
|
|
|
|
|
|
|
res.render(`admin/federation/rules`, {
|
|
|
|
|
title: '[[admin/menu:federation/rules]]',
|
|
|
|
|
rules,
|
|
|
|
|
hideSave: true,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
federationController.relays = async function (req, res) {
|
|
|
|
|
const relays = await activitypub.relays.list();
|
|
|
|
|
|
|
|
|
|
res.render(`admin/federation/relays`, {
|
|
|
|
|
title: '[[admin/menu:federation/relays]]',
|
|
|
|
|
relays,
|
|
|
|
|
hideSave: true,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
federationController.pruning = function (req, res) {
|
|
|
|
|
res.render(`admin/federation/pruning`, {
|
|
|
|
|
title: '[[admin/menu:federation/pruning]]',
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-26 15:49:41 -05:00
|
|
|
federationController.safety = async function (req, res) {
|
|
|
|
|
const instanceCount = await activitypub.instances.getCount();
|
2026-03-25 11:31:50 -04:00
|
|
|
const blocklists = await activitypub.blocklists.list();
|
2026-02-26 15:49:41 -05:00
|
|
|
|
2026-02-26 14:41:00 -05:00
|
|
|
res.render(`admin/federation/safety`, {
|
|
|
|
|
title: '[[admin/menu:federation/safety]]',
|
2026-03-25 11:31:50 -04:00
|
|
|
blocklists,
|
2026-02-26 15:49:41 -05:00
|
|
|
instanceCount,
|
2026-02-26 14:41:00 -05:00
|
|
|
});
|
|
|
|
|
};
|
2026-04-01 13:39:47 -04:00
|
|
|
|
|
|
|
|
federationController.analytics = async function (req, res) {
|
|
|
|
|
const instances = await activitypub.instances.list();
|
2026-04-08 10:51:15 -04:00
|
|
|
instances.sort();
|
|
|
|
|
|
2026-04-01 14:32:50 -04:00
|
|
|
let { host, term } = req.query;
|
2026-04-01 13:39:47 -04:00
|
|
|
if (!instances.includes(host)) {
|
|
|
|
|
host = undefined;
|
|
|
|
|
}
|
2026-04-01 14:32:50 -04:00
|
|
|
let method = 'getHourlyStatsForSet';
|
|
|
|
|
let count = 24;
|
|
|
|
|
if (term === 'daily') {
|
|
|
|
|
method = 'getDailyStatsForSet';
|
|
|
|
|
count = 30;
|
|
|
|
|
}
|
2026-04-08 11:18:13 -04:00
|
|
|
const receivedSet = host ? `activities:byHost:${host}` : 'activities';
|
|
|
|
|
const receivedErrSet = host ? `ap.inErr:byHost:${host}` : 'ap.inErr';
|
2026-04-01 14:41:36 -04:00
|
|
|
const sentSet = host ? `ap.out:byHost:${host}` : 'ap.out';
|
2026-04-08 11:18:13 -04:00
|
|
|
const received = await analytics[method](receivedSet, Date.now(), count);
|
|
|
|
|
const receivedErr = await analytics[method](receivedErrSet, Date.now(), count);
|
2026-04-01 14:32:50 -04:00
|
|
|
const sent = await analytics[method](sentSet, Date.now(), count);
|
2026-04-01 13:39:47 -04:00
|
|
|
|
|
|
|
|
res.render('admin/federation/analytics', {
|
|
|
|
|
title: '[[admin/menu:federation/analytics]]',
|
|
|
|
|
instances,
|
2026-04-01 14:02:56 -04:00
|
|
|
received,
|
2026-04-08 11:18:13 -04:00
|
|
|
receivedErr,
|
2026-04-01 14:00:04 -04:00
|
|
|
sent,
|
2026-04-08 12:12:53 -04:00
|
|
|
hideSave: 1,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
federationController.errors = async function (req, res) {
|
2026-04-08 13:36:55 -04:00
|
|
|
const ids = await db.getSortedSetRevRangeByScore('ap.errors', 0, -1, Date.now(), '-inf');
|
2026-04-08 15:17:46 -04:00
|
|
|
const errorObj = await db.getObjects(ids.map(id => `ap.errors:${id}`));
|
2026-04-08 12:12:53 -04:00
|
|
|
const errors = ids.map((id, idx) => {
|
2026-04-08 15:17:46 -04:00
|
|
|
let { body, stack } = errorObj[idx];
|
2026-04-09 10:47:55 -04:00
|
|
|
let hostname = 'Invalid hostname';
|
2026-04-08 15:17:46 -04:00
|
|
|
try {
|
|
|
|
|
body = JSON.stringify(JSON.parse(body), null, 4);
|
2026-04-09 10:47:55 -04:00
|
|
|
({ hostname } = new URL(id));
|
2026-04-08 15:17:46 -04:00
|
|
|
} catch (e) {
|
|
|
|
|
// noop
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 10:47:55 -04:00
|
|
|
return { id, body, stack, hostname };
|
2026-04-08 12:12:53 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.render('admin/federation/errors', {
|
|
|
|
|
title: '[[admin/menu:federation/errors]]',
|
|
|
|
|
errors,
|
2026-04-01 13:39:47 -04:00
|
|
|
});
|
|
|
|
|
};
|