Reduce AP context size on specific activities
authorChocobozzz <me@florianbigard.com>
Mon, 3 Feb 2020 10:12:29 +0000 (11:12 +0100)
committerChocobozzz <me@florianbigard.com>
Mon, 3 Feb 2020 10:31:23 +0000 (11:31 +0100)
server/controllers/activitypub/client.ts
server/helpers/activitypub.ts
server/lib/activitypub/send/send-announce.ts
server/lib/activitypub/send/send-view.ts
server/lib/activitypub/send/utils.ts
server/lib/job-queue/handlers/activitypub-http-broadcast.ts
server/lib/job-queue/handlers/activitypub-http-unicast.ts
server/lib/job-queue/handlers/utils/activitypub-http-utils.ts

index 39f6d7231a90f89151026da46a3b24e28db1e10b..2812bfe1e8e9b194145330cc6080abff6db831da 100644 (file)
@@ -234,7 +234,7 @@ async function videoAnnounceController (req: express.Request, res: express.Respo
 
   const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined)
 
-  return activityPubResponse(activityPubContextify(activity), res)
+  return activityPubResponse(activityPubContextify(activity, 'Announce'), res)
 }
 
 async function videoAnnouncesController (req: express.Request, res: express.Response) {
index 22f8550caf37a4a343d736e0eada920e82d3c611..326785b680581fc4627a1b20a6bfd76151d86e7e 100644 (file)
@@ -8,93 +8,100 @@ import { pageToStartAndCount } from './core-utils'
 import { URL } from 'url'
 import { MActor, MVideoAccountLight } from '../typings/models'
 
-function activityPubContextify <T> (data: T) {
-  return Object.assign(data, {
+export type ContextType = 'All' | 'View' | 'Announce'
+
+function activityPubContextify <T> (data: T, type: ContextType = 'All') {
+  const base = {
+    RsaSignature2017: 'https://w3id.org/security#RsaSignature2017'
+  }
+
+  if (type === 'All') {
+    Object.assign(base, {
+      pt: 'https://joinpeertube.org/ns#',
+      sc: 'http://schema.org#',
+      Hashtag: 'as:Hashtag',
+      uuid: 'sc:identifier',
+      category: 'sc:category',
+      licence: 'sc:license',
+      subtitleLanguage: 'sc:subtitleLanguage',
+      sensitive: 'as:sensitive',
+      language: 'sc:inLanguage',
+      expires: 'sc:expires',
+      CacheFile: 'pt:CacheFile',
+      Infohash: 'pt:Infohash',
+      originallyPublishedAt: 'sc:datePublished',
+      views: {
+        '@type': 'sc:Number',
+        '@id': 'pt:views'
+      },
+      state: {
+        '@type': 'sc:Number',
+        '@id': 'pt:state'
+      },
+      size: {
+        '@type': 'sc:Number',
+        '@id': 'pt:size'
+      },
+      fps: {
+        '@type': 'sc:Number',
+        '@id': 'pt:fps'
+      },
+      startTimestamp: {
+        '@type': 'sc:Number',
+        '@id': 'pt:startTimestamp'
+      },
+      stopTimestamp: {
+        '@type': 'sc:Number',
+        '@id': 'pt:stopTimestamp'
+      },
+      position: {
+        '@type': 'sc:Number',
+        '@id': 'pt:position'
+      },
+      commentsEnabled: {
+        '@type': 'sc:Boolean',
+        '@id': 'pt:commentsEnabled'
+      },
+      downloadEnabled: {
+        '@type': 'sc:Boolean',
+        '@id': 'pt:downloadEnabled'
+      },
+      waitTranscoding: {
+        '@type': 'sc:Boolean',
+        '@id': 'pt:waitTranscoding'
+      },
+      support: {
+        '@type': 'sc:Text',
+        '@id': 'pt:support'
+      },
+      likes: {
+        '@id': 'as:likes',
+        '@type': '@id'
+      },
+      dislikes: {
+        '@id': 'as:dislikes',
+        '@type': '@id'
+      },
+      playlists: {
+        '@id': 'pt:playlists',
+        '@type': '@id'
+      },
+      shares: {
+        '@id': 'as:shares',
+        '@type': '@id'
+      },
+      comments: {
+        '@id': 'as:comments',
+        '@type': '@id'
+      }
+    })
+  }
+
+  return Object.assign({}, data, {
     '@context': [
       'https://www.w3.org/ns/activitystreams',
       'https://w3id.org/security/v1',
-      {
-        RsaSignature2017: 'https://w3id.org/security#RsaSignature2017',
-        pt: 'https://joinpeertube.org/ns#',
-        sc: 'http://schema.org#',
-        Hashtag: 'as:Hashtag',
-        uuid: 'sc:identifier',
-        category: 'sc:category',
-        licence: 'sc:license',
-        subtitleLanguage: 'sc:subtitleLanguage',
-        sensitive: 'as:sensitive',
-        language: 'sc:inLanguage',
-        expires: 'sc:expires',
-        CacheFile: 'pt:CacheFile',
-        Infohash: 'pt:Infohash',
-        originallyPublishedAt: 'sc:datePublished',
-        views: {
-          '@type': 'sc:Number',
-          '@id': 'pt:views'
-        },
-        state: {
-          '@type': 'sc:Number',
-          '@id': 'pt:state'
-        },
-        size: {
-          '@type': 'sc:Number',
-          '@id': 'pt:size'
-        },
-        fps: {
-          '@type': 'sc:Number',
-          '@id': 'pt:fps'
-        },
-        startTimestamp: {
-          '@type': 'sc:Number',
-          '@id': 'pt:startTimestamp'
-        },
-        stopTimestamp: {
-          '@type': 'sc:Number',
-          '@id': 'pt:stopTimestamp'
-        },
-        position: {
-          '@type': 'sc:Number',
-          '@id': 'pt:position'
-        },
-        commentsEnabled: {
-          '@type': 'sc:Boolean',
-          '@id': 'pt:commentsEnabled'
-        },
-        downloadEnabled: {
-          '@type': 'sc:Boolean',
-          '@id': 'pt:downloadEnabled'
-        },
-        waitTranscoding: {
-          '@type': 'sc:Boolean',
-          '@id': 'pt:waitTranscoding'
-        },
-        support: {
-          '@type': 'sc:Text',
-          '@id': 'pt:support'
-        }
-      },
-      {
-        likes: {
-          '@id': 'as:likes',
-          '@type': '@id'
-        },
-        dislikes: {
-          '@id': 'as:dislikes',
-          '@type': '@id'
-        },
-        playlists: {
-          '@id': 'pt:playlists',
-          '@type': '@id'
-        },
-        shares: {
-          '@id': 'as:shares',
-          '@type': '@id'
-        },
-        comments: {
-          '@id': 'as:comments',
-          '@type': '@id'
-        }
-      }
+      base
     ]
   })
 }
@@ -148,8 +155,8 @@ async function activityPubCollectionPagination (
 
 }
 
-function buildSignedActivity (byActor: MActor, data: Object) {
-  const activity = activityPubContextify(data)
+function buildSignedActivity (byActor: MActor, data: Object, contextType?: ContextType) {
+  const activity = activityPubContextify(data, contextType)
 
   return signJsonLDObject(byActor, activity) as Promise<Activity>
 }
index a0f33852ca79a7a8a07b0f26037db975c30274a5..d03b358f1a4ff3b5df2ce279863fa345e792b0bf 100644 (file)
@@ -28,7 +28,7 @@ async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare,
   logger.info('Creating job to send announce %s.', videoShare.url)
 
   const followersException = [ byActor ]
-  return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException)
+  return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException, 'Announce')
 }
 
 function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce {
index 8809417f9b16bcf76df88ec81b0f75cd30ccc1eb..47482b9a99ce8b81d20d9908ed6a7b6a5f4d452a 100644 (file)
@@ -16,7 +16,7 @@ async function sendView (byActor: ActorModel, video: MVideoAccountLight, t: Tran
     return buildViewActivity(url, byActor, video, audience)
   }
 
-  return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t })
+  return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t, contextType: 'View' })
 }
 
 function buildViewActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityView {
index 6fb4efd60c36e468a1e96751adc64b562fbe57e3..ce932eb1fb1d5dca88c15349e24a76b73009fe7d 100644 (file)
@@ -8,13 +8,15 @@ import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAud
 import { getServerActor } from '../../../helpers/utils'
 import { afterCommitIfTransaction } from '../../../helpers/database-utils'
 import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models'
+import { ContextType } from '@server/helpers/activitypub'
 
 async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
   byActor: MActorLight
   video: MVideoAccountLight
-  transaction?: Transaction
+  transaction?: Transaction,
+  contextType?: ContextType
 }) {
-  const { byActor, video, transaction } = options
+  const { byActor, video, transaction, contextType } = options
 
   const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction)
 
@@ -24,7 +26,7 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud
     const activity = activityBuilder(audience)
 
     return afterCommitIfTransaction(transaction, () => {
-      return unicastTo(activity, byActor, video.VideoChannel.Account.Actor.getSharedInbox())
+      return unicastTo(activity, byActor, video.VideoChannel.Account.Actor.getSharedInbox(), contextType)
     })
   }
 
@@ -34,7 +36,7 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud
 
   const actorsException = [ byActor ]
 
-  return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException)
+  return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException, contextType)
 }
 
 async function forwardVideoRelatedActivity (
@@ -90,11 +92,12 @@ async function broadcastToFollowers (
   byActor: MActorId,
   toFollowersOf: MActorId[],
   t: Transaction,
-  actorsException: MActorWithInboxes[] = []
+  actorsException: MActorWithInboxes[] = [],
+  contextType?: ContextType
 ) {
   const uris = await computeFollowerUris(toFollowersOf, actorsException, t)
 
-  return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor))
+  return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType))
 }
 
 async function broadcastToActors (
@@ -102,13 +105,14 @@ async function broadcastToActors (
   byActor: MActorId,
   toActors: MActor[],
   t?: Transaction,
-  actorsException: MActorWithInboxes[] = []
+  actorsException: MActorWithInboxes[] = [],
+  contextType?: ContextType
 ) {
   const uris = await computeUris(toActors, actorsException)
-  return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor))
+  return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType))
 }
 
-function broadcastTo (uris: string[], data: any, byActor: MActorId) {
+function broadcastTo (uris: string[], data: any, byActor: MActorId, contextType?: ContextType) {
   if (uris.length === 0) return undefined
 
   logger.debug('Creating broadcast job.', { uris })
@@ -116,19 +120,21 @@ function broadcastTo (uris: string[], data: any, byActor: MActorId) {
   const payload = {
     uris,
     signatureActorId: byActor.id,
-    body: data
+    body: data,
+    contextType
   }
 
   return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })
 }
 
-function unicastTo (data: any, byActor: MActorId, toActorUrl: string) {
+function unicastTo (data: any, byActor: MActorId, toActorUrl: string, contextType?: ContextType) {
   logger.debug('Creating unicast job.', { uri: toActorUrl })
 
   const payload = {
     uri: toActorUrl,
     signatureActorId: byActor.id,
-    body: data
+    body: data,
+    contextType
   }
 
   JobQueue.Instance.createJob({ type: 'activitypub-http-unicast', payload })
index 0ff7b44a0af8f3df10b238ed00fcefafc2303b5e..7d9dd61e9475f2e0a53e42c8f13c6b27026d40e9 100644 (file)
@@ -5,11 +5,13 @@ import { doRequest } from '../../../helpers/requests'
 import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils'
 import { BROADCAST_CONCURRENCY, JOB_REQUEST_TIMEOUT } from '../../../initializers/constants'
 import { ActorFollowScoreCache } from '../../files-cache'
+import { ContextType } from '@server/helpers/activitypub'
 
 export type ActivitypubHttpBroadcastPayload = {
   uris: string[]
   signatureActorId?: number
   body: any
+  contextType?: ContextType
 }
 
 async function processActivityPubHttpBroadcast (job: Bull.Job) {
index c70ce3be90fb80a346787391acc85b8cbb5d63a5..6b71e28916c82aa8dd2fa6d0b8a07dfc496458b2 100644 (file)
@@ -4,11 +4,13 @@ import { doRequest } from '../../../helpers/requests'
 import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils'
 import { JOB_REQUEST_TIMEOUT } from '../../../initializers/constants'
 import { ActorFollowScoreCache } from '../../files-cache'
+import { ContextType } from '@server/helpers/activitypub'
 
 export type ActivitypubHttpUnicastPayload = {
   uri: string
   signatureActorId?: number
   body: any
+  contextType?: ContextType
 }
 
 async function processActivityPubHttpUnicast (job: Bull.Job) {
index a28f3596f7aebc33be3f62c37aea5cee8a0389f3..54b35840df90be01772af9f91b2fc5eb21882f58 100644 (file)
@@ -1,11 +1,11 @@
-import { buildSignedActivity } from '../../../../helpers/activitypub'
+import { buildSignedActivity, ContextType } from '../../../../helpers/activitypub'
 import { getServerActor } from '../../../../helpers/utils'
 import { ActorModel } from '../../../../models/activitypub/actor'
 import { sha256 } from '../../../../helpers/core-utils'
 import { HTTP_SIGNATURE } from '../../../../initializers/constants'
 import { MActor } from '../../../../typings/models'
 
-type Payload = { body: any, signatureActorId?: number }
+type Payload = { body: any, contextType?: ContextType, signatureActorId?: number }
 
 async function computeBody (payload: Payload) {
   let body = payload.body
@@ -13,7 +13,7 @@ async function computeBody (payload: Payload) {
   if (payload.signatureActorId) {
     const actorSignature = await ActorModel.load(payload.signatureActorId)
     if (!actorSignature) throw new Error('Unknown signature actor id.')
-    body = await buildSignedActivity(actorSignature, payload.body)
+    body = await buildSignedActivity(actorSignature, payload.body, payload.contextType)
   }
 
   return body