aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/helpers/promise-cache.ts21
-rw-r--r--server/lib/activitypub/actors/get.ts2
-rw-r--r--server/lib/activitypub/actors/refresh.ts34
-rw-r--r--server/lib/job-queue/handlers/activitypub-refresher.ts2
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 @@
1export 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 @@
1import { logger, loggerTagsFactory } from '@server/helpers/logger' 1import { logger, loggerTagsFactory } from '@server/helpers/logger'
2import { PromiseCache } from '@server/helpers/promise-cache'
2import { PeerTubeRequestError } from '@server/helpers/requests' 3import { PeerTubeRequestError } from '@server/helpers/requests'
3import { ActorLoadByUrlType } from '@server/lib/model-loaders' 4import { ActorLoadByUrlType } from '@server/lib/model-loaders'
4import { ActorModel } from '@server/models/actor/actor' 5import { ActorModel } from '@server/models/actor/actor'
@@ -8,11 +9,30 @@ import { fetchRemoteActor } from './shared'
8import { APActorUpdater } from './updater' 9import { APActorUpdater } from './updater'
9import { getUrlFromWebfinger } from './webfinger' 10import { getUrlFromWebfinger } from './webfinger'
10 11
11async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> ( 12type RefreshResult <T> = Promise<{ actor: T | MActorFull, refreshed: boolean }>
12 actorArg: T, 13
14type 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
19const promiseCache = new PromiseCache(doRefresh, (options: RefreshOptions<MActorFull | MActorAccountChannelId>) => options.actor.url)
20
21function 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
28export {
29 refreshActorIfNeeded
30}
31
32// ---------------------------------------------------------------------------
33
34async 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
55export {
56 refreshActorIfNeeded
57}
58
59// ---------------------------------------------------------------------------
60
61function getActorUrl (actor: MActorFull) { 75function 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