diff options
author | Chocobozzz <me@florianbigard.com> | 2019-01-14 11:30:15 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-01-14 11:30:15 +0100 |
commit | 744d0eca195bce7dafeb4a958d0eb3c0046be32d (patch) | |
tree | 226c28f7fc63d1f6bf32095d7db0ef26a5b7073a /server/lib | |
parent | bb8f7872f5a473c47a688b0c282ff34cd78a9835 (diff) | |
download | PeerTube-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.ts | 111 | ||||
-rw-r--r-- | server/lib/activitypub/videos.ts | 2 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/activitypub-refresher.ts | 25 |
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 | ||
204 | async 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 | |||
204 | export { | 260 | export { |
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 | ||
376 | async 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 @@ | |||
1 | import * as Bull from 'bull' | 1 | import * as Bull from 'bull' |
2 | import { logger } from '../../../helpers/logger' | 2 | import { logger } from '../../../helpers/logger' |
3 | import { fetchVideoByUrl } from '../../../helpers/video' | 3 | import { fetchVideoByUrl } from '../../../helpers/video' |
4 | import { refreshVideoIfNeeded } from '../../activitypub' | 4 | import { refreshVideoIfNeeded, refreshActorIfNeeded } from '../../activitypub' |
5 | import { ActorModel } from '../../../models/activitypub/actor' | ||
5 | 6 | ||
6 | export type RefreshPayload = { | 7 | export type RefreshPayload = { |
7 | videoUrl: string | 8 | type: 'video' | 'actor' |
8 | type: 'video' | 9 | url: string |
9 | } | 10 | } |
10 | 11 | ||
11 | async function refreshAPObject (job: Bull.Job) { | 12 | async 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 | ||
21 | export { | 23 | export { |
24 | refreshActor, | ||
22 | refreshAPObject | 25 | refreshAPObject |
23 | } | 26 | } |
24 | 27 | ||
25 | // --------------------------------------------------------------------------- | 28 | // --------------------------------------------------------------------------- |
26 | 29 | ||
27 | async function refreshAPVideo (videoUrl: string) { | 30 | async 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 | |||
46 | async 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 | } | ||