diff --git a/packages/backend/src/queue/processors/deliver.ts b/packages/backend/src/queue/processors/deliver.ts index 2795b7d15..4dc3defd7 100644 --- a/packages/backend/src/queue/processors/deliver.ts +++ b/packages/backend/src/queue/processors/deliver.ts @@ -47,7 +47,7 @@ export default async (job: Bull.Job) => { isNotResponding: false, }); - fetchInstanceMetadata(i); + fetchInstanceMetadata(host); }); } catch (res) { // Update stats diff --git a/packages/backend/src/queue/processors/inbox.ts b/packages/backend/src/queue/processors/inbox.ts index 696cb4cdf..8e3574608 100644 --- a/packages/backend/src/queue/processors/inbox.ts +++ b/packages/backend/src/queue/processors/inbox.ts @@ -69,7 +69,7 @@ export default async (job: Bull.Job): Promise => { isNotResponding: false, }); - fetchInstanceMetadata(i); + fetchInstanceMetadata(i.host); instanceChart.requestReceived(i.host); apRequestChart.inbox(); diff --git a/packages/backend/src/queue/processors/system/update-instance.ts b/packages/backend/src/queue/processors/system/update-instance.ts index 657e0bf67..4485d5a89 100644 --- a/packages/backend/src/queue/processors/system/update-instance.ts +++ b/packages/backend/src/queue/processors/system/update-instance.ts @@ -2,7 +2,7 @@ import Bull from 'bull'; import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; export async function updateInstance(job: Bull.Job>, done: any): Promise { - await fetchInstanceMetadata({ host: job.data.host }, true); + await fetchInstanceMetadata(job.data.host, true); done(); } diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index 4b9218deb..ba688aa25 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -253,7 +253,7 @@ export async function createPerson(value: string | IObject, resolver: Resolver): registerOrFetchInstanceDoc(host).then(i => { Instances.increment({ id: i.id }, 'usersCount', 1); instanceChart.newUser(i.host); - fetchInstanceMetadata(i); + fetchInstanceMetadata(i.host); }); usersChart.update(user!, true); diff --git a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts index 502cbdb0c..3e7f9c796 100644 --- a/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts +++ b/packages/backend/src/server/api/endpoints/admin/federation/refresh-remote-instance-metadata.ts @@ -1,6 +1,4 @@ -import { Instances } from '@/models/index.js'; import { toPuny } from '@/misc/convert-host.js'; -import { ApiError } from '@/server/api/error.js'; import { fetchInstanceMetadata } from '@/services/fetch-instance-metadata.js'; import define from '@/server/api/define.js'; @@ -9,8 +7,6 @@ export const meta = { requireCredential: true, requireModerator: true, - - errors: ['NO_SUCH_OBJECT'], } as const; export const paramDef = { @@ -23,11 +19,5 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps) => { - const instance = await Instances.findOneBy({ host: toPuny(ps.host) }); - - if (instance == null) { - throw new ApiError('NO_SUCH_OBJECT'); - } - - fetchInstanceMetadata(instance, true); + fetchInstanceMetadata(toPuny(ps.host), true); }); diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index 3b3c2d7aa..44fef77d4 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -4,7 +4,6 @@ import fetch from 'node-fetch'; import tinycolor from 'tinycolor2'; import { DAY } from '@/const.js'; import { getJson, getHtml, getAgentByUrl } from '@/misc/fetch.js'; -import { Instance } from '@/models/entities/instance.js'; import { Instances } from '@/models/index.js'; import { getFetchInstanceMetadataLock } from '@/misc/app-lock.js'; import { createUpdateInstanceJob } from '@/queue/index.js'; @@ -12,16 +11,16 @@ import Logger from './logger.js'; const logger = new Logger('metadata'); -export async function fetchInstanceMetadata(instance: Instance, force = false): Promise { - const unlock = await getFetchInstanceMetadataLock(instance.host); +export async function fetchInstanceMetadata(instance_host: string, force = false): Promise { + const unlock = await getFetchInstanceMetadataLock(instance_host); + const instance = await Instances.findOneBy({ host: instance_host }); if (!force) { - const _instance = await Instances.findOneBy({ host: instance.host }); - if (_instance && _instance.infoUpdatedAt) { - const threshold = Date.now() - _instance.infoUpdatedAt.getTime(); + if (instance && !instance.isNotResponding && instance.infoUpdatedAt) { + const threshold = Date.now() - instance.infoUpdatedAt.getTime(); if (threshold > DAY) { // queue a job to deal with it later - createUpdateInstanceJob(instance.host); + createUpdateInstanceJob(instance_host); } // if the instance is already known and force is not specified, // never update the data in the same thread @@ -30,24 +29,24 @@ export async function fetchInstanceMetadata(instance: Instance, force = false): } } - logger.info(`Fetching metadata of ${instance.host} ...`); + logger.info(`Fetching metadata of ${instance_host} ...`); try { const [info, dom, manifest] = await Promise.all([ - fetchNodeinfo(instance).catch(() => null), - fetchDom(instance).catch(() => null), - fetchManifest(instance).catch(() => null), + fetchNodeinfo(instance_host).catch(() => null), + fetchDom(instance_host).catch(() => null), + fetchManifest(instance_host).catch(() => null), ]); const [favicon, icon, themeColor, name, description] = await Promise.all([ - fetchFaviconUrl(instance, dom).catch(() => null), - fetchIconUrl(instance, dom, manifest).catch(() => null), + fetchFaviconUrl(instance_host, dom).catch(() => null), + fetchIconUrl(instance_host, dom, manifest).catch(() => null), getThemeColor(info, dom, manifest).catch(() => null), getSiteName(info, dom, manifest).catch(() => null), getDescription(info, dom, manifest).catch(() => null), ]); - logger.succ(`Successfuly fetched metadata of ${instance.host}`); + logger.succ(`Successfuly fetched metadata of ${instance_host}`); const updates = { infoUpdatedAt: new Date(), @@ -69,9 +68,9 @@ export async function fetchInstanceMetadata(instance: Instance, force = false): await Instances.update(instance.id, updates); - logger.succ(`Successfuly updated metadata of ${instance.host}`); + logger.succ(`Successfuly updated metadata of ${instance_host}`); } catch (e) { - logger.error(`Failed to update metadata of ${instance.host}: ${e}`); + logger.error(`Failed to update metadata of ${instance_host}: ${e}`); } finally { unlock(); } @@ -96,11 +95,11 @@ type NodeInfo = { }; }; -async function fetchNodeinfo(instance: Instance): Promise { - logger.info(`Fetching nodeinfo of ${instance.host} ...`); +async function fetchNodeinfo(instance_host: string): Promise { + logger.info(`Fetching nodeinfo of ${instance_host} ...`); try { - const wellknown = await getJson('https://' + instance.host + '/.well-known/nodeinfo') + const wellknown = await getJson('https://' + instance_host + '/.well-known/nodeinfo') .catch(e => { if (e.statusCode === 404) { throw new Error('No nodeinfo provided'); @@ -129,21 +128,21 @@ async function fetchNodeinfo(instance: Instance): Promise { throw new Error(e.statusCode || e.message); }); - logger.succ(`Successfuly fetched nodeinfo of ${instance.host}`); + logger.succ(`Successfuly fetched nodeinfo of ${instance_host}`); return info as NodeInfo; } catch (e) { const message = e instanceof Error ? e.message : e; - logger.error(`Failed to fetch nodeinfo of ${instance.host}: ${message}`); + logger.error(`Failed to fetch nodeinfo of ${instance_host}: ${message}`); throw e; } } -async function fetchDom(instance: Instance): Promise { - logger.info(`Fetching HTML of ${instance.host} ...`); +async function fetchDom(instance_host: string): Promise { + logger.info(`Fetching HTML of ${instance_host} ...`); - const url = 'https://' + instance.host; + const url = 'https://' + instance_host; const html = await getHtml(url); @@ -153,8 +152,8 @@ async function fetchDom(instance: Instance): Promise { return doc; } -async function fetchManifest(instance: Instance): Promise | null> { - const url = 'https://' + instance.host; +async function fetchManifest(instance_host: string): Promise | null> { + const url = 'https://' + instance_host; const manifestUrl = url + '/manifest.json'; @@ -163,8 +162,8 @@ async function fetchManifest(instance: Instance): Promise { - const url = 'https://' + instance.host; +async function fetchFaviconUrl(instance_host: string, doc: DOMWindow['document'] | null): Promise { + const url = 'https://' + instance_host; if (doc) { // https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043 @@ -190,19 +189,19 @@ async function fetchFaviconUrl(instance: Instance, doc: DOMWindow['document'] | return null; } -async function fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | null, manifest: Record | null): Promise { +async function fetchIconUrl(instance_host: string, doc: DOMWindow['document'] | null, manifest: Record | null): Promise { if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) { - const url = 'https://' + instance.host; + const url = 'https://' + instance_host; return (new URL(manifest.icons[0].src, url)).href; } if (doc) { - const url = 'https://' + instance.host; + const url = 'https://' + instance_host; // https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043 const links = Array.from(doc.getElementsByTagName('link')).reverse(); // https://github.com/misskey-dev/misskey/pull/8220/files/0ec4eba22a914e31b86874f12448f88b3e58dd5a#r796487559 - const href = + const href = [ links.find(link => link.relList.contains('apple-touch-icon-precomposed'))?.href, links.find(link => link.relList.contains('apple-touch-icon'))?.href,