aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/shared/shared-custom-markup/custom-markup.service.ts4
-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
-rw-r--r--shared/models/custom-markup/custom-markup-data.model.ts1
6 files changed, 49 insertions, 15 deletions
diff --git a/client/src/app/shared/shared-custom-markup/custom-markup.service.ts b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts
index 729cd296b..cb1110593 100644
--- a/client/src/app/shared/shared-custom-markup/custom-markup.service.ts
+++ b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts
@@ -138,10 +138,10 @@ export class CustomMarkupService {
138 const component = this.dynamicElementService.createElement(ButtonMarkupComponent) 138 const component = this.dynamicElementService.createElement(ButtonMarkupComponent)
139 139
140 const model = { 140 const model = {
141 theme: data.theme, 141 theme: data.theme ?? 'primary',
142 href: data.href, 142 href: data.href,
143 label: data.label, 143 label: data.label,
144 blankTarget: this.buildBoolean(data.blankTarget) 144 blankTarget: this.buildBoolean(data.blankTarget) ?? false
145 } 145 }
146 this.dynamicElementService.setModel(component, model) 146 this.dynamicElementService.setModel(component, model)
147 147
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
diff --git a/shared/models/custom-markup/custom-markup-data.model.ts b/shared/models/custom-markup/custom-markup-data.model.ts
index 06c9b544d..c56494485 100644
--- a/shared/models/custom-markup/custom-markup-data.model.ts
+++ b/shared/models/custom-markup/custom-markup-data.model.ts
@@ -34,7 +34,6 @@ export type VideosListMarkupData = {
34 languageOneOf?: string // coma separated values 34 languageOneOf?: string // coma separated values
35 35
36 onlyLocal?: string // boolean 36 onlyLocal?: string // boolean
37
38} 37}
39 38
40export type ButtonMarkupData = { 39export type ButtonMarkupData = {