diff options
author | Chocobozzz <me@florianbigard.com> | 2022-03-23 16:14:33 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-03-24 09:40:46 +0100 |
commit | a219c9100b3ce8774d454497d46be87465bf664e (patch) | |
tree | caa869e47919a9e23cc86dcece1100e239683b8c /server/lib/activitypub | |
parent | 7e98a7df7d04e19ba67163a86c7b876d78d76839 (diff) | |
download | PeerTube-a219c9100b3ce8774d454497d46be87465bf664e.tar.gz PeerTube-a219c9100b3ce8774d454497d46be87465bf664e.tar.zst PeerTube-a219c9100b3ce8774d454497d46be87465bf664e.zip |
Refactor AP context builder
Diffstat (limited to 'server/lib/activitypub')
-rw-r--r-- | server/lib/activitypub/activity.ts | 12 | ||||
-rw-r--r-- | server/lib/activitypub/audience.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/context.ts | 275 | ||||
-rw-r--r-- | server/lib/activitypub/send/http.ts | 68 | ||||
-rw-r--r-- | server/lib/activitypub/send/index.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-accept.ts | 7 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-announce.ts | 14 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-create.ts | 67 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-delete.ts | 67 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-dislike.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-flag.ts | 14 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-follow.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-like.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-reject.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-undo.ts | 50 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-update.ts | 44 | ||||
-rw-r--r-- | server/lib/activitypub/send/shared/send-utils.ts | 104 |
17 files changed, 507 insertions, 233 deletions
diff --git a/server/lib/activitypub/activity.ts b/server/lib/activitypub/activity.ts index 215b50b69..cccb7b1c1 100644 --- a/server/lib/activitypub/activity.ts +++ b/server/lib/activitypub/activity.ts | |||
@@ -1,14 +1,3 @@ | |||
1 | import { signJsonLDObject } from '@server/helpers/peertube-crypto' | ||
2 | import { MActor } from '@server/types/models' | ||
3 | import { ContextType } from '@shared/models' | ||
4 | import { activityPubContextify } from './context' | ||
5 | |||
6 | function buildSignedActivity <T> (byActor: MActor, data: T, contextType?: ContextType) { | ||
7 | const activity = activityPubContextify(data, contextType) | ||
8 | |||
9 | return signJsonLDObject(byActor, activity) | ||
10 | } | ||
11 | |||
12 | function getAPId (object: string | { id: string }) { | 1 | function getAPId (object: string | { id: string }) { |
13 | if (typeof object === 'string') return object | 2 | if (typeof object === 'string') return object |
14 | 3 | ||
@@ -16,6 +5,5 @@ function getAPId (object: string | { id: string }) { | |||
16 | } | 5 | } |
17 | 6 | ||
18 | export { | 7 | export { |
19 | buildSignedActivity, | ||
20 | getAPId | 8 | getAPId |
21 | } | 9 | } |
diff --git a/server/lib/activitypub/audience.ts b/server/lib/activitypub/audience.ts index 2bd5bb066..6f5491387 100644 --- a/server/lib/activitypub/audience.ts +++ b/server/lib/activitypub/audience.ts | |||
@@ -22,7 +22,7 @@ function buildAudience (followerUrls: string[], isPublic = true) { | |||
22 | } | 22 | } |
23 | 23 | ||
24 | function audiencify<T> (object: T, audience: ActivityAudience) { | 24 | function audiencify<T> (object: T, audience: ActivityAudience) { |
25 | return Object.assign(object, audience) | 25 | return { ...audience, ...object } |
26 | } | 26 | } |
27 | 27 | ||
28 | // --------------------------------------------------------------------------- | 28 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/context.ts b/server/lib/activitypub/context.ts index 71f08da80..3bc40e2aa 100644 --- a/server/lib/activitypub/context.ts +++ b/server/lib/activitypub/context.ts | |||
@@ -1,137 +1,168 @@ | |||
1 | import { ContextType } from '@shared/models' | 1 | import { ContextType } from '@shared/models' |
2 | 2 | ||
3 | function getContextData (type: ContextType) { | 3 | function activityPubContextify <T> (data: T, type: ContextType) { |
4 | const context: any[] = [ | 4 | return { ...getContextData(type), ...data } |
5 | 'https://www.w3.org/ns/activitystreams', | 5 | } |
6 | 'https://w3id.org/security/v1', | 6 | |
7 | { | 7 | // --------------------------------------------------------------------------- |
8 | RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' | 8 | |
9 | export { | ||
10 | getContextData, | ||
11 | activityPubContextify | ||
12 | } | ||
13 | |||
14 | // --------------------------------------------------------------------------- | ||
15 | |||
16 | type ContextValue = { [ id: string ]: (string | { '@type': string, '@id': string }) } | ||
17 | |||
18 | const contextStore = { | ||
19 | Video: buildContext({ | ||
20 | Hashtag: 'as:Hashtag', | ||
21 | uuid: 'sc:identifier', | ||
22 | category: 'sc:category', | ||
23 | licence: 'sc:license', | ||
24 | subtitleLanguage: 'sc:subtitleLanguage', | ||
25 | sensitive: 'as:sensitive', | ||
26 | language: 'sc:inLanguage', | ||
27 | |||
28 | // TODO: remove in a few versions, introduced in 4.2 | ||
29 | icons: 'as:icon', | ||
30 | |||
31 | isLiveBroadcast: 'sc:isLiveBroadcast', | ||
32 | liveSaveReplay: { | ||
33 | '@type': 'sc:Boolean', | ||
34 | '@id': 'pt:liveSaveReplay' | ||
35 | }, | ||
36 | permanentLive: { | ||
37 | '@type': 'sc:Boolean', | ||
38 | '@id': 'pt:permanentLive' | ||
39 | }, | ||
40 | latencyMode: { | ||
41 | '@type': 'sc:Number', | ||
42 | '@id': 'pt:latencyMode' | ||
43 | }, | ||
44 | |||
45 | Infohash: 'pt:Infohash', | ||
46 | |||
47 | originallyPublishedAt: 'sc:datePublished', | ||
48 | views: { | ||
49 | '@type': 'sc:Number', | ||
50 | '@id': 'pt:views' | ||
51 | }, | ||
52 | state: { | ||
53 | '@type': 'sc:Number', | ||
54 | '@id': 'pt:state' | ||
55 | }, | ||
56 | size: { | ||
57 | '@type': 'sc:Number', | ||
58 | '@id': 'pt:size' | ||
59 | }, | ||
60 | fps: { | ||
61 | '@type': 'sc:Number', | ||
62 | '@id': 'pt:fps' | ||
63 | }, | ||
64 | commentsEnabled: { | ||
65 | '@type': 'sc:Boolean', | ||
66 | '@id': 'pt:commentsEnabled' | ||
67 | }, | ||
68 | downloadEnabled: { | ||
69 | '@type': 'sc:Boolean', | ||
70 | '@id': 'pt:downloadEnabled' | ||
71 | }, | ||
72 | waitTranscoding: { | ||
73 | '@type': 'sc:Boolean', | ||
74 | '@id': 'pt:waitTranscoding' | ||
75 | }, | ||
76 | support: { | ||
77 | '@type': 'sc:Text', | ||
78 | '@id': 'pt:support' | ||
79 | }, | ||
80 | likes: { | ||
81 | '@id': 'as:likes', | ||
82 | '@type': '@id' | ||
83 | }, | ||
84 | dislikes: { | ||
85 | '@id': 'as:dislikes', | ||
86 | '@type': '@id' | ||
87 | }, | ||
88 | shares: { | ||
89 | '@id': 'as:shares', | ||
90 | '@type': '@id' | ||
91 | }, | ||
92 | comments: { | ||
93 | '@id': 'as:comments', | ||
94 | '@type': '@id' | ||
9 | } | 95 | } |
10 | ] | 96 | }), |
11 | 97 | ||
12 | if (type !== 'View' && type !== 'Announce') { | 98 | Playlist: buildContext({ |
13 | const additional = { | 99 | Playlist: 'pt:Playlist', |
14 | pt: 'https://joinpeertube.org/ns#', | 100 | PlaylistElement: 'pt:PlaylistElement', |
15 | sc: 'http://schema.org#' | 101 | position: { |
102 | '@type': 'sc:Number', | ||
103 | '@id': 'pt:position' | ||
104 | }, | ||
105 | startTimestamp: { | ||
106 | '@type': 'sc:Number', | ||
107 | '@id': 'pt:startTimestamp' | ||
108 | }, | ||
109 | stopTimestamp: { | ||
110 | '@type': 'sc:Number', | ||
111 | '@id': 'pt:stopTimestamp' | ||
16 | } | 112 | } |
113 | }), | ||
114 | |||
115 | CacheFile: buildContext({ | ||
116 | expires: 'sc:expires', | ||
117 | CacheFile: 'pt:CacheFile' | ||
118 | }), | ||
17 | 119 | ||
18 | if (type === 'CacheFile') { | 120 | Flag: buildContext({ |
19 | Object.assign(additional, { | 121 | Hashtag: 'as:Hashtag' |
20 | expires: 'sc:expires', | 122 | }), |
21 | CacheFile: 'pt:CacheFile' | 123 | |
22 | }) | 124 | Actor: buildContext({ |
23 | } else { | 125 | playlists: { |
24 | Object.assign(additional, { | 126 | '@id': 'pt:playlists', |
25 | Hashtag: 'as:Hashtag', | 127 | '@type': '@id' |
26 | uuid: 'sc:identifier', | ||
27 | category: 'sc:category', | ||
28 | licence: 'sc:license', | ||
29 | subtitleLanguage: 'sc:subtitleLanguage', | ||
30 | sensitive: 'as:sensitive', | ||
31 | language: 'sc:inLanguage', | ||
32 | |||
33 | // TODO: remove in a few versions, introduced in 4.2 | ||
34 | icons: 'as:icon', | ||
35 | |||
36 | isLiveBroadcast: 'sc:isLiveBroadcast', | ||
37 | liveSaveReplay: { | ||
38 | '@type': 'sc:Boolean', | ||
39 | '@id': 'pt:liveSaveReplay' | ||
40 | }, | ||
41 | permanentLive: { | ||
42 | '@type': 'sc:Boolean', | ||
43 | '@id': 'pt:permanentLive' | ||
44 | }, | ||
45 | latencyMode: { | ||
46 | '@type': 'sc:Number', | ||
47 | '@id': 'pt:latencyMode' | ||
48 | }, | ||
49 | |||
50 | Infohash: 'pt:Infohash', | ||
51 | Playlist: 'pt:Playlist', | ||
52 | PlaylistElement: 'pt:PlaylistElement', | ||
53 | |||
54 | originallyPublishedAt: 'sc:datePublished', | ||
55 | views: { | ||
56 | '@type': 'sc:Number', | ||
57 | '@id': 'pt:views' | ||
58 | }, | ||
59 | state: { | ||
60 | '@type': 'sc:Number', | ||
61 | '@id': 'pt:state' | ||
62 | }, | ||
63 | size: { | ||
64 | '@type': 'sc:Number', | ||
65 | '@id': 'pt:size' | ||
66 | }, | ||
67 | fps: { | ||
68 | '@type': 'sc:Number', | ||
69 | '@id': 'pt:fps' | ||
70 | }, | ||
71 | startTimestamp: { | ||
72 | '@type': 'sc:Number', | ||
73 | '@id': 'pt:startTimestamp' | ||
74 | }, | ||
75 | stopTimestamp: { | ||
76 | '@type': 'sc:Number', | ||
77 | '@id': 'pt:stopTimestamp' | ||
78 | }, | ||
79 | position: { | ||
80 | '@type': 'sc:Number', | ||
81 | '@id': 'pt:position' | ||
82 | }, | ||
83 | commentsEnabled: { | ||
84 | '@type': 'sc:Boolean', | ||
85 | '@id': 'pt:commentsEnabled' | ||
86 | }, | ||
87 | downloadEnabled: { | ||
88 | '@type': 'sc:Boolean', | ||
89 | '@id': 'pt:downloadEnabled' | ||
90 | }, | ||
91 | waitTranscoding: { | ||
92 | '@type': 'sc:Boolean', | ||
93 | '@id': 'pt:waitTranscoding' | ||
94 | }, | ||
95 | support: { | ||
96 | '@type': 'sc:Text', | ||
97 | '@id': 'pt:support' | ||
98 | }, | ||
99 | likes: { | ||
100 | '@id': 'as:likes', | ||
101 | '@type': '@id' | ||
102 | }, | ||
103 | dislikes: { | ||
104 | '@id': 'as:dislikes', | ||
105 | '@type': '@id' | ||
106 | }, | ||
107 | playlists: { | ||
108 | '@id': 'pt:playlists', | ||
109 | '@type': '@id' | ||
110 | }, | ||
111 | shares: { | ||
112 | '@id': 'as:shares', | ||
113 | '@type': '@id' | ||
114 | }, | ||
115 | comments: { | ||
116 | '@id': 'as:comments', | ||
117 | '@type': '@id' | ||
118 | } | ||
119 | }) | ||
120 | } | 128 | } |
129 | }), | ||
121 | 130 | ||
122 | context.push(additional) | 131 | Follow: buildContext(), |
123 | } | 132 | Reject: buildContext(), |
133 | Accept: buildContext(), | ||
134 | View: buildContext(), | ||
135 | Announce: buildContext(), | ||
136 | Comment: buildContext(), | ||
137 | Delete: buildContext(), | ||
138 | Rate: buildContext() | ||
139 | } | ||
124 | 140 | ||
141 | function getContextData (type: ContextType) { | ||
125 | return { | 142 | return { |
126 | '@context': context | 143 | '@context': contextStore[type] |
127 | } | 144 | } |
128 | } | 145 | } |
129 | 146 | ||
130 | function activityPubContextify <T> (data: T, type: ContextType = 'All') { | 147 | function buildContext (contextValue?: ContextValue) { |
131 | return Object.assign({}, data, getContextData(type)) | 148 | const baseContext = [ |
132 | } | 149 | 'https://www.w3.org/ns/activitystreams', |
150 | 'https://w3id.org/security/v1', | ||
151 | { | ||
152 | RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' | ||
153 | } | ||
154 | ] | ||
133 | 155 | ||
134 | export { | 156 | if (!contextValue) return baseContext |
135 | getContextData, | 157 | |
136 | activityPubContextify | 158 | return [ |
159 | ...baseContext, | ||
160 | |||
161 | { | ||
162 | pt: 'https://joinpeertube.org/ns#', | ||
163 | sc: 'http://schema.org#', | ||
164 | |||
165 | ...contextValue | ||
166 | } | ||
167 | ] | ||
137 | } | 168 | } |
diff --git a/server/lib/activitypub/send/http.ts b/server/lib/activitypub/send/http.ts new file mode 100644 index 000000000..d8d0b8542 --- /dev/null +++ b/server/lib/activitypub/send/http.ts | |||
@@ -0,0 +1,68 @@ | |||
1 | import { buildDigest, signJsonLDObject } from '@server/helpers/peertube-crypto' | ||
2 | import { ACTIVITY_PUB, HTTP_SIGNATURE } from '@server/initializers/constants' | ||
3 | import { ActorModel } from '@server/models/actor/actor' | ||
4 | import { getServerActor } from '@server/models/application/application' | ||
5 | import { MActor } from '@server/types/models' | ||
6 | import { ContextType } from '@shared/models/activitypub/context' | ||
7 | import { activityPubContextify } from '../context' | ||
8 | |||
9 | type Payload <T> = { body: T, contextType: ContextType, signatureActorId?: number } | ||
10 | |||
11 | async function computeBody <T> ( | ||
12 | payload: Payload<T> | ||
13 | ): Promise<T | T & { type: 'RsaSignature2017', creator: string, created: string }> { | ||
14 | let body = payload.body | ||
15 | |||
16 | if (payload.signatureActorId) { | ||
17 | const actorSignature = await ActorModel.load(payload.signatureActorId) | ||
18 | if (!actorSignature) throw new Error('Unknown signature actor id.') | ||
19 | |||
20 | body = await signAndContextify(actorSignature, payload.body, payload.contextType) | ||
21 | } | ||
22 | |||
23 | return body | ||
24 | } | ||
25 | |||
26 | async function buildSignedRequestOptions (payload: Payload<any>) { | ||
27 | let actor: MActor | null | ||
28 | |||
29 | if (payload.signatureActorId) { | ||
30 | actor = await ActorModel.load(payload.signatureActorId) | ||
31 | if (!actor) throw new Error('Unknown signature actor id.') | ||
32 | } else { | ||
33 | // We need to sign the request, so use the server | ||
34 | actor = await getServerActor() | ||
35 | } | ||
36 | |||
37 | const keyId = actor.url | ||
38 | return { | ||
39 | algorithm: HTTP_SIGNATURE.ALGORITHM, | ||
40 | authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, | ||
41 | keyId, | ||
42 | key: actor.privateKey, | ||
43 | headers: HTTP_SIGNATURE.HEADERS_TO_SIGN | ||
44 | } | ||
45 | } | ||
46 | |||
47 | function buildGlobalHeaders (body: any) { | ||
48 | return { | ||
49 | 'digest': buildDigest(body), | ||
50 | 'content-type': 'application/activity+json', | ||
51 | 'accept': ACTIVITY_PUB.ACCEPT_HEADER | ||
52 | } | ||
53 | } | ||
54 | |||
55 | function signAndContextify <T> (byActor: MActor, data: T, contextType: ContextType | null) { | ||
56 | const activity = contextType | ||
57 | ? activityPubContextify(data, contextType) | ||
58 | : data | ||
59 | |||
60 | return signJsonLDObject(byActor, activity) | ||
61 | } | ||
62 | |||
63 | export { | ||
64 | buildGlobalHeaders, | ||
65 | computeBody, | ||
66 | buildSignedRequestOptions, | ||
67 | signAndContextify | ||
68 | } | ||
diff --git a/server/lib/activitypub/send/index.ts b/server/lib/activitypub/send/index.ts index 028936810..852ea2e74 100644 --- a/server/lib/activitypub/send/index.ts +++ b/server/lib/activitypub/send/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './send-accept' | 1 | export * from './http' |
2 | export * from './send-accept' | 2 | export * from './send-accept' |
3 | export * from './send-announce' | 3 | export * from './send-announce' |
4 | export * from './send-create' | 4 | export * from './send-create' |
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts index 939f06d9e..4c9bcbb0b 100644 --- a/server/lib/activitypub/send/send-accept.ts +++ b/server/lib/activitypub/send/send-accept.ts | |||
@@ -21,7 +21,12 @@ function sendAccept (actorFollow: MActorFollowActors) { | |||
21 | const url = getLocalActorFollowAcceptActivityPubUrl(actorFollow) | 21 | const url = getLocalActorFollowAcceptActivityPubUrl(actorFollow) |
22 | const data = buildAcceptActivity(url, me, followData) | 22 | const data = buildAcceptActivity(url, me, followData) |
23 | 23 | ||
24 | return unicastTo(data, me, follower.inboxUrl) | 24 | return unicastTo({ |
25 | data, | ||
26 | byActor: me, | ||
27 | toActorUrl: follower.inboxUrl, | ||
28 | contextType: 'Accept' | ||
29 | }) | ||
25 | } | 30 | } |
26 | 31 | ||
27 | // --------------------------------------------------------------------------- | 32 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts index 7897beb75..6c078b047 100644 --- a/server/lib/activitypub/send/send-announce.ts +++ b/server/lib/activitypub/send/send-announce.ts | |||
@@ -23,13 +23,19 @@ async function buildAnnounceWithVideoAudience ( | |||
23 | return { activity, actorsInvolvedInVideo } | 23 | return { activity, actorsInvolvedInVideo } |
24 | } | 24 | } |
25 | 25 | ||
26 | async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, t: Transaction) { | 26 | async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, transaction: Transaction) { |
27 | const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t) | 27 | const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, transaction) |
28 | 28 | ||
29 | logger.info('Creating job to send announce %s.', videoShare.url) | 29 | logger.info('Creating job to send announce %s.', videoShare.url) |
30 | 30 | ||
31 | const followersException = [ byActor ] | 31 | return broadcastToFollowers({ |
32 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException, 'Announce') | 32 | data: activity, |
33 | byActor, | ||
34 | toFollowersOf: actorsInvolvedInVideo, | ||
35 | transaction, | ||
36 | actorsException: [ byActor ], | ||
37 | contextType: 'Announce' | ||
38 | }) | ||
33 | } | 39 | } |
34 | 40 | ||
35 | function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce { | 41 | function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce { |
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts index f6d897220..5d8763495 100644 --- a/server/lib/activitypub/send/send-create.ts +++ b/server/lib/activitypub/send/send-create.ts | |||
@@ -25,7 +25,7 @@ import { | |||
25 | 25 | ||
26 | const lTags = loggerTagsFactory('ap', 'create') | 26 | const lTags = loggerTagsFactory('ap', 'create') |
27 | 27 | ||
28 | async function sendCreateVideo (video: MVideoAP, t: Transaction) { | 28 | async function sendCreateVideo (video: MVideoAP, transaction: Transaction) { |
29 | if (!video.hasPrivacyForFederation()) return undefined | 29 | if (!video.hasPrivacyForFederation()) return undefined |
30 | 30 | ||
31 | logger.info('Creating job to send video creation of %s.', video.url, lTags(video.uuid)) | 31 | logger.info('Creating job to send video creation of %s.', video.url, lTags(video.uuid)) |
@@ -36,7 +36,13 @@ async function sendCreateVideo (video: MVideoAP, t: Transaction) { | |||
36 | const audience = getAudience(byActor, video.privacy === VideoPrivacy.PUBLIC) | 36 | const audience = getAudience(byActor, video.privacy === VideoPrivacy.PUBLIC) |
37 | const createActivity = buildCreateActivity(video.url, byActor, videoObject, audience) | 37 | const createActivity = buildCreateActivity(video.url, byActor, videoObject, audience) |
38 | 38 | ||
39 | return broadcastToFollowers(createActivity, byActor, [ byActor ], t) | 39 | return broadcastToFollowers({ |
40 | data: createActivity, | ||
41 | byActor, | ||
42 | toFollowersOf: [ byActor ], | ||
43 | transaction, | ||
44 | contextType: 'Video' | ||
45 | }) | ||
40 | } | 46 | } |
41 | 47 | ||
42 | async function sendCreateCacheFile ( | 48 | async function sendCreateCacheFile ( |
@@ -55,7 +61,7 @@ async function sendCreateCacheFile ( | |||
55 | }) | 61 | }) |
56 | } | 62 | } |
57 | 63 | ||
58 | async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, t: Transaction) { | 64 | async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, transaction: Transaction) { |
59 | if (playlist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined | 65 | if (playlist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined |
60 | 66 | ||
61 | logger.info('Creating job to send create video playlist of %s.', playlist.url, lTags(playlist.uuid)) | 67 | logger.info('Creating job to send create video playlist of %s.', playlist.url, lTags(playlist.uuid)) |
@@ -63,7 +69,7 @@ async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, t: Transac | |||
63 | const byActor = playlist.OwnerAccount.Actor | 69 | const byActor = playlist.OwnerAccount.Actor |
64 | const audience = getAudience(byActor, playlist.privacy === VideoPlaylistPrivacy.PUBLIC) | 70 | const audience = getAudience(byActor, playlist.privacy === VideoPlaylistPrivacy.PUBLIC) |
65 | 71 | ||
66 | const object = await playlist.toActivityPubObject(null, t) | 72 | const object = await playlist.toActivityPubObject(null, transaction) |
67 | const createActivity = buildCreateActivity(playlist.url, byActor, object, audience) | 73 | const createActivity = buildCreateActivity(playlist.url, byActor, object, audience) |
68 | 74 | ||
69 | const serverActor = await getServerActor() | 75 | const serverActor = await getServerActor() |
@@ -71,19 +77,25 @@ async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, t: Transac | |||
71 | 77 | ||
72 | if (playlist.VideoChannel) toFollowersOf.push(playlist.VideoChannel.Actor) | 78 | if (playlist.VideoChannel) toFollowersOf.push(playlist.VideoChannel.Actor) |
73 | 79 | ||
74 | return broadcastToFollowers(createActivity, byActor, toFollowersOf, t) | 80 | return broadcastToFollowers({ |
81 | data: createActivity, | ||
82 | byActor, | ||
83 | toFollowersOf, | ||
84 | transaction, | ||
85 | contextType: 'Playlist' | ||
86 | }) | ||
75 | } | 87 | } |
76 | 88 | ||
77 | async function sendCreateVideoComment (comment: MCommentOwnerVideo, t: Transaction) { | 89 | async function sendCreateVideoComment (comment: MCommentOwnerVideo, transaction: Transaction) { |
78 | logger.info('Creating job to send comment %s.', comment.url) | 90 | logger.info('Creating job to send comment %s.', comment.url) |
79 | 91 | ||
80 | const isOrigin = comment.Video.isOwned() | 92 | const isOrigin = comment.Video.isOwned() |
81 | 93 | ||
82 | const byActor = comment.Account.Actor | 94 | const byActor = comment.Account.Actor |
83 | const threadParentComments = await VideoCommentModel.listThreadParentComments(comment, t) | 95 | const threadParentComments = await VideoCommentModel.listThreadParentComments(comment, transaction) |
84 | const commentObject = comment.toActivityPubObject(threadParentComments) | 96 | const commentObject = comment.toActivityPubObject(threadParentComments) |
85 | 97 | ||
86 | const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, t) | 98 | const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, transaction) |
87 | // Add the actor that commented too | 99 | // Add the actor that commented too |
88 | actorsInvolvedInComment.push(byActor) | 100 | actorsInvolvedInComment.push(byActor) |
89 | 101 | ||
@@ -101,16 +113,45 @@ async function sendCreateVideoComment (comment: MCommentOwnerVideo, t: Transacti | |||
101 | 113 | ||
102 | // This was a reply, send it to the parent actors | 114 | // This was a reply, send it to the parent actors |
103 | const actorsException = [ byActor ] | 115 | const actorsException = [ byActor ] |
104 | await broadcastToActors(createActivity, byActor, parentsCommentActors, t, actorsException) | 116 | await broadcastToActors({ |
117 | data: createActivity, | ||
118 | byActor, | ||
119 | toActors: parentsCommentActors, | ||
120 | transaction, | ||
121 | actorsException, | ||
122 | contextType: 'Comment' | ||
123 | }) | ||
105 | 124 | ||
106 | // Broadcast to our followers | 125 | // Broadcast to our followers |
107 | await broadcastToFollowers(createActivity, byActor, [ byActor ], t) | 126 | await broadcastToFollowers({ |
127 | data: createActivity, | ||
128 | byActor, | ||
129 | toFollowersOf: [ byActor ], | ||
130 | transaction, | ||
131 | contextType: 'Comment' | ||
132 | }) | ||
108 | 133 | ||
109 | // Send to actors involved in the comment | 134 | // Send to actors involved in the comment |
110 | if (isOrigin) return broadcastToFollowers(createActivity, byActor, actorsInvolvedInComment, t, actorsException) | 135 | if (isOrigin) { |
136 | return broadcastToFollowers({ | ||
137 | data: createActivity, | ||
138 | byActor, | ||
139 | toFollowersOf: actorsInvolvedInComment, | ||
140 | transaction, | ||
141 | actorsException, | ||
142 | contextType: 'Comment' | ||
143 | }) | ||
144 | } | ||
111 | 145 | ||
112 | // Send to origin | 146 | // Send to origin |
113 | t.afterCommit(() => unicastTo(createActivity, byActor, comment.Video.VideoChannel.Account.Actor.getSharedInbox())) | 147 | return transaction.afterCommit(() => { |
148 | return unicastTo({ | ||
149 | data: createActivity, | ||
150 | byActor, | ||
151 | toActorUrl: comment.Video.VideoChannel.Account.Actor.getSharedInbox(), | ||
152 | contextType: 'Comment' | ||
153 | }) | ||
154 | }) | ||
114 | } | 155 | } |
115 | 156 | ||
116 | function buildCreateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityCreate { | 157 | function buildCreateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityCreate { |
@@ -144,8 +185,8 @@ async function sendVideoRelatedCreateActivity (options: { | |||
144 | video: MVideoAccountLight | 185 | video: MVideoAccountLight |
145 | url: string | 186 | url: string |
146 | object: any | 187 | object: any |
188 | contextType: ContextType | ||
147 | transaction?: Transaction | 189 | transaction?: Transaction |
148 | contextType?: ContextType | ||
149 | }) { | 190 | }) { |
150 | const activityBuilder = (audience: ActivityAudience) => { | 191 | const activityBuilder = (audience: ActivityAudience) => { |
151 | return buildCreateActivity(options.url, options.byActor, options.object, audience) | 192 | return buildCreateActivity(options.url, options.byActor, options.object, audience) |
diff --git a/server/lib/activitypub/send/send-delete.ts b/server/lib/activitypub/send/send-delete.ts index 39216cdeb..0d85d9001 100644 --- a/server/lib/activitypub/send/send-delete.ts +++ b/server/lib/activitypub/send/send-delete.ts | |||
@@ -23,16 +23,16 @@ async function sendDeleteVideo (video: MVideoAccountLight, transaction: Transact | |||
23 | return buildDeleteActivity(url, video.url, byActor, audience) | 23 | return buildDeleteActivity(url, video.url, byActor, audience) |
24 | } | 24 | } |
25 | 25 | ||
26 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction }) | 26 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, contextType: 'Delete', transaction }) |
27 | } | 27 | } |
28 | 28 | ||
29 | async function sendDeleteActor (byActor: ActorModel, t: Transaction) { | 29 | async function sendDeleteActor (byActor: ActorModel, transaction: Transaction) { |
30 | logger.info('Creating job to broadcast delete of actor %s.', byActor.url) | 30 | logger.info('Creating job to broadcast delete of actor %s.', byActor.url) |
31 | 31 | ||
32 | const url = getDeleteActivityPubUrl(byActor.url) | 32 | const url = getDeleteActivityPubUrl(byActor.url) |
33 | const activity = buildDeleteActivity(url, byActor.url, byActor) | 33 | const activity = buildDeleteActivity(url, byActor.url, byActor) |
34 | 34 | ||
35 | const actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, t) | 35 | const actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, transaction) |
36 | 36 | ||
37 | // In case the actor did not have any videos | 37 | // In case the actor did not have any videos |
38 | const serverActor = await getServerActor() | 38 | const serverActor = await getServerActor() |
@@ -40,10 +40,16 @@ async function sendDeleteActor (byActor: ActorModel, t: Transaction) { | |||
40 | 40 | ||
41 | actorsInvolved.push(byActor) | 41 | actorsInvolved.push(byActor) |
42 | 42 | ||
43 | return broadcastToFollowers(activity, byActor, actorsInvolved, t) | 43 | return broadcastToFollowers({ |
44 | data: activity, | ||
45 | byActor, | ||
46 | toFollowersOf: actorsInvolved, | ||
47 | contextType: 'Delete', | ||
48 | transaction | ||
49 | }) | ||
44 | } | 50 | } |
45 | 51 | ||
46 | async function sendDeleteVideoComment (videoComment: MCommentOwnerVideo, t: Transaction) { | 52 | async function sendDeleteVideoComment (videoComment: MCommentOwnerVideo, transaction: Transaction) { |
47 | logger.info('Creating job to send delete of comment %s.', videoComment.url) | 53 | logger.info('Creating job to send delete of comment %s.', videoComment.url) |
48 | 54 | ||
49 | const isVideoOrigin = videoComment.Video.isOwned() | 55 | const isVideoOrigin = videoComment.Video.isOwned() |
@@ -53,10 +59,10 @@ async function sendDeleteVideoComment (videoComment: MCommentOwnerVideo, t: Tran | |||
53 | ? videoComment.Account.Actor | 59 | ? videoComment.Account.Actor |
54 | : videoComment.Video.VideoChannel.Account.Actor | 60 | : videoComment.Video.VideoChannel.Account.Actor |
55 | 61 | ||
56 | const threadParentComments = await VideoCommentModel.listThreadParentComments(videoComment, t) | 62 | const threadParentComments = await VideoCommentModel.listThreadParentComments(videoComment, transaction) |
57 | const threadParentCommentsFiltered = threadParentComments.filter(c => !c.isDeleted()) | 63 | const threadParentCommentsFiltered = threadParentComments.filter(c => !c.isDeleted()) |
58 | 64 | ||
59 | const actorsInvolvedInComment = await getActorsInvolvedInVideo(videoComment.Video, t) | 65 | const actorsInvolvedInComment = await getActorsInvolvedInVideo(videoComment.Video, transaction) |
60 | actorsInvolvedInComment.push(byActor) // Add the actor that commented the video | 66 | actorsInvolvedInComment.push(byActor) // Add the actor that commented the video |
61 | 67 | ||
62 | const audience = getVideoCommentAudience(videoComment, threadParentCommentsFiltered, actorsInvolvedInComment, isVideoOrigin) | 68 | const audience = getVideoCommentAudience(videoComment, threadParentCommentsFiltered, actorsInvolvedInComment, isVideoOrigin) |
@@ -64,19 +70,48 @@ async function sendDeleteVideoComment (videoComment: MCommentOwnerVideo, t: Tran | |||
64 | 70 | ||
65 | // This was a reply, send it to the parent actors | 71 | // This was a reply, send it to the parent actors |
66 | const actorsException = [ byActor ] | 72 | const actorsException = [ byActor ] |
67 | await broadcastToActors(activity, byActor, threadParentCommentsFiltered.map(c => c.Account.Actor), t, actorsException) | 73 | await broadcastToActors({ |
74 | data: activity, | ||
75 | byActor, | ||
76 | toActors: threadParentCommentsFiltered.map(c => c.Account.Actor), | ||
77 | transaction, | ||
78 | contextType: 'Delete', | ||
79 | actorsException | ||
80 | }) | ||
68 | 81 | ||
69 | // Broadcast to our followers | 82 | // Broadcast to our followers |
70 | await broadcastToFollowers(activity, byActor, [ byActor ], t) | 83 | await broadcastToFollowers({ |
84 | data: activity, | ||
85 | byActor, | ||
86 | toFollowersOf: [ byActor ], | ||
87 | contextType: 'Delete', | ||
88 | transaction | ||
89 | }) | ||
71 | 90 | ||
72 | // Send to actors involved in the comment | 91 | // Send to actors involved in the comment |
73 | if (isVideoOrigin) return broadcastToFollowers(activity, byActor, actorsInvolvedInComment, t, actorsException) | 92 | if (isVideoOrigin) { |
93 | return broadcastToFollowers({ | ||
94 | data: activity, | ||
95 | byActor, | ||
96 | toFollowersOf: actorsInvolvedInComment, | ||
97 | transaction, | ||
98 | contextType: 'Delete', | ||
99 | actorsException | ||
100 | }) | ||
101 | } | ||
74 | 102 | ||
75 | // Send to origin | 103 | // Send to origin |
76 | t.afterCommit(() => unicastTo(activity, byActor, videoComment.Video.VideoChannel.Account.Actor.getSharedInbox())) | 104 | return transaction.afterCommit(() => { |
105 | return unicastTo({ | ||
106 | data: activity, | ||
107 | byActor, | ||
108 | toActorUrl: videoComment.Video.VideoChannel.Account.Actor.getSharedInbox(), | ||
109 | contextType: 'Delete' | ||
110 | }) | ||
111 | }) | ||
77 | } | 112 | } |
78 | 113 | ||
79 | async function sendDeleteVideoPlaylist (videoPlaylist: MVideoPlaylistFullSummary, t: Transaction) { | 114 | async function sendDeleteVideoPlaylist (videoPlaylist: MVideoPlaylistFullSummary, transaction: Transaction) { |
80 | logger.info('Creating job to send delete of playlist %s.', videoPlaylist.url) | 115 | logger.info('Creating job to send delete of playlist %s.', videoPlaylist.url) |
81 | 116 | ||
82 | const byActor = videoPlaylist.OwnerAccount.Actor | 117 | const byActor = videoPlaylist.OwnerAccount.Actor |
@@ -89,7 +124,13 @@ async function sendDeleteVideoPlaylist (videoPlaylist: MVideoPlaylistFullSummary | |||
89 | 124 | ||
90 | if (videoPlaylist.VideoChannel) toFollowersOf.push(videoPlaylist.VideoChannel.Actor) | 125 | if (videoPlaylist.VideoChannel) toFollowersOf.push(videoPlaylist.VideoChannel.Actor) |
91 | 126 | ||
92 | return broadcastToFollowers(activity, byActor, toFollowersOf, t) | 127 | return broadcastToFollowers({ |
128 | data: activity, | ||
129 | byActor, | ||
130 | toFollowersOf, | ||
131 | contextType: 'Delete', | ||
132 | transaction | ||
133 | }) | ||
93 | } | 134 | } |
94 | 135 | ||
95 | // --------------------------------------------------------------------------- | 136 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/send/send-dislike.ts b/server/lib/activitypub/send/send-dislike.ts index ecb11e9bf..959e74823 100644 --- a/server/lib/activitypub/send/send-dislike.ts +++ b/server/lib/activitypub/send/send-dislike.ts | |||
@@ -6,7 +6,7 @@ import { audiencify, getAudience } from '../audience' | |||
6 | import { getVideoDislikeActivityPubUrlByLocalActor } from '../url' | 6 | import { getVideoDislikeActivityPubUrlByLocalActor } from '../url' |
7 | import { sendVideoActivityToOrigin } from './shared/send-utils' | 7 | import { sendVideoActivityToOrigin } from './shared/send-utils' |
8 | 8 | ||
9 | function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { | 9 | function sendDislike (byActor: MActor, video: MVideoAccountLight, transaction: Transaction) { |
10 | logger.info('Creating job to dislike %s.', video.url) | 10 | logger.info('Creating job to dislike %s.', video.url) |
11 | 11 | ||
12 | const activityBuilder = (audience: ActivityAudience) => { | 12 | const activityBuilder = (audience: ActivityAudience) => { |
@@ -15,7 +15,7 @@ function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction | |||
15 | return buildDislikeActivity(url, byActor, video, audience) | 15 | return buildDislikeActivity(url, byActor, video, audience) |
16 | } | 16 | } |
17 | 17 | ||
18 | return sendVideoActivityToOrigin(activityBuilder, { byActor, video, transaction: t }) | 18 | return sendVideoActivityToOrigin(activityBuilder, { byActor, video, transaction, contextType: 'Rate' }) |
19 | } | 19 | } |
20 | 20 | ||
21 | function buildDislikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityDislike { | 21 | function buildDislikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityDislike { |
diff --git a/server/lib/activitypub/send/send-flag.ts b/server/lib/activitypub/send/send-flag.ts index 6df4e7eb8..138eb5adc 100644 --- a/server/lib/activitypub/send/send-flag.ts +++ b/server/lib/activitypub/send/send-flag.ts | |||
@@ -17,16 +17,20 @@ function sendAbuse (byActor: MActor, abuse: MAbuseAP, flaggedAccount: MAccountLi | |||
17 | const audience = { to: [ flaggedAccount.Actor.url ], cc: [] } | 17 | const audience = { to: [ flaggedAccount.Actor.url ], cc: [] } |
18 | const flagActivity = buildFlagActivity(url, byActor, abuse, audience) | 18 | const flagActivity = buildFlagActivity(url, byActor, abuse, audience) |
19 | 19 | ||
20 | t.afterCommit(() => unicastTo(flagActivity, byActor, flaggedAccount.Actor.getSharedInbox())) | 20 | return t.afterCommit(() => { |
21 | return unicastTo({ | ||
22 | data: flagActivity, | ||
23 | byActor, | ||
24 | toActorUrl: flaggedAccount.Actor.getSharedInbox(), | ||
25 | contextType: 'Flag' | ||
26 | }) | ||
27 | }) | ||
21 | } | 28 | } |
22 | 29 | ||
23 | function buildFlagActivity (url: string, byActor: MActor, abuse: MAbuseAP, audience: ActivityAudience): ActivityFlag { | 30 | function buildFlagActivity (url: string, byActor: MActor, abuse: MAbuseAP, audience: ActivityAudience): ActivityFlag { |
24 | if (!audience) audience = getAudience(byActor) | 31 | if (!audience) audience = getAudience(byActor) |
25 | 32 | ||
26 | const activity = Object.assign( | 33 | const activity = { id: url, actor: byActor.url, ...abuse.toActivityPubObject() } |
27 | { id: url, actor: byActor.url }, | ||
28 | abuse.toActivityPubObject() | ||
29 | ) | ||
30 | 34 | ||
31 | return audiencify(activity, audience) | 35 | return audiencify(activity, audience) |
32 | } | 36 | } |
diff --git a/server/lib/activitypub/send/send-follow.ts b/server/lib/activitypub/send/send-follow.ts index aeeb50a2a..57501dadb 100644 --- a/server/lib/activitypub/send/send-follow.ts +++ b/server/lib/activitypub/send/send-follow.ts | |||
@@ -15,7 +15,9 @@ function sendFollow (actorFollow: MActorFollowActors, t: Transaction) { | |||
15 | 15 | ||
16 | const data = buildFollowActivity(actorFollow.url, me, following) | 16 | const data = buildFollowActivity(actorFollow.url, me, following) |
17 | 17 | ||
18 | t.afterCommit(() => unicastTo(data, me, following.inboxUrl)) | 18 | return t.afterCommit(() => { |
19 | return unicastTo({ data, byActor: me, toActorUrl: following.inboxUrl, contextType: 'Follow' }) | ||
20 | }) | ||
19 | } | 21 | } |
20 | 22 | ||
21 | function buildFollowActivity (url: string, byActor: MActor, targetActor: MActor): ActivityFollow { | 23 | function buildFollowActivity (url: string, byActor: MActor, targetActor: MActor): ActivityFollow { |
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts index a5fe95e0a..46c9fdec9 100644 --- a/server/lib/activitypub/send/send-like.ts +++ b/server/lib/activitypub/send/send-like.ts | |||
@@ -6,7 +6,7 @@ import { audiencify, getAudience } from '../audience' | |||
6 | import { getVideoLikeActivityPubUrlByLocalActor } from '../url' | 6 | import { getVideoLikeActivityPubUrlByLocalActor } from '../url' |
7 | import { sendVideoActivityToOrigin } from './shared/send-utils' | 7 | import { sendVideoActivityToOrigin } from './shared/send-utils' |
8 | 8 | ||
9 | function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { | 9 | function sendLike (byActor: MActor, video: MVideoAccountLight, transaction: Transaction) { |
10 | logger.info('Creating job to like %s.', video.url) | 10 | logger.info('Creating job to like %s.', video.url) |
11 | 11 | ||
12 | const activityBuilder = (audience: ActivityAudience) => { | 12 | const activityBuilder = (audience: ActivityAudience) => { |
@@ -15,7 +15,7 @@ function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { | |||
15 | return buildLikeActivity(url, byActor, video, audience) | 15 | return buildLikeActivity(url, byActor, video, audience) |
16 | } | 16 | } |
17 | 17 | ||
18 | return sendVideoActivityToOrigin(activityBuilder, { byActor, video, transaction: t }) | 18 | return sendVideoActivityToOrigin(activityBuilder, { byActor, video, transaction, contextType: 'Rate' }) |
19 | } | 19 | } |
20 | 20 | ||
21 | function buildLikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityLike { | 21 | function buildLikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityLike { |
diff --git a/server/lib/activitypub/send/send-reject.ts b/server/lib/activitypub/send/send-reject.ts index 01b8f743b..83d8dfba7 100644 --- a/server/lib/activitypub/send/send-reject.ts +++ b/server/lib/activitypub/send/send-reject.ts | |||
@@ -18,7 +18,7 @@ function sendReject (followUrl: string, follower: MActor, following: MActor) { | |||
18 | const url = getLocalActorFollowRejectActivityPubUrl(follower, following) | 18 | const url = getLocalActorFollowRejectActivityPubUrl(follower, following) |
19 | const data = buildRejectActivity(url, following, followData) | 19 | const data = buildRejectActivity(url, following, followData) |
20 | 20 | ||
21 | return unicastTo(data, following, follower.inboxUrl) | 21 | return unicastTo({ data, byActor: following, toActorUrl: follower.inboxUrl, contextType: 'Reject' }) |
22 | } | 22 | } |
23 | 23 | ||
24 | // --------------------------------------------------------------------------- | 24 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index 948ca0d7a..36d7ef991 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts | |||
@@ -6,7 +6,8 @@ import { | |||
6 | ActivityDislike, | 6 | ActivityDislike, |
7 | ActivityFollow, | 7 | ActivityFollow, |
8 | ActivityLike, | 8 | ActivityLike, |
9 | ActivityUndo | 9 | ActivityUndo, |
10 | ContextType | ||
10 | } from '@shared/models' | 11 | } from '@shared/models' |
11 | import { logger } from '../../../helpers/logger' | 12 | import { logger } from '../../../helpers/logger' |
12 | import { VideoModel } from '../../../models/video/video' | 13 | import { VideoModel } from '../../../models/video/video' |
@@ -43,24 +44,37 @@ function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) { | |||
43 | const followActivity = buildFollowActivity(actorFollow.url, me, following) | 44 | const followActivity = buildFollowActivity(actorFollow.url, me, following) |
44 | const undoActivity = undoActivityData(undoUrl, me, followActivity) | 45 | const undoActivity = undoActivityData(undoUrl, me, followActivity) |
45 | 46 | ||
46 | t.afterCommit(() => unicastTo(undoActivity, me, following.inboxUrl)) | 47 | return t.afterCommit(() => { |
48 | return unicastTo({ | ||
49 | data: undoActivity, | ||
50 | byActor: me, | ||
51 | toActorUrl: following.inboxUrl, | ||
52 | contextType: 'Follow' | ||
53 | }) | ||
54 | }) | ||
47 | } | 55 | } |
48 | 56 | ||
49 | // --------------------------------------------------------------------------- | 57 | // --------------------------------------------------------------------------- |
50 | 58 | ||
51 | async function sendUndoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, t: Transaction) { | 59 | async function sendUndoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, transaction: Transaction) { |
52 | logger.info('Creating job to undo announce %s.', videoShare.url) | 60 | logger.info('Creating job to undo announce %s.', videoShare.url) |
53 | 61 | ||
54 | const undoUrl = getUndoActivityPubUrl(videoShare.url) | 62 | const undoUrl = getUndoActivityPubUrl(videoShare.url) |
55 | 63 | ||
56 | const { activity: announceActivity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t) | 64 | const { activity: announce, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, transaction) |
57 | const undoActivity = undoActivityData(undoUrl, byActor, announceActivity) | 65 | const undoActivity = undoActivityData(undoUrl, byActor, announce) |
58 | 66 | ||
59 | const followersException = [ byActor ] | 67 | return broadcastToFollowers({ |
60 | return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException) | 68 | data: undoActivity, |
69 | byActor, | ||
70 | toFollowersOf: actorsInvolvedInVideo, | ||
71 | transaction, | ||
72 | actorsException: [ byActor ], | ||
73 | contextType: 'Announce' | ||
74 | }) | ||
61 | } | 75 | } |
62 | 76 | ||
63 | async function sendUndoCacheFile (byActor: MActor, redundancyModel: MVideoRedundancyVideo, t: Transaction) { | 77 | async function sendUndoCacheFile (byActor: MActor, redundancyModel: MVideoRedundancyVideo, transaction: Transaction) { |
64 | logger.info('Creating job to undo cache file %s.', redundancyModel.url) | 78 | logger.info('Creating job to undo cache file %s.', redundancyModel.url) |
65 | 79 | ||
66 | const associatedVideo = redundancyModel.getVideo() | 80 | const associatedVideo = redundancyModel.getVideo() |
@@ -72,7 +86,14 @@ async function sendUndoCacheFile (byActor: MActor, redundancyModel: MVideoRedund | |||
72 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(associatedVideo.id) | 86 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(associatedVideo.id) |
73 | const createActivity = buildCreateActivity(redundancyModel.url, byActor, redundancyModel.toActivityPubObject()) | 87 | const createActivity = buildCreateActivity(redundancyModel.url, byActor, redundancyModel.toActivityPubObject()) |
74 | 88 | ||
75 | return sendUndoVideoRelatedActivity({ byActor, video, url: redundancyModel.url, activity: createActivity, transaction: t }) | 89 | return sendUndoVideoRelatedActivity({ |
90 | byActor, | ||
91 | video, | ||
92 | url: redundancyModel.url, | ||
93 | activity: createActivity, | ||
94 | contextType: 'CacheFile', | ||
95 | transaction | ||
96 | }) | ||
76 | } | 97 | } |
77 | 98 | ||
78 | // --------------------------------------------------------------------------- | 99 | // --------------------------------------------------------------------------- |
@@ -83,7 +104,7 @@ async function sendUndoLike (byActor: MActor, video: MVideoAccountLight, t: Tran | |||
83 | const likeUrl = getVideoLikeActivityPubUrlByLocalActor(byActor, video) | 104 | const likeUrl = getVideoLikeActivityPubUrlByLocalActor(byActor, video) |
84 | const likeActivity = buildLikeActivity(likeUrl, byActor, video) | 105 | const likeActivity = buildLikeActivity(likeUrl, byActor, video) |
85 | 106 | ||
86 | return sendUndoVideoToOriginActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t }) | 107 | return sendUndoVideoRateToOriginActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t }) |
87 | } | 108 | } |
88 | 109 | ||
89 | async function sendUndoDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { | 110 | async function sendUndoDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { |
@@ -92,7 +113,7 @@ async function sendUndoDislike (byActor: MActor, video: MVideoAccountLight, t: T | |||
92 | const dislikeUrl = getVideoDislikeActivityPubUrlByLocalActor(byActor, video) | 113 | const dislikeUrl = getVideoDislikeActivityPubUrlByLocalActor(byActor, video) |
93 | const dislikeActivity = buildDislikeActivity(dislikeUrl, byActor, video) | 114 | const dislikeActivity = buildDislikeActivity(dislikeUrl, byActor, video) |
94 | 115 | ||
95 | return sendUndoVideoToOriginActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t }) | 116 | return sendUndoVideoRateToOriginActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t }) |
96 | } | 117 | } |
97 | 118 | ||
98 | // --------------------------------------------------------------------------- | 119 | // --------------------------------------------------------------------------- |
@@ -131,6 +152,7 @@ async function sendUndoVideoRelatedActivity (options: { | |||
131 | video: MVideoAccountLight | 152 | video: MVideoAccountLight |
132 | url: string | 153 | url: string |
133 | activity: ActivityFollow | ActivityCreate | ActivityAnnounce | 154 | activity: ActivityFollow | ActivityCreate | ActivityAnnounce |
155 | contextType: ContextType | ||
134 | transaction: Transaction | 156 | transaction: Transaction |
135 | }) { | 157 | }) { |
136 | const activityBuilder = (audience: ActivityAudience) => { | 158 | const activityBuilder = (audience: ActivityAudience) => { |
@@ -142,7 +164,7 @@ async function sendUndoVideoRelatedActivity (options: { | |||
142 | return sendVideoRelatedActivity(activityBuilder, options) | 164 | return sendVideoRelatedActivity(activityBuilder, options) |
143 | } | 165 | } |
144 | 166 | ||
145 | async function sendUndoVideoToOriginActivity (options: { | 167 | async function sendUndoVideoRateToOriginActivity (options: { |
146 | byActor: MActor | 168 | byActor: MActor |
147 | video: MVideoAccountLight | 169 | video: MVideoAccountLight |
148 | url: string | 170 | url: string |
@@ -155,5 +177,5 @@ async function sendUndoVideoToOriginActivity (options: { | |||
155 | return undoActivityData(undoUrl, options.byActor, options.activity, audience) | 177 | return undoActivityData(undoUrl, options.byActor, options.activity, audience) |
156 | } | 178 | } |
157 | 179 | ||
158 | return sendVideoActivityToOrigin(activityBuilder, options) | 180 | return sendVideoActivityToOrigin(activityBuilder, { ...options, contextType: 'Rate' }) |
159 | } | 181 | } |
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 7c9e72cbc..3577ece02 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts | |||
@@ -20,20 +20,20 @@ import { getUpdateActivityPubUrl } from '../url' | |||
20 | import { getActorsInvolvedInVideo } from './shared' | 20 | import { getActorsInvolvedInVideo } from './shared' |
21 | import { broadcastToFollowers, sendVideoRelatedActivity } from './shared/send-utils' | 21 | import { broadcastToFollowers, sendVideoRelatedActivity } from './shared/send-utils' |
22 | 22 | ||
23 | async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction, overrodeByActor?: MActor) { | 23 | async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, transaction: Transaction, overriddenByActor?: MActor) { |
24 | const video = videoArg as MVideoAP | 24 | const video = videoArg as MVideoAP |
25 | 25 | ||
26 | if (!video.hasPrivacyForFederation()) return undefined | 26 | if (!video.hasPrivacyForFederation()) return undefined |
27 | 27 | ||
28 | logger.info('Creating job to update video %s.', video.url) | 28 | logger.info('Creating job to update video %s.', video.url) |
29 | 29 | ||
30 | const byActor = overrodeByActor || video.VideoChannel.Account.Actor | 30 | const byActor = overriddenByActor || video.VideoChannel.Account.Actor |
31 | 31 | ||
32 | const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) | 32 | const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) |
33 | 33 | ||
34 | // Needed to build the AP object | 34 | // Needed to build the AP object |
35 | if (!video.VideoCaptions) { | 35 | if (!video.VideoCaptions) { |
36 | video.VideoCaptions = await video.$get('VideoCaptions', { transaction: t }) | 36 | video.VideoCaptions = await video.$get('VideoCaptions', { transaction }) |
37 | } | 37 | } |
38 | 38 | ||
39 | const videoObject = video.toActivityPubObject() | 39 | const videoObject = video.toActivityPubObject() |
@@ -41,13 +41,19 @@ async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction | |||
41 | 41 | ||
42 | const updateActivity = buildUpdateActivity(url, byActor, videoObject, audience) | 42 | const updateActivity = buildUpdateActivity(url, byActor, videoObject, audience) |
43 | 43 | ||
44 | const actorsInvolved = await getActorsInvolvedInVideo(video, t) | 44 | const actorsInvolved = await getActorsInvolvedInVideo(video, transaction) |
45 | if (overrodeByActor) actorsInvolved.push(overrodeByActor) | 45 | if (overriddenByActor) actorsInvolved.push(overriddenByActor) |
46 | 46 | ||
47 | return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t) | 47 | return broadcastToFollowers({ |
48 | data: updateActivity, | ||
49 | byActor, | ||
50 | toFollowersOf: actorsInvolved, | ||
51 | contextType: 'Video', | ||
52 | transaction | ||
53 | }) | ||
48 | } | 54 | } |
49 | 55 | ||
50 | async function sendUpdateActor (accountOrChannel: MChannelDefault | MAccountDefault, t: Transaction) { | 56 | async function sendUpdateActor (accountOrChannel: MChannelDefault | MAccountDefault, transaction: Transaction) { |
51 | const byActor = accountOrChannel.Actor | 57 | const byActor = accountOrChannel.Actor |
52 | 58 | ||
53 | logger.info('Creating job to update actor %s.', byActor.url) | 59 | logger.info('Creating job to update actor %s.', byActor.url) |
@@ -60,15 +66,21 @@ async function sendUpdateActor (accountOrChannel: MChannelDefault | MAccountDefa | |||
60 | let actorsInvolved: MActor[] | 66 | let actorsInvolved: MActor[] |
61 | if (accountOrChannel instanceof AccountModel) { | 67 | if (accountOrChannel instanceof AccountModel) { |
62 | // Actors that shared my videos are involved too | 68 | // Actors that shared my videos are involved too |
63 | actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, t) | 69 | actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, transaction) |
64 | } else { | 70 | } else { |
65 | // Actors that shared videos of my channel are involved too | 71 | // Actors that shared videos of my channel are involved too |
66 | actorsInvolved = await VideoShareModel.loadActorsByVideoChannel(accountOrChannel.id, t) | 72 | actorsInvolved = await VideoShareModel.loadActorsByVideoChannel(accountOrChannel.id, transaction) |
67 | } | 73 | } |
68 | 74 | ||
69 | actorsInvolved.push(byActor) | 75 | actorsInvolved.push(byActor) |
70 | 76 | ||
71 | return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t) | 77 | return broadcastToFollowers({ |
78 | data: updateActivity, | ||
79 | byActor, | ||
80 | toFollowersOf: actorsInvolved, | ||
81 | transaction, | ||
82 | contextType: 'Actor' | ||
83 | }) | ||
72 | } | 84 | } |
73 | 85 | ||
74 | async function sendUpdateCacheFile (byActor: MActorLight, redundancyModel: MVideoRedundancyVideo) { | 86 | async function sendUpdateCacheFile (byActor: MActorLight, redundancyModel: MVideoRedundancyVideo) { |
@@ -92,7 +104,7 @@ async function sendUpdateCacheFile (byActor: MActorLight, redundancyModel: MVide | |||
92 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, contextType: 'CacheFile' }) | 104 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, contextType: 'CacheFile' }) |
93 | } | 105 | } |
94 | 106 | ||
95 | async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, t: Transaction) { | 107 | async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, transaction: Transaction) { |
96 | if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined | 108 | if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined |
97 | 109 | ||
98 | const byActor = videoPlaylist.OwnerAccount.Actor | 110 | const byActor = videoPlaylist.OwnerAccount.Actor |
@@ -101,7 +113,7 @@ async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, t: Tr | |||
101 | 113 | ||
102 | const url = getUpdateActivityPubUrl(videoPlaylist.url, videoPlaylist.updatedAt.toISOString()) | 114 | const url = getUpdateActivityPubUrl(videoPlaylist.url, videoPlaylist.updatedAt.toISOString()) |
103 | 115 | ||
104 | const object = await videoPlaylist.toActivityPubObject(null, t) | 116 | const object = await videoPlaylist.toActivityPubObject(null, transaction) |
105 | const audience = getAudience(byActor, videoPlaylist.privacy === VideoPlaylistPrivacy.PUBLIC) | 117 | const audience = getAudience(byActor, videoPlaylist.privacy === VideoPlaylistPrivacy.PUBLIC) |
106 | 118 | ||
107 | const updateActivity = buildUpdateActivity(url, byActor, object, audience) | 119 | const updateActivity = buildUpdateActivity(url, byActor, object, audience) |
@@ -111,7 +123,13 @@ async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, t: Tr | |||
111 | 123 | ||
112 | if (videoPlaylist.VideoChannel) toFollowersOf.push(videoPlaylist.VideoChannel.Actor) | 124 | if (videoPlaylist.VideoChannel) toFollowersOf.push(videoPlaylist.VideoChannel.Actor) |
113 | 125 | ||
114 | return broadcastToFollowers(updateActivity, byActor, toFollowersOf, t) | 126 | return broadcastToFollowers({ |
127 | data: updateActivity, | ||
128 | byActor, | ||
129 | toFollowersOf, | ||
130 | transaction, | ||
131 | contextType: 'Playlist' | ||
132 | }) | ||
115 | } | 133 | } |
116 | 134 | ||
117 | // --------------------------------------------------------------------------- | 135 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/send/shared/send-utils.ts b/server/lib/activitypub/send/shared/send-utils.ts index 9e8f12fa8..dbcde91ee 100644 --- a/server/lib/activitypub/send/shared/send-utils.ts +++ b/server/lib/activitypub/send/shared/send-utils.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { ActorFollowHealthCache } from '@server/lib/actor-follow-health-cache' | 2 | import { ActorFollowHealthCache } from '@server/lib/actor-follow-health-cache' |
3 | import { getServerActor } from '@server/models/application/application' | 3 | import { getServerActor } from '@server/models/application/application' |
4 | import { Activity, ActivityAudience } from '@shared/models' | 4 | import { Activity, ActivityAudience, ActivitypubHttpBroadcastPayload } from '@shared/models' |
5 | import { ContextType } from '@shared/models/activitypub/context' | 5 | import { ContextType } from '@shared/models/activitypub/context' |
6 | import { afterCommitIfTransaction } from '../../../../helpers/database-utils' | 6 | import { afterCommitIfTransaction } from '../../../../helpers/database-utils' |
7 | import { logger } from '../../../../helpers/logger' | 7 | import { logger } from '../../../../helpers/logger' |
@@ -14,8 +14,8 @@ import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getOriginVideoAud | |||
14 | async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { | 14 | async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { |
15 | byActor: MActorLight | 15 | byActor: MActorLight |
16 | video: MVideoImmutable | MVideoAccountLight | 16 | video: MVideoImmutable | MVideoAccountLight |
17 | contextType: ContextType | ||
17 | transaction?: Transaction | 18 | transaction?: Transaction |
18 | contextType?: ContextType | ||
19 | }) { | 19 | }) { |
20 | const { byActor, video, transaction, contextType } = options | 20 | const { byActor, video, transaction, contextType } = options |
21 | 21 | ||
@@ -32,15 +32,23 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud | |||
32 | 32 | ||
33 | const actorsException = [ byActor ] | 33 | const actorsException = [ byActor ] |
34 | 34 | ||
35 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException, contextType) | 35 | return broadcastToFollowers({ |
36 | data: activity, | ||
37 | byActor, | ||
38 | toFollowersOf: actorsInvolvedInVideo, | ||
39 | transaction, | ||
40 | actorsException, | ||
41 | contextType | ||
42 | }) | ||
36 | } | 43 | } |
37 | 44 | ||
38 | async function sendVideoActivityToOrigin (activityBuilder: (audience: ActivityAudience) => Activity, options: { | 45 | async function sendVideoActivityToOrigin (activityBuilder: (audience: ActivityAudience) => Activity, options: { |
39 | byActor: MActorLight | 46 | byActor: MActorLight |
40 | video: MVideoImmutable | MVideoAccountLight | 47 | video: MVideoImmutable | MVideoAccountLight |
48 | contextType: ContextType | ||
49 | |||
41 | actorsInvolvedInVideo?: MActorLight[] | 50 | actorsInvolvedInVideo?: MActorLight[] |
42 | transaction?: Transaction | 51 | transaction?: Transaction |
43 | contextType?: ContextType | ||
44 | }) { | 52 | }) { |
45 | const { byActor, video, actorsInvolvedInVideo, transaction, contextType } = options | 53 | const { byActor, video, actorsInvolvedInVideo, transaction, contextType } = options |
46 | 54 | ||
@@ -53,7 +61,12 @@ async function sendVideoActivityToOrigin (activityBuilder: (audience: ActivityAu | |||
53 | const activity = activityBuilder(audience) | 61 | const activity = activityBuilder(audience) |
54 | 62 | ||
55 | return afterCommitIfTransaction(transaction, () => { | 63 | return afterCommitIfTransaction(transaction, () => { |
56 | return unicastTo(activity, byActor, accountActor.getSharedInbox(), contextType) | 64 | return unicastTo({ |
65 | data: activity, | ||
66 | byActor, | ||
67 | toActorUrl: accountActor.getSharedInbox(), | ||
68 | contextType | ||
69 | }) | ||
57 | }) | 70 | }) |
58 | } | 71 | } |
59 | 72 | ||
@@ -100,41 +113,69 @@ async function forwardActivity ( | |||
100 | 113 | ||
101 | logger.debug('Creating forwarding job.', { uris }) | 114 | logger.debug('Creating forwarding job.', { uris }) |
102 | 115 | ||
103 | const payload = { | 116 | const payload: ActivitypubHttpBroadcastPayload = { |
104 | uris, | 117 | uris, |
105 | body: activity | 118 | body: activity, |
119 | contextType: null | ||
106 | } | 120 | } |
107 | return afterCommitIfTransaction(t, () => JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })) | 121 | return afterCommitIfTransaction(t, () => JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })) |
108 | } | 122 | } |
109 | 123 | ||
110 | // --------------------------------------------------------------------------- | 124 | // --------------------------------------------------------------------------- |
111 | 125 | ||
112 | async function broadcastToFollowers ( | 126 | async function broadcastToFollowers (options: { |
113 | data: any, | 127 | data: any |
114 | byActor: MActorId, | 128 | byActor: MActorId |
115 | toFollowersOf: MActorId[], | 129 | toFollowersOf: MActorId[] |
116 | t: Transaction, | 130 | transaction: Transaction |
117 | actorsException: MActorWithInboxes[] = [], | 131 | contextType: ContextType |
118 | contextType?: ContextType | 132 | |
119 | ) { | 133 | actorsException?: MActorWithInboxes[] |
120 | const uris = await computeFollowerUris(toFollowersOf, actorsException, t) | 134 | }) { |
135 | const { data, byActor, toFollowersOf, transaction, contextType, actorsException = [] } = options | ||
121 | 136 | ||
122 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType)) | 137 | const uris = await computeFollowerUris(toFollowersOf, actorsException, transaction) |
138 | |||
139 | return afterCommitIfTransaction(transaction, () => { | ||
140 | return broadcastTo({ | ||
141 | uris, | ||
142 | data, | ||
143 | byActor, | ||
144 | contextType | ||
145 | }) | ||
146 | }) | ||
123 | } | 147 | } |
124 | 148 | ||
125 | async function broadcastToActors ( | 149 | async function broadcastToActors (options: { |
126 | data: any, | 150 | data: any |
127 | byActor: MActorId, | 151 | byActor: MActorId |
128 | toActors: MActor[], | 152 | toActors: MActor[] |
129 | t?: Transaction, | 153 | transaction: Transaction |
130 | actorsException: MActorWithInboxes[] = [], | 154 | contextType: ContextType |
131 | contextType?: ContextType | 155 | actorsException?: MActorWithInboxes[] |
132 | ) { | 156 | }) { |
157 | const { data, byActor, toActors, transaction, contextType, actorsException = [] } = options | ||
158 | |||
133 | const uris = await computeUris(toActors, actorsException) | 159 | const uris = await computeUris(toActors, actorsException) |
134 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType)) | 160 | |
161 | return afterCommitIfTransaction(transaction, () => { | ||
162 | return broadcastTo({ | ||
163 | uris, | ||
164 | data, | ||
165 | byActor, | ||
166 | contextType | ||
167 | }) | ||
168 | }) | ||
135 | } | 169 | } |
136 | 170 | ||
137 | function broadcastTo (uris: string[], data: any, byActor: MActorId, contextType?: ContextType) { | 171 | function broadcastTo (options: { |
172 | uris: string[] | ||
173 | data: any | ||
174 | byActor: MActorId | ||
175 | contextType: ContextType | ||
176 | }) { | ||
177 | const { uris, data, byActor, contextType } = options | ||
178 | |||
138 | if (uris.length === 0) return undefined | 179 | if (uris.length === 0) return undefined |
139 | 180 | ||
140 | const broadcastUris: string[] = [] | 181 | const broadcastUris: string[] = [] |
@@ -174,7 +215,14 @@ function broadcastTo (uris: string[], data: any, byActor: MActorId, contextType? | |||
174 | } | 215 | } |
175 | } | 216 | } |
176 | 217 | ||
177 | function unicastTo (data: any, byActor: MActorId, toActorUrl: string, contextType?: ContextType) { | 218 | function unicastTo (options: { |
219 | data: any | ||
220 | byActor: MActorId | ||
221 | toActorUrl: string | ||
222 | contextType: ContextType | ||
223 | }) { | ||
224 | const { data, byActor, toActorUrl, contextType } = options | ||
225 | |||
178 | logger.debug('Creating unicast job.', { uri: toActorUrl }) | 226 | logger.debug('Creating unicast job.', { uri: toActorUrl }) |
179 | 227 | ||
180 | const payload = { | 228 | const payload = { |