aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-01-14 11:30:15 +0100
committerChocobozzz <me@florianbigard.com>2019-01-14 11:30:15 +0100
commit744d0eca195bce7dafeb4a958d0eb3c0046be32d (patch)
tree226c28f7fc63d1f6bf32095d7db0ef26a5b7073a /server/lib
parentbb8f7872f5a473c47a688b0c282ff34cd78a9835 (diff)
downloadPeerTube-744d0eca195bce7dafeb4a958d0eb3c0046be32d.tar.gz
PeerTube-744d0eca195bce7dafeb4a958d0eb3c0046be32d.tar.zst
PeerTube-744d0eca195bce7dafeb4a958d0eb3c0046be32d.zip
Refresh remote actors on GET enpoints
Diffstat (limited to 'server/lib')
-rw-r--r--server/lib/activitypub/actor.ts111
-rw-r--r--server/lib/activitypub/videos.ts2
-rw-r--r--server/lib/job-queue/handlers/activitypub-refresher.ts25
3 files changed, 77 insertions, 61 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index f80296725..d728c81d1 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -201,6 +201,62 @@ async function addFetchOutboxJob (actor: ActorModel) {
201 return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) 201 return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })
202} 202}
203 203
204async function refreshActorIfNeeded (
205 actorArg: ActorModel,
206 fetchedType: ActorFetchByUrlType
207): Promise<{ actor: ActorModel, refreshed: boolean }> {
208 if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false }
209
210 // We need more attributes
211 const actor = fetchedType === 'all' ? actorArg : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url)
212
213 try {
214 const actorUrl = await getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost())
215 const { result, statusCode } = await fetchRemoteActor(actorUrl)
216
217 if (statusCode === 404) {
218 logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url)
219 actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy()
220 return { actor: undefined, refreshed: false }
221 }
222
223 if (result === undefined) {
224 logger.warn('Cannot fetch remote actor in refresh actor.')
225 return { actor, refreshed: false }
226 }
227
228 return sequelizeTypescript.transaction(async t => {
229 updateInstanceWithAnother(actor, result.actor)
230
231 if (result.avatarName !== undefined) {
232 await updateActorAvatarInstance(actor, result.avatarName, t)
233 }
234
235 // Force update
236 actor.setDataValue('updatedAt', new Date())
237 await actor.save({ transaction: t })
238
239 if (actor.Account) {
240 actor.Account.set('name', result.name)
241 actor.Account.set('description', result.summary)
242
243 await actor.Account.save({ transaction: t })
244 } else if (actor.VideoChannel) {
245 actor.VideoChannel.set('name', result.name)
246 actor.VideoChannel.set('description', result.summary)
247 actor.VideoChannel.set('support', result.support)
248
249 await actor.VideoChannel.save({ transaction: t })
250 }
251
252 return { refreshed: true, actor }
253 })
254 } catch (err) {
255 logger.warn('Cannot refresh actor.', { err })
256 return { actor, refreshed: false }
257 }
258}
259
204export { 260export {
205 getOrCreateActorAndServerAndModel, 261 getOrCreateActorAndServerAndModel,
206 buildActorInstance, 262 buildActorInstance,
@@ -208,6 +264,7 @@ export {
208 fetchActorTotalItems, 264 fetchActorTotalItems,
209 fetchAvatarIfExists, 265 fetchAvatarIfExists,
210 updateActorInstance, 266 updateActorInstance,
267 refreshActorIfNeeded,
211 updateActorAvatarInstance, 268 updateActorAvatarInstance,
212 addFetchOutboxJob 269 addFetchOutboxJob
213} 270}
@@ -373,58 +430,4 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu
373 return videoChannelCreated 430 return videoChannelCreated
374} 431}
375 432
376async function refreshActorIfNeeded (
377 actorArg: ActorModel,
378 fetchedType: ActorFetchByUrlType
379): Promise<{ actor: ActorModel, refreshed: boolean }> {
380 if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false }
381
382 // We need more attributes
383 const actor = fetchedType === 'all' ? actorArg : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url)
384
385 try {
386 const actorUrl = await getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost())
387 const { result, statusCode } = await fetchRemoteActor(actorUrl)
388
389 if (statusCode === 404) {
390 logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url)
391 actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy()
392 return { actor: undefined, refreshed: false }
393 }
394
395 if (result === undefined) {
396 logger.warn('Cannot fetch remote actor in refresh actor.')
397 return { actor, refreshed: false }
398 }
399 433
400 return sequelizeTypescript.transaction(async t => {
401 updateInstanceWithAnother(actor, result.actor)
402
403 if (result.avatarName !== undefined) {
404 await updateActorAvatarInstance(actor, result.avatarName, t)
405 }
406
407 // Force update
408 actor.setDataValue('updatedAt', new Date())
409 await actor.save({ transaction: t })
410
411 if (actor.Account) {
412 actor.Account.set('name', result.name)
413 actor.Account.set('description', result.summary)
414
415 await actor.Account.save({ transaction: t })
416 } else if (actor.VideoChannel) {
417 actor.VideoChannel.set('name', result.name)
418 actor.VideoChannel.set('description', result.summary)
419 actor.VideoChannel.set('support', result.support)
420
421 await actor.VideoChannel.save({ transaction: t })
422 }
423
424 return { refreshed: true, actor }
425 })
426 } catch (err) {
427 logger.warn('Cannot refresh actor.', { err })
428 return { actor, refreshed: false }
429 }
430}
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index 893768769..cbdd981c5 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -179,7 +179,7 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
179 } 179 }
180 180
181 if (syncParam.refreshVideo === true) videoFromDatabase = await refreshVideoIfNeeded(refreshOptions) 181 if (syncParam.refreshVideo === true) videoFromDatabase = await refreshVideoIfNeeded(refreshOptions)
182 else await JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', videoUrl: videoFromDatabase.url } }) 182 else await JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: videoFromDatabase.url } })
183 } 183 }
184 184
185 return { video: videoFromDatabase, created: false } 185 return { video: videoFromDatabase, created: false }
diff --git a/server/lib/job-queue/handlers/activitypub-refresher.ts b/server/lib/job-queue/handlers/activitypub-refresher.ts
index 671b0f487..454b975fe 100644
--- a/server/lib/job-queue/handlers/activitypub-refresher.ts
+++ b/server/lib/job-queue/handlers/activitypub-refresher.ts
@@ -1,30 +1,33 @@
1import * as Bull from 'bull' 1import * as Bull from 'bull'
2import { logger } from '../../../helpers/logger' 2import { logger } from '../../../helpers/logger'
3import { fetchVideoByUrl } from '../../../helpers/video' 3import { fetchVideoByUrl } from '../../../helpers/video'
4import { refreshVideoIfNeeded } from '../../activitypub' 4import { refreshVideoIfNeeded, refreshActorIfNeeded } from '../../activitypub'
5import { ActorModel } from '../../../models/activitypub/actor'
5 6
6export type RefreshPayload = { 7export type RefreshPayload = {
7 videoUrl: string 8 type: 'video' | 'actor'
8 type: 'video' 9 url: string
9} 10}
10 11
11async function refreshAPObject (job: Bull.Job) { 12async function refreshAPObject (job: Bull.Job) {
12 const payload = job.data as RefreshPayload 13 const payload = job.data as RefreshPayload
13 14
14 logger.info('Processing AP refresher in job %d for video %s.', job.id, payload.videoUrl) 15 logger.info('Processing AP refresher in job %d for %s.', job.id, payload.url)
15 16
16 if (payload.type === 'video') return refreshAPVideo(payload.videoUrl) 17 if (payload.type === 'video') return refreshVideo(payload.url)
18 if (payload.type === 'actor') return refreshActor(payload.url)
17} 19}
18 20
19// --------------------------------------------------------------------------- 21// ---------------------------------------------------------------------------
20 22
21export { 23export {
24 refreshActor,
22 refreshAPObject 25 refreshAPObject
23} 26}
24 27
25// --------------------------------------------------------------------------- 28// ---------------------------------------------------------------------------
26 29
27async function refreshAPVideo (videoUrl: string) { 30async function refreshVideo (videoUrl: string) {
28 const fetchType = 'all' as 'all' 31 const fetchType = 'all' as 'all'
29 const syncParam = { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true } 32 const syncParam = { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true }
30 33
@@ -39,3 +42,13 @@ async function refreshAPVideo (videoUrl: string) {
39 await refreshVideoIfNeeded(refreshOptions) 42 await refreshVideoIfNeeded(refreshOptions)
40 } 43 }
41} 44}
45
46async function refreshActor (actorUrl: string) {
47 const fetchType = 'all' as 'all'
48 const actor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorUrl)
49
50 if (actor) {
51 await refreshActorIfNeeded(actor, fetchType)
52 }
53
54}