From f7e7cddf72f64fb881b3d5e74872996df0829280 Mon Sep 17 00:00:00 2001 From: John Livingston Date: Tue, 4 Jul 2023 18:07:59 +0200 Subject: [PATCH] FEP-1970: implementation WIP: Adding the data on outgoing objects. Related to #113. --- CHANGELOG.md | 6 ++++ server/lib/federation/outgoing.ts | 56 ++++++++++++++++++++++++++----- server/lib/federation/types.ts | 6 ++++ server/lib/uri/webchat.ts | 10 +++++- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6d4e14a..d45025ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 7.2.0 (Not Released Yet) + +## New Features + +* Implementing the [FEP-1970](https://codeberg.org/fediverse/fep/src/branch/main/fep/0ea0/fep-0ea0.md) draft for ActivityPub chat declaration. + ## 7.1.0 ### Minor changes and fixes diff --git a/server/lib/federation/outgoing.ts b/server/lib/federation/outgoing.ts index 6db2e82a..9421f91f 100644 --- a/server/lib/federation/outgoing.ts +++ b/server/lib/federation/outgoing.ts @@ -8,7 +8,7 @@ import type { } from './types' import { storeVideoLiveChatInfos } from './storage' import { videoHasWebchat } from '../../../shared/lib/video' -import { getBoshUri, getWSUri, getWSS2SUri } from '../uri/webchat' +import { getBoshUri, getWSUri, getWSS2SUri, getPublicChatUri } from '../uri/webchat' import { canonicalizePluginUri } from '../uri/canonicalize' import { getProsodyDomain } from '../prosody/config/domain' import { fillVideoCustomFields } from '../custom-fields' @@ -16,18 +16,18 @@ import { fillVideoCustomFields } from '../custom-fields' /** * This function adds LiveChat information on video ActivityPub data if relevant. * @param options server options - * @param jsonld JSON-LD video data to fill + * @param videoJsonld JSON-LD video data to fill * @param context handler context * @returns void */ async function videoBuildJSONLD ( options: RegisterServerOptions, - jsonld: VideoObject, + videoJsonld: VideoObject | LiveChatVideoObject, context: VideoBuildResultContext ): Promise { const logger = options.peertubeHelpers.logger const video = context.video - if (video.remote) { return jsonld } // should not happen, but... just in case... + if (video.remote) { return videoJsonld } // should not happen, but... just in case... const settings = await options.settingsManager.getSettings([ 'chat-per-live-video', @@ -45,7 +45,7 @@ async function videoBuildJSONLD ( if (settings['federation-dont-publish-remotely']) { // Note: we store also outgoing data. Could help for migration/cleanup scripts, for example. await storeVideoLiveChatInfos(options, video, false) - return jsonld + return videoJsonld } await fillVideoCustomFields(options, video) @@ -60,10 +60,10 @@ async function videoBuildJSONLD ( logger.debug(`Video uuid=${video.uuid} has not livechat, adding peertubeLiveChat=false.`) // Note: we store also outgoing data. Could help for migration/cleanup scripts, for example. await storeVideoLiveChatInfos(options, video, false) - Object.assign(jsonld, { + Object.assign(videoJsonld, { peertubeLiveChat: false }) - return jsonld + return videoJsonld } logger.debug(`Adding LiveChat data on video uuid=${video.uuid}...`) @@ -84,6 +84,43 @@ async function videoBuildJSONLD ( 'chat-no-anonymous': settings['chat-no-anonymous'] }) + // Adding attachments, as described in FEP-1970 + const discussionLinks: LiveChatVideoObject['attachment'] = [] + discussionLinks.push({ + type: 'Link', + name: 'Chat', // TODO: getter naming, maybe use chat_for_live_stream loc string + rel: 'discussion', + href: getPublicChatUri(options, videoJsonld) + }) + // Adding the xmpp:// link requires: + // - prosody-room-allow-s2s + // - prosody-s2s-port + // For now, this can be tested reading serverInfos.directs2s + if (serverInfos.directs2s) { + discussionLinks.push({ + type: 'Link', + name: 'Chat', // TODO: getter naming, maybe use chat_for_live_stream loc string + rel: 'discussion', + href: 'xmpp://' + roomJID + '?join' + }) + } + + if (!('attachment' in videoJsonld) || !videoJsonld.attachment) { + Object.assign(videoJsonld, { + attachment: discussionLinks + }) + } else if (Array.isArray(videoJsonld.attachment)) { + videoJsonld.attachment.push(...discussionLinks) + } else { + videoJsonld.attachment = [ + videoJsonld.attachment, + ...discussionLinks + ] + } + + // Code beneath this point is for backward compatibility, before v7.2.0. + // Since then, the ActivityPub metadata were not standardized. + // For backward compatibility with remote servers, using plugin <=6.3.0, we must provide links: const links: LiveChatJSONLDLink[] = [] if (serverInfos.anonymous) { @@ -103,18 +140,19 @@ async function videoBuildJSONLD ( } } + // This is the custom format used by plugin > 6.3.0. const peertubeLiveChat: LiveChatJSONLDAttribute = { type: 'xmpp', jid: roomJID, links, xmppserver: serverInfos } - Object.assign(jsonld, { + Object.assign(videoJsonld, { peertubeLiveChat }) // Note: we store also outgoing data. Could help for migration/cleanup scripts, for example. await storeVideoLiveChatInfos(options, video, peertubeLiveChat) - return jsonld + return videoJsonld } async function serverBuildInfos (options: RegisterServerOptions): Promise { diff --git a/server/lib/federation/types.ts b/server/lib/federation/types.ts index 73f1d545..69458959 100644 --- a/server/lib/federation/types.ts +++ b/server/lib/federation/types.ts @@ -65,6 +65,12 @@ type LiveChatJSONLDAttributeV1 = LiveChatJSONLDInfosV1 | false interface LiveChatVideoObject extends VideoObject { peertubeLiveChat: LiveChatJSONLDAttribute + attachment: Array<{ + type: 'Link' + name: string + href: string + rel: string + }> } interface RemoteVideoHandlerParams { diff --git a/server/lib/uri/webchat.ts b/server/lib/uri/webchat.ts index d63d07bf..7121bc1a 100644 --- a/server/lib/uri/webchat.ts +++ b/server/lib/uri/webchat.ts @@ -1,6 +1,7 @@ -import type { RegisterServerOptions } from '@peertube/peertube-types' +import type { RegisterServerOptions, VideoObject } from '@peertube/peertube-types' import { getBaseRouterRoute, getBaseWebSocketRoute } from '../helpers' +import { canonicalizePluginUri } from './canonicalize' export function getBoshUri (options: RegisterServerOptions): string { return getBaseRouterRoute(options) + 'http-bind' @@ -17,3 +18,10 @@ export function getWSS2SUri (options: RegisterServerOptions): string | undefined if (base === undefined) { return undefined } return base + 'xmpp-websocket-s2s' } + +export function getPublicChatUri (options: RegisterServerOptions, video: VideoObject): string { + const url = getBaseRouterRoute(options) + 'webchat/room/' + encodeURIComponent(video.uuid) + return canonicalizePluginUri(options, url, { + removePluginVersion: true + }) +}