]>
Commit | Line | Data |
---|---|---|
1 | import { Transaction } from 'sequelize' | |
2 | import { Activity } from '../../../../shared/models/activitypub' | |
3 | import { logger } from '../../../helpers' | |
4 | import { ACTIVITY_PUB } from '../../../initializers' | |
5 | import { ActorModel } from '../../../models/activitypub/actor' | |
6 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | |
7 | import { VideoModel } from '../../../models/video/video' | |
8 | import { VideoShareModel } from '../../../models/video/video-share' | |
9 | import { activitypubHttpJobScheduler, ActivityPubHttpPayload } from '../../jobs/activitypub-http-job-scheduler' | |
10 | ||
11 | async function forwardActivity ( | |
12 | activity: Activity, | |
13 | t: Transaction, | |
14 | followersException: ActorModel[] = [] | |
15 | ) { | |
16 | const to = activity.to || [] | |
17 | const cc = activity.cc || [] | |
18 | ||
19 | const followersUrls: string[] = [] | |
20 | for (const dest of to.concat(cc)) { | |
21 | if (dest.endsWith('/followers')) { | |
22 | followersUrls.push(dest) | |
23 | } | |
24 | } | |
25 | ||
26 | const toActorFollowers = await ActorModel.listByFollowersUrls(followersUrls, t) | |
27 | const uris = await computeFollowerUris(toActorFollowers, followersException, t) | |
28 | ||
29 | if (uris.length === 0) { | |
30 | logger.info('0 followers for %s, no forwarding.', toActorFollowers.map(a => a.id).join(', ')) | |
31 | return undefined | |
32 | } | |
33 | ||
34 | logger.debug('Creating forwarding job.', { uris }) | |
35 | ||
36 | const jobPayload: ActivityPubHttpPayload = { | |
37 | uris, | |
38 | body: activity | |
39 | } | |
40 | ||
41 | return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload) | |
42 | } | |
43 | ||
44 | async function broadcastToFollowers ( | |
45 | data: any, | |
46 | byActor: ActorModel, | |
47 | toActorFollowers: ActorModel[], | |
48 | t: Transaction, | |
49 | followersException: ActorModel[] = [] | |
50 | ) { | |
51 | const uris = await computeFollowerUris(toActorFollowers, followersException, t) | |
52 | if (uris.length === 0) { | |
53 | logger.info('0 followers for %s, no broadcasting.', toActorFollowers.map(a => a.id).join(', ')) | |
54 | return undefined | |
55 | } | |
56 | ||
57 | logger.debug('Creating broadcast job.', { uris }) | |
58 | ||
59 | const jobPayload: ActivityPubHttpPayload = { | |
60 | uris, | |
61 | signatureActorId: byActor.id, | |
62 | body: data | |
63 | } | |
64 | ||
65 | return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload) | |
66 | } | |
67 | ||
68 | async function unicastTo (data: any, byActor: ActorModel, toActorUrl: string, t: Transaction) { | |
69 | logger.debug('Creating unicast job.', { uri: toActorUrl }) | |
70 | ||
71 | const jobPayload: ActivityPubHttpPayload = { | |
72 | uris: [ toActorUrl ], | |
73 | signatureActorId: byActor.id, | |
74 | body: data | |
75 | } | |
76 | ||
77 | return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload) | |
78 | } | |
79 | ||
80 | function getOriginVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]) { | |
81 | return { | |
82 | to: [ video.VideoChannel.Account.Actor.url ], | |
83 | cc: actorsInvolvedInVideo.map(a => a.followersUrl) | |
84 | } | |
85 | } | |
86 | ||
87 | function getObjectFollowersAudience (actorsInvolvedInObject: ActorModel[]) { | |
88 | return { | |
89 | to: actorsInvolvedInObject.map(a => a.followersUrl), | |
90 | cc: [] | |
91 | } | |
92 | } | |
93 | ||
94 | async function getActorsInvolvedInVideo (video: VideoModel, t: Transaction) { | |
95 | const actorsToForwardView = await VideoShareModel.loadActorsByShare(video.id, t) | |
96 | actorsToForwardView.push(video.VideoChannel.Account.Actor) | |
97 | ||
98 | return actorsToForwardView | |
99 | } | |
100 | ||
101 | async function getAudience (actorSender: ActorModel, t: Transaction, isPublic = true) { | |
102 | const followerInboxUrls = await actorSender.getFollowerSharedInboxUrls(t) | |
103 | ||
104 | // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47 | |
105 | let to = [] | |
106 | let cc = [] | |
107 | ||
108 | if (isPublic) { | |
109 | to = [ ACTIVITY_PUB.PUBLIC ] | |
110 | cc = followerInboxUrls | |
111 | } else { // Unlisted | |
112 | to = followerInboxUrls | |
113 | cc = [ ACTIVITY_PUB.PUBLIC ] | |
114 | } | |
115 | ||
116 | return { to, cc } | |
117 | } | |
118 | ||
119 | async function computeFollowerUris (toActorFollower: ActorModel[], followersException: ActorModel[], t: Transaction) { | |
120 | const toActorFollowerIds = toActorFollower.map(a => a.id) | |
121 | ||
122 | const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t) | |
123 | const followersSharedInboxException = followersException.map(f => f.sharedInboxUrl) | |
124 | return result.data.filter(sharedInbox => followersSharedInboxException.indexOf(sharedInbox) === -1) | |
125 | } | |
126 | ||
127 | // --------------------------------------------------------------------------- | |
128 | ||
129 | export { | |
130 | broadcastToFollowers, | |
131 | unicastTo, | |
132 | getAudience, | |
133 | getOriginVideoAudience, | |
134 | getActorsInvolvedInVideo, | |
135 | getObjectFollowersAudience, | |
136 | forwardActivity | |
137 | } |