Chat federation: add metadata in ActivityPub. WIP
This commit is contained in:
parent
bcafac5cce
commit
115fcd8484
7017
package-lock.json
generated
7017
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -40,7 +40,7 @@
|
|||||||
"validate-color": "^2.2.1"
|
"validate-color": "^2.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@peertube/peertube-types": "^4.2.2",
|
"@peertube/peertube-types": "^5.1.0",
|
||||||
"@tsconfig/node12": "^1.0.9",
|
"@tsconfig/node12": "^1.0.9",
|
||||||
"@types/async": "^3.2.9",
|
"@types/async": "^3.2.9",
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
|
117
server/lib/federation/init.ts
Normal file
117
server/lib/federation/init.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import type { RegisterServerOptions, VideoObject, MVideoAP, MVideoFullLight } from '@peertube/peertube-types'
|
||||||
|
import { videoHasWebchat } from '../../../shared/lib/video'
|
||||||
|
import { getBoshUri, getWSUri } from '../uri/webchat'
|
||||||
|
import { fullUri } from '../uri/full'
|
||||||
|
import { getProsodyDomain } from '../prosody/config/domain'
|
||||||
|
|
||||||
|
interface LiveChatVideoObject extends VideoObject {
|
||||||
|
peertubeLiveChat: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoBuildResultContext {
|
||||||
|
video: MVideoAP
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RemoteHandlerParams {
|
||||||
|
video: MVideoFullLight
|
||||||
|
videoAPObject: VideoObject | LiveChatVideoObject
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initFederation (options: RegisterServerOptions): Promise<void> {
|
||||||
|
const logger = options.peertubeHelpers.logger
|
||||||
|
const registerHook = options.registerHook
|
||||||
|
logger.info('Registring federation hooks...')
|
||||||
|
|
||||||
|
registerHook({
|
||||||
|
target: 'filter:activity-pub.video.json-ld.build.result',
|
||||||
|
handler: async (
|
||||||
|
jsonld: VideoObject,
|
||||||
|
context: VideoBuildResultContext
|
||||||
|
): Promise<VideoObject | LiveChatVideoObject> => {
|
||||||
|
const video = context.video
|
||||||
|
if (video.remote) { return jsonld } // should not happen, but... just in case...
|
||||||
|
|
||||||
|
const settings = await options.settingsManager.getSettings([
|
||||||
|
'chat-per-live-video',
|
||||||
|
'chat-all-lives',
|
||||||
|
'chat-all-non-lives',
|
||||||
|
'chat-videos-list',
|
||||||
|
'disable-websocket',
|
||||||
|
'prosody-room-type'
|
||||||
|
])
|
||||||
|
|
||||||
|
const hasChat = await videoHasWebchat({
|
||||||
|
'chat-per-live-video': !!settings['chat-per-live-video'],
|
||||||
|
'chat-all-lives': !!settings['chat-all-lives'],
|
||||||
|
'chat-all-non-lives': !!settings['chat-all-non-lives'],
|
||||||
|
'chat-videos-list': settings['chat-videos-list'] as string
|
||||||
|
}, video)
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
`Adding LiveChat data on video uuid=${video.uuid}: peertubeLiveChat=${hasChat ? 'true' : 'false'}`
|
||||||
|
)
|
||||||
|
|
||||||
|
const prosodyDomain = await getProsodyDomain(options)
|
||||||
|
const userJID = 'anon.' + prosodyDomain
|
||||||
|
let roomJID: string
|
||||||
|
if (settings['prosody-room-type'] === 'channel') {
|
||||||
|
roomJID = `channel.${video.channelId}@room.${prosodyDomain}`
|
||||||
|
} else {
|
||||||
|
roomJID = `${video.uuid}@room.${prosodyDomain}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const links = [{
|
||||||
|
type: 'xmpp-bosh-anonymous',
|
||||||
|
url: fullUri(options, getBoshUri(options)),
|
||||||
|
jid: userJID
|
||||||
|
}]
|
||||||
|
if (!settings['disable-websocket']) {
|
||||||
|
const wsUri = getWSUri(options)
|
||||||
|
if (wsUri) {
|
||||||
|
links.push({
|
||||||
|
type: 'xmpp-websocket-anonymous',
|
||||||
|
url: fullUri(options, wsUri),
|
||||||
|
jid: userJID
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign(jsonld, {
|
||||||
|
peertubeLiveChat: {
|
||||||
|
type: 'xmpp',
|
||||||
|
jid: roomJID,
|
||||||
|
links
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: we should also register the context.build hook.
|
||||||
|
// registerHook({
|
||||||
|
// target: 'filter:activity-pub.activity.context.build.result',
|
||||||
|
// handler: (jsonld: any) => {
|
||||||
|
// return jsonld.concat([
|
||||||
|
// { peertubeLiveChat: 'sc:Boolean' }
|
||||||
|
// ])
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
const remoteHandler = async ({ video, videoAPObject }: RemoteHandlerParams): Promise<void> => {
|
||||||
|
if (!('peertubeLiveChat' in videoAPObject)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: save the information.
|
||||||
|
logger.debug(
|
||||||
|
`Remote video uuid=${video.uuid} has a peertubeLiveChat attribute: ` +
|
||||||
|
JSON.stringify(videoAPObject.peertubeLiveChat)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
registerHook({
|
||||||
|
target: 'action:activity-pub.remote-video.created',
|
||||||
|
handler: remoteHandler
|
||||||
|
})
|
||||||
|
registerHook({
|
||||||
|
target: 'action:activity-pub.remote-video.updated',
|
||||||
|
handler: remoteHandler
|
||||||
|
})
|
||||||
|
}
|
@ -5,13 +5,14 @@ import type {
|
|||||||
} from '../../../shared/lib/types'
|
} from '../../../shared/lib/types'
|
||||||
import { createProxyServer } from 'http-proxy'
|
import { createProxyServer } from 'http-proxy'
|
||||||
import {
|
import {
|
||||||
RegisterServerOptionsV5, getBaseRouterRoute, getBaseWebSocketRoute, getBaseStaticRoute, isUserAdmin
|
RegisterServerOptionsV5, getBaseRouterRoute, getBaseStaticRoute, isUserAdmin
|
||||||
} from '../helpers'
|
} from '../helpers'
|
||||||
import { asyncMiddleware } from '../middlewares/async'
|
import { asyncMiddleware } from '../middlewares/async'
|
||||||
import { getProsodyDomain } from '../prosody/config/domain'
|
import { getProsodyDomain } from '../prosody/config/domain'
|
||||||
import { getAPIKey } from '../apikey'
|
import { getAPIKey } from '../apikey'
|
||||||
import { getChannelInfosById, getChannelNameById } from '../database/channel'
|
import { getChannelInfosById, getChannelNameById } from '../database/channel'
|
||||||
import { isAutoColorsAvailable, areAutoColorsValid, AutoColors } from '../../../shared/lib/autocolors'
|
import { isAutoColorsAvailable, areAutoColorsValid, AutoColors } from '../../../shared/lib/autocolors'
|
||||||
|
import { getBoshUri, getWSUri } from '../uri/webchat'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
const got = require('got')
|
const got = require('got')
|
||||||
|
|
||||||
@ -48,11 +49,10 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
|
|||||||
'converse-theme', 'converse-autocolors'
|
'converse-theme', 'converse-autocolors'
|
||||||
])
|
])
|
||||||
|
|
||||||
const boshUri = getBaseRouterRoute(options) + 'http-bind'
|
const boshUri = getBoshUri(options)
|
||||||
let wsUri = settings['disable-websocket']
|
const wsUri = settings['disable-websocket']
|
||||||
? undefined
|
? ''
|
||||||
: getBaseWebSocketRoute(options) // can be undefined
|
: (getWSUri(options) ?? '')
|
||||||
wsUri = wsUri !== undefined ? wsUri + 'xmpp-websocket' : ''
|
|
||||||
|
|
||||||
let room: string
|
let room: string
|
||||||
let autoViewerMode: boolean = false
|
let autoViewerMode: boolean = false
|
||||||
|
10
server/lib/uri/full.ts
Normal file
10
server/lib/uri/full.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import type { RegisterServerOptions } from '@peertube/peertube-types'
|
||||||
|
import * as url from 'url'
|
||||||
|
|
||||||
|
export function fullUri (options: RegisterServerOptions, path: string): string {
|
||||||
|
if (path.startsWith('https://') || path.startsWith('http://')) {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
const uri = new url.URL(path, options.peertubeHelpers.config.getWebserverUrl())
|
||||||
|
return uri.toString()
|
||||||
|
}
|
13
server/lib/uri/webchat.ts
Normal file
13
server/lib/uri/webchat.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
import type { RegisterServerOptions } from '@peertube/peertube-types'
|
||||||
|
import { getBaseRouterRoute, getBaseWebSocketRoute } from '../helpers'
|
||||||
|
|
||||||
|
export function getBoshUri (options: RegisterServerOptions): string {
|
||||||
|
return getBaseRouterRoute(options) + 'http-bind'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWSUri (options: RegisterServerOptions): string | undefined {
|
||||||
|
const base = getBaseWebSocketRoute(options) // can be undefined if Peertube is too old
|
||||||
|
if (base === undefined) { return undefined }
|
||||||
|
return base + 'xmpp-websocket'
|
||||||
|
}
|
@ -3,6 +3,7 @@ import { migrateSettings } from './lib/migration/settings'
|
|||||||
import { initSettings } from './lib/settings'
|
import { initSettings } from './lib/settings'
|
||||||
import { initCustomFields } from './lib/custom-fields'
|
import { initCustomFields } from './lib/custom-fields'
|
||||||
import { initRouters } from './lib/routers/index'
|
import { initRouters } from './lib/routers/index'
|
||||||
|
import { initFederation } from './lib/federation/init'
|
||||||
import { prepareProsody, ensureProsodyRunning, ensureProsodyNotRunning } from './lib/prosody/ctl'
|
import { prepareProsody, ensureProsodyRunning, ensureProsodyNotRunning } from './lib/prosody/ctl'
|
||||||
import decache from 'decache'
|
import decache from 'decache'
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ async function register (options: RegisterServerOptions): Promise<any> {
|
|||||||
await initSettings(options)
|
await initSettings(options)
|
||||||
await initCustomFields(options)
|
await initCustomFields(options)
|
||||||
await initRouters(options)
|
await initRouters(options)
|
||||||
|
await initFederation(options)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await prepareProsody(options)
|
await prepareProsody(options)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user