]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/activitypub/send/utils.ts
Fix requests timeout
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / send / utils.ts
CommitLineData
54141398 1import { Transaction } from 'sequelize'
7d9ba5c0
C
2import { getServerActor } from '@server/models/application/application'
3import { ContextType } from '@shared/models/activitypub/context'
a2377d15 4import { Activity, ActivityAudience } from '../../../../shared/models/activitypub'
7d9ba5c0 5import { afterCommitIfTransaction } from '../../../helpers/database-utils'
da854ddd 6import { logger } from '../../../helpers/logger'
7d9ba5c0
C
7import { ActorModel } from '../../../models/actor/actor'
8import { ActorFollowModel } from '../../../models/actor/actor-follow'
9import { MActor, MActorId, MActorLight, MActorWithInboxes, MVideoAccountLight, MVideoId, MVideoImmutable } from '../../../types/models'
94a5ff8a 10import { JobQueue } from '../../job-queue'
a2377d15 11import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience'
9588d4f4 12
a2377d15 13async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
a1587156 14 byActor: MActorLight
2c8776fc 15 video: MVideoImmutable | MVideoAccountLight
f51c02c7 16 transaction?: Transaction
598edb8a 17 contextType?: ContextType
a2377d15 18}) {
598edb8a 19 const { byActor, video, transaction, contextType } = options
5224c394
C
20
21 const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction)
a2377d15
C
22
23 // Send to origin
5224c394 24 if (video.isOwned() === false) {
06c27593
C
25 let accountActor: MActorLight = (video as MVideoAccountLight).VideoChannel?.Account?.Actor
26
27 if (!accountActor) accountActor = await ActorModel.loadAccountActorByVideoId(video.id, transaction)
2c8776fc
C
28
29 const audience = getRemoteVideoAudience(accountActor, actorsInvolvedInVideo)
a2377d15
C
30 const activity = activityBuilder(audience)
31
5224c394 32 return afterCommitIfTransaction(transaction, () => {
2c8776fc 33 return unicastTo(activity, byActor, accountActor.getSharedInbox(), contextType)
2284f202 34 })
a2377d15
C
35 }
36
37 // Send to followers
38 const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo)
39 const activity = activityBuilder(audience)
40
5224c394 41 const actorsException = [ byActor ]
2284f202 42
598edb8a 43 return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException, contextType)
a2377d15
C
44}
45
9588d4f4
C
46async function forwardVideoRelatedActivity (
47 activity: Activity,
48 t: Transaction,
bdd428a6 49 followersException: MActorWithInboxes[],
943e5193 50 video: MVideoId
9588d4f4
C
51) {
52 // Mastodon does not add our announces in audience, so we forward to them manually
53 const additionalActors = await getActorsInvolvedInVideo(video, t)
54 const additionalFollowerUrls = additionalActors.map(a => a.followersUrl)
55
56 return forwardActivity(activity, t, followersException, additionalFollowerUrls)
57}
63c93323
C
58
59async function forwardActivity (
60 activity: Activity,
61 t: Transaction,
47581df0 62 followersException: MActorWithInboxes[] = [],
93ef8a9d 63 additionalFollowerUrls: string[] = []
63c93323 64) {
8e0fd45e
C
65 logger.info('Forwarding activity %s.', activity.id)
66
63c93323
C
67 const to = activity.to || []
68 const cc = activity.cc || []
69
93ef8a9d 70 const followersUrls = additionalFollowerUrls
63c93323
C
71 for (const dest of to.concat(cc)) {
72 if (dest.endsWith('/followers')) {
73 followersUrls.push(dest)
74 }
75 }
76
50d6de9c
C
77 const toActorFollowers = await ActorModel.listByFollowersUrls(followersUrls, t)
78 const uris = await computeFollowerUris(toActorFollowers, followersException, t)
63c93323
C
79
80 if (uris.length === 0) {
50d6de9c 81 logger.info('0 followers for %s, no forwarding.', toActorFollowers.map(a => a.id).join(', '))
df1966c9 82 return undefined
63c93323
C
83 }
84
85 logger.debug('Creating forwarding job.', { uris })
86
94a5ff8a 87 const payload = {
63c93323
C
88 uris,
89 body: activity
90 }
2284f202 91 return afterCommitIfTransaction(t, () => JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }))
63c93323 92}
54141398 93
40ff5707
C
94async function broadcastToFollowers (
95 data: any,
453e83ea
C
96 byActor: MActorId,
97 toFollowersOf: MActorId[],
40ff5707 98 t: Transaction,
598edb8a
C
99 actorsException: MActorWithInboxes[] = [],
100 contextType?: ContextType
40ff5707 101) {
c48e82b5 102 const uris = await computeFollowerUris(toFollowersOf, actorsException, t)
2284f202 103
598edb8a 104 return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType))
93ef8a9d
C
105}
106
107async function broadcastToActors (
108 data: any,
453e83ea
C
109 byActor: MActorId,
110 toActors: MActor[],
2284f202 111 t?: Transaction,
598edb8a
C
112 actorsException: MActorWithInboxes[] = [],
113 contextType?: ContextType
93ef8a9d
C
114) {
115 const uris = await computeUris(toActors, actorsException)
598edb8a 116 return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType))
93ef8a9d
C
117}
118
598edb8a 119function broadcastTo (uris: string[], data: any, byActor: MActorId, contextType?: ContextType) {
93ef8a9d 120 if (uris.length === 0) return undefined
54141398 121
63c93323 122 logger.debug('Creating broadcast job.', { uris })
40ff5707 123
94a5ff8a 124 const payload = {
40ff5707 125 uris,
50d6de9c 126 signatureActorId: byActor.id,
598edb8a
C
127 body: data,
128 contextType
54141398
C
129 }
130
94a5ff8a 131 return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })
54141398
C
132}
133
598edb8a 134function unicastTo (data: any, byActor: MActorId, toActorUrl: string, contextType?: ContextType) {
50d6de9c 135 logger.debug('Creating unicast job.', { uri: toActorUrl })
63c93323 136
94a5ff8a
C
137 const payload = {
138 uri: toActorUrl,
50d6de9c 139 signatureActorId: byActor.id,
598edb8a
C
140 body: data,
141 contextType
54141398
C
142 }
143
2284f202 144 JobQueue.Instance.createJob({ type: 'activitypub-http-unicast', payload })
54141398
C
145}
146
e251f170 147// ---------------------------------------------------------------------------
54141398 148
e251f170
C
149export {
150 broadcastToFollowers,
151 unicastTo,
152 forwardActivity,
9588d4f4 153 broadcastToActors,
a2377d15
C
154 forwardVideoRelatedActivity,
155 sendVideoRelatedActivity
54141398
C
156}
157
e251f170 158// ---------------------------------------------------------------------------
e12a0092 159
47581df0 160async function computeFollowerUris (toFollowersOf: MActorId[], actorsException: MActorWithInboxes[], t: Transaction) {
c48e82b5 161 const toActorFollowerIds = toFollowersOf.map(a => a.id)
63c93323 162
50d6de9c 163 const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t)
06a05d5f
C
164 const sharedInboxesException = await buildSharedInboxesException(actorsException)
165
bdd428a6 166 return result.data.filter(sharedInbox => sharedInboxesException.includes(sharedInbox) === false)
93ef8a9d
C
167}
168
47581df0 169async function computeUris (toActors: MActor[], actorsException: MActorWithInboxes[] = []) {
06a05d5f
C
170 const serverActor = await getServerActor()
171 const targetUrls = toActors
172 .filter(a => a.id !== serverActor.id) // Don't send to ourselves
47581df0 173 .map(a => a.getSharedInbox())
06a05d5f
C
174
175 const toActorSharedInboxesSet = new Set(targetUrls)
93ef8a9d 176
06a05d5f 177 const sharedInboxesException = await buildSharedInboxesException(actorsException)
93ef8a9d 178 return Array.from(toActorSharedInboxesSet)
bdd428a6 179 .filter(sharedInbox => sharedInboxesException.includes(sharedInbox) === false)
54141398 180}
06a05d5f 181
47581df0 182async function buildSharedInboxesException (actorsException: MActorWithInboxes[]) {
06a05d5f
C
183 const serverActor = await getServerActor()
184
185 return actorsException
47581df0 186 .map(f => f.getSharedInbox())
06a05d5f
C
187 .concat([ serverActor.sharedInboxUrl ])
188}