diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/helpers/promise-cache.ts | 21 | ||||
-rw-r--r-- | server/lib/activitypub/actors/get.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/actors/refresh.ts | 34 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/activitypub-refresher.ts | 2 |
4 files changed, 47 insertions, 12 deletions
diff --git a/server/helpers/promise-cache.ts b/server/helpers/promise-cache.ts new file mode 100644 index 000000000..07e8a9962 --- /dev/null +++ b/server/helpers/promise-cache.ts | |||
@@ -0,0 +1,21 @@ | |||
1 | export class PromiseCache <A, R> { | ||
2 | private readonly running = new Map<string, Promise<R>>() | ||
3 | |||
4 | constructor ( | ||
5 | private readonly fn: (arg: A) => Promise<R>, | ||
6 | private readonly keyBuilder: (arg: A) => string | ||
7 | ) { | ||
8 | } | ||
9 | |||
10 | run (arg: A) { | ||
11 | const key = this.keyBuilder(arg) | ||
12 | |||
13 | if (this.running.has(key)) return this.running.get(key) | ||
14 | |||
15 | const p = this.fn(arg) | ||
16 | |||
17 | this.running.set(key, p) | ||
18 | |||
19 | return p.finally(() => this.running.delete(key)) | ||
20 | } | ||
21 | } | ||
diff --git a/server/lib/activitypub/actors/get.ts b/server/lib/activitypub/actors/get.ts index de93aa964..501ff74e3 100644 --- a/server/lib/activitypub/actors/get.ts +++ b/server/lib/activitypub/actors/get.ts | |||
@@ -56,7 +56,7 @@ async function getOrCreateAPActor ( | |||
56 | if (actor.Account) (actor as MActorAccountChannelIdActor).Account.Actor = actor | 56 | if (actor.Account) (actor as MActorAccountChannelIdActor).Account.Actor = actor |
57 | if (actor.VideoChannel) (actor as MActorAccountChannelIdActor).VideoChannel.Actor = actor | 57 | if (actor.VideoChannel) (actor as MActorAccountChannelIdActor).VideoChannel.Actor = actor |
58 | 58 | ||
59 | const { actor: actorRefreshed, refreshed } = await refreshActorIfNeeded(actor, fetchType) | 59 | const { actor: actorRefreshed, refreshed } = await refreshActorIfNeeded({ actor, fetchedType: fetchType }) |
60 | if (!actorRefreshed) throw new Error('Actor ' + actor.url + ' does not exist anymore.') | 60 | if (!actorRefreshed) throw new Error('Actor ' + actor.url + ' does not exist anymore.') |
61 | 61 | ||
62 | await scheduleOutboxFetchIfNeeded(actor, created, refreshed, updateCollections) | 62 | await scheduleOutboxFetchIfNeeded(actor, created, refreshed, updateCollections) |
diff --git a/server/lib/activitypub/actors/refresh.ts b/server/lib/activitypub/actors/refresh.ts index 1f7cfcd8f..b2fe3932f 100644 --- a/server/lib/activitypub/actors/refresh.ts +++ b/server/lib/activitypub/actors/refresh.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { logger, loggerTagsFactory } from '@server/helpers/logger' | 1 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
2 | import { PromiseCache } from '@server/helpers/promise-cache' | ||
2 | import { PeerTubeRequestError } from '@server/helpers/requests' | 3 | import { PeerTubeRequestError } from '@server/helpers/requests' |
3 | import { ActorLoadByUrlType } from '@server/lib/model-loaders' | 4 | import { ActorLoadByUrlType } from '@server/lib/model-loaders' |
4 | import { ActorModel } from '@server/models/actor/actor' | 5 | import { ActorModel } from '@server/models/actor/actor' |
@@ -8,11 +9,30 @@ import { fetchRemoteActor } from './shared' | |||
8 | import { APActorUpdater } from './updater' | 9 | import { APActorUpdater } from './updater' |
9 | import { getUrlFromWebfinger } from './webfinger' | 10 | import { getUrlFromWebfinger } from './webfinger' |
10 | 11 | ||
11 | async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> ( | 12 | type RefreshResult <T> = Promise<{ actor: T | MActorFull, refreshed: boolean }> |
12 | actorArg: T, | 13 | |
14 | type RefreshOptions <T> = { | ||
15 | actor: T | ||
13 | fetchedType: ActorLoadByUrlType | 16 | fetchedType: ActorLoadByUrlType |
14 | ): Promise<{ actor: T | MActorFull, refreshed: boolean }> { | 17 | } |
15 | if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false } | 18 | |
19 | const promiseCache = new PromiseCache(doRefresh, (options: RefreshOptions<MActorFull | MActorAccountChannelId>) => options.actor.url) | ||
20 | |||
21 | function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> (options: RefreshOptions<T>): RefreshResult <T> { | ||
22 | const actorArg = options.actor | ||
23 | if (!actorArg.isOutdated()) return Promise.resolve({ actor: actorArg, refreshed: false }) | ||
24 | |||
25 | return promiseCache.run(options) | ||
26 | } | ||
27 | |||
28 | export { | ||
29 | refreshActorIfNeeded | ||
30 | } | ||
31 | |||
32 | // --------------------------------------------------------------------------- | ||
33 | |||
34 | async function doRefresh <T extends MActorFull | MActorAccountChannelId> (options: RefreshOptions<T>): RefreshResult <MActorFull> { | ||
35 | const { actor: actorArg, fetchedType } = options | ||
16 | 36 | ||
17 | // We need more attributes | 37 | // We need more attributes |
18 | const actor = fetchedType === 'all' | 38 | const actor = fetchedType === 'all' |
@@ -52,12 +72,6 @@ async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannel | |||
52 | } | 72 | } |
53 | } | 73 | } |
54 | 74 | ||
55 | export { | ||
56 | refreshActorIfNeeded | ||
57 | } | ||
58 | |||
59 | // --------------------------------------------------------------------------- | ||
60 | |||
61 | function getActorUrl (actor: MActorFull) { | 75 | function getActorUrl (actor: MActorFull) { |
62 | return getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost()) | 76 | return getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost()) |
63 | .catch(err => { | 77 | .catch(err => { |
diff --git a/server/lib/job-queue/handlers/activitypub-refresher.ts b/server/lib/job-queue/handlers/activitypub-refresher.ts index f1c7d01b6..d97e50ebc 100644 --- a/server/lib/job-queue/handlers/activitypub-refresher.ts +++ b/server/lib/job-queue/handlers/activitypub-refresher.ts | |||
@@ -47,7 +47,7 @@ async function refreshActor (actorUrl: string) { | |||
47 | const actor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorUrl) | 47 | const actor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorUrl) |
48 | 48 | ||
49 | if (actor) { | 49 | if (actor) { |
50 | await refreshActorIfNeeded(actor, fetchType) | 50 | await refreshActorIfNeeded({ actor, fetchedType: fetchType }) |
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||