]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Cache refresh actor promise
authorChocobozzz <me@florianbigard.com>
Wed, 9 Jun 2021 11:34:40 +0000 (13:34 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 9 Jun 2021 11:34:40 +0000 (13:34 +0200)
client/src/app/shared/shared-custom-markup/custom-markup.service.ts
server/helpers/promise-cache.ts [new file with mode: 0644]
server/lib/activitypub/actors/get.ts
server/lib/activitypub/actors/refresh.ts
server/lib/job-queue/handlers/activitypub-refresher.ts
shared/models/custom-markup/custom-markup-data.model.ts

index 729cd296b7f10018fa0d058b6200584397747580..cb1110593f8f3e2bf419c7de944a9a0a7949ef60 100644 (file)
@@ -138,10 +138,10 @@ export class CustomMarkupService {
     const component = this.dynamicElementService.createElement(ButtonMarkupComponent)
 
     const model = {
-      theme: data.theme,
+      theme: data.theme ?? 'primary',
       href: data.href,
       label: data.label,
-      blankTarget: this.buildBoolean(data.blankTarget)
+      blankTarget: this.buildBoolean(data.blankTarget) ?? false
     }
     this.dynamicElementService.setModel(component, model)
 
diff --git a/server/helpers/promise-cache.ts b/server/helpers/promise-cache.ts
new file mode 100644 (file)
index 0000000..07e8a99
--- /dev/null
@@ -0,0 +1,21 @@
+export class PromiseCache <A, R> {
+  private readonly running = new Map<string, Promise<R>>()
+
+  constructor (
+    private readonly fn: (arg: A) => Promise<R>,
+    private readonly keyBuilder: (arg: A) => string
+  ) {
+  }
+
+  run (arg: A) {
+    const key = this.keyBuilder(arg)
+
+    if (this.running.has(key)) return this.running.get(key)
+
+    const p = this.fn(arg)
+
+    this.running.set(key, p)
+
+    return p.finally(() => this.running.delete(key))
+  }
+}
index de93aa9643f70689a20cd1a85e23175c3921d282..501ff74e337a7a2759a7ae8af9ab12415e35826e 100644 (file)
@@ -56,7 +56,7 @@ async function getOrCreateAPActor (
   if (actor.Account) (actor as MActorAccountChannelIdActor).Account.Actor = actor
   if (actor.VideoChannel) (actor as MActorAccountChannelIdActor).VideoChannel.Actor = actor
 
-  const { actor: actorRefreshed, refreshed } = await refreshActorIfNeeded(actor, fetchType)
+  const { actor: actorRefreshed, refreshed } = await refreshActorIfNeeded({ actor, fetchedType: fetchType })
   if (!actorRefreshed) throw new Error('Actor ' + actor.url + ' does not exist anymore.')
 
   await scheduleOutboxFetchIfNeeded(actor, created, refreshed, updateCollections)
index 1f7cfcd8fb32ee17312ab55a17e9296e91bb8167..b2fe3932fff848d846912d813b023858b84426b5 100644 (file)
@@ -1,4 +1,5 @@
 import { logger, loggerTagsFactory } from '@server/helpers/logger'
+import { PromiseCache } from '@server/helpers/promise-cache'
 import { PeerTubeRequestError } from '@server/helpers/requests'
 import { ActorLoadByUrlType } from '@server/lib/model-loaders'
 import { ActorModel } from '@server/models/actor/actor'
@@ -8,11 +9,30 @@ import { fetchRemoteActor } from './shared'
 import { APActorUpdater } from './updater'
 import { getUrlFromWebfinger } from './webfinger'
 
-async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> (
-  actorArg: T,
+type RefreshResult <T> = Promise<{ actor: T | MActorFull, refreshed: boolean }>
+
+type RefreshOptions <T> = {
+  actor: T
   fetchedType: ActorLoadByUrlType
-): Promise<{ actor: T | MActorFull, refreshed: boolean }> {
-  if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false }
+}
+
+const promiseCache = new PromiseCache(doRefresh, (options: RefreshOptions<MActorFull | MActorAccountChannelId>) => options.actor.url)
+
+function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> (options: RefreshOptions<T>): RefreshResult <T> {
+  const actorArg = options.actor
+  if (!actorArg.isOutdated()) return Promise.resolve({ actor: actorArg, refreshed: false })
+
+  return promiseCache.run(options)
+}
+
+export {
+  refreshActorIfNeeded
+}
+
+// ---------------------------------------------------------------------------
+
+async function doRefresh <T extends MActorFull | MActorAccountChannelId> (options: RefreshOptions<T>): RefreshResult <MActorFull> {
+  const { actor: actorArg, fetchedType } = options
 
   // We need more attributes
   const actor = fetchedType === 'all'
@@ -52,12 +72,6 @@ async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannel
   }
 }
 
-export {
-  refreshActorIfNeeded
-}
-
-// ---------------------------------------------------------------------------
-
 function getActorUrl (actor: MActorFull) {
   return getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost())
     .catch(err => {
index f1c7d01b6e67da9e3ef25b481504a2cbe1ad971b..d97e50ebc4b3acf3a7c9638dab2aa02d168d8181 100644 (file)
@@ -47,7 +47,7 @@ async function refreshActor (actorUrl: string) {
   const actor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorUrl)
 
   if (actor) {
-    await refreshActorIfNeeded(actor, fetchType)
+    await refreshActorIfNeeded({ actor, fetchedType: fetchType })
   }
 }
 
index 06c9b544d9120530be13550b031a1c389c6e232f..c5649448524830e614d4388776aaf0f7fac30ebe 100644 (file)
@@ -34,7 +34,6 @@ export type VideosListMarkupData = {
   languageOneOf?: string // coma separated values
 
   onlyLocal?: string // boolean
-
 }
 
 export type ButtonMarkupData = {