Using Peertube v5.0.0 websocket capacities.

This commit is contained in:
John Livingston 2022-10-13 18:34:41 +02:00
parent e7eca75736
commit 0be08c7b57
No known key found for this signature in database
GPG Key ID: B17B5640CE66CDBC
3 changed files with 51 additions and 76 deletions

1
package-lock.json generated
View File

@ -25076,6 +25076,7 @@
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"emoji-regex": {

View File

@ -1,5 +1,7 @@
import type { RegisterServerOptions, PeerTubeHelpers } from '@peertube/peertube-types'
import { Response } from 'express'
import type { Response } from 'express'
import type { IncomingMessage } from 'http'
import type { Duplex } from 'stream'
const packagejson: any = require('../../../package.json')
const version: string = packagejson.version || ''
@ -19,14 +21,34 @@ function getBaseRouterRoute (options: RegisterServerOptions): string {
return options.peertubeHelpers.plugin.getBaseRouterRoute()
}
interface RegisterServerWebSocketRouteOptions {
route: string
handler: (request: IncomingMessage, socket: Duplex, head: Buffer) => any
}
// getBaseWebSocketRoute() comes with Peertube 5.0.0.
type RegisterServerOptionsV5 = RegisterServerOptions & {
registerWebSocketRoute?: (options: RegisterServerWebSocketRouteOptions) => void
peertubeHelpers: {
plugin: {
getBaseWebSocketRoute?: () => string
}
}
}
/**
* Returns the base router route, but without the plugin version.
* Returns the base route for Websocket endpoint.
* This features comes with Peertube >=5.0.0.
* @param options server options
* @returns the route, or undefined if the Peertube version does not provide this feature
*/
function getBaseRouterCanonicalRoute (options: RegisterServerOptions): string {
let route = getBaseRouterRoute(options)
route = route.replace(pluginShortName + '/' + version + '/', pluginShortName + '/')
return route
function getBaseWebSocketRoute (options: RegisterServerOptionsV5): string | undefined {
if (!options.peertubeHelpers.plugin) {
throw new Error('Missing peertubeHelpers.plugin, have you the correct Peertube version?')
}
if (!options.peertubeHelpers.plugin.getBaseWebSocketRoute) {
return undefined
}
return options.peertubeHelpers.plugin.getBaseWebSocketRoute()
}
function getBaseStaticRoute (options: RegisterServerOptions): string {
@ -71,8 +93,9 @@ async function getUserNickname (options: RegisterServerOptions, user: AuthUserFi
}
export {
RegisterServerOptionsV5,
getBaseRouterRoute,
getBaseRouterCanonicalRoute,
getBaseWebSocketRoute,
getBaseStaticRoute,
isUserAdmin,
getUserNickname,

View File

@ -4,7 +4,9 @@ import type {
ProsodyListRoomsResult, ProsodyListRoomsResultRoom
} from '../../../shared/lib/types'
import { createProxyServer } from 'http-proxy'
import { getBaseRouterRoute, getBaseRouterCanonicalRoute, getBaseStaticRoute, isUserAdmin } from '../helpers'
import {
RegisterServerOptionsV5, getBaseRouterRoute, getBaseWebSocketRoute, getBaseStaticRoute, isUserAdmin
} from '../helpers'
import { asyncMiddleware } from '../middlewares/async'
import { getProsodyDomain } from '../prosody/config/domain'
import { getAPIKey } from '../apikey'
@ -14,7 +16,6 @@ import * as path from 'path'
const got = require('got')
const fs = require('fs').promises
// const proxy = require('express-http-proxy')
interface ProsodyProxyInfo {
host: string
@ -23,15 +24,11 @@ interface ProsodyProxyInfo {
let currentProsodyProxyInfo: ProsodyProxyInfo | null = null
let currentHttpBindProxy: ReturnType<typeof createProxyServer> | null = null
let currentWebsocketProxy: ReturnType<typeof createProxyServer> | null = null
interface CurrentWebsocketUpgradeEvent {
server: any
listener: Function
}
let currentWebsocketUpgradeEvent: CurrentWebsocketUpgradeEvent | null = null
async function initWebchatRouter (options: RegisterServerOptions): Promise<Router> {
async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Router> {
const {
getRouter,
registerWebSocketRoute,
peertubeHelpers,
settingsManager
} = options
@ -50,6 +47,10 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise<Route
'converse-theme', 'converse-autocolors'
])
const boshUri = getBaseRouterRoute(options) + 'http-bind'
let wsUri = getBaseWebSocketRoute(options) // can be undefined
wsUri = wsUri !== undefined ? wsUri + 'xmpp-websocket' : ''
let room: string
let authenticationUrl: string = ''
let advancedControls: boolean = false // auto join the chat in viewer mode, if not logged in
@ -81,13 +82,7 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise<Route
room = '{{VIDEO_UUID}}@room.' + prosodyDomain
}
}
// Here we are using getBaseRouterCanonicalRoute,
// which correspond to a path without the plugin version.
// We are doing this, so the path is predictible,
// and can be optimized in the nginx configuration (to bypass Peertube).
const proxyBaseUri = getBaseRouterCanonicalRoute(options) + 'webchat/'
const boshUri = proxyBaseUri + 'http-bind'
const wsUri = proxyBaseUri + 'xmpp-websocket'
authenticationUrl = options.peertubeHelpers.config.getWebserverUrl() +
getBaseRouterRoute(options) +
'api/auth'
@ -229,59 +224,19 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise<Route
}
}
)
router.all('/xmpp-websocket',
(req: Request, res: Response, next: NextFunction) => {
try {
// Peertube >=5.0.0: Adding the websocket route.
if (registerWebSocketRoute) {
registerWebSocketRoute({
route: '/xmpp-websocket',
handler: (request, socket, head) => {
if (!currentWebsocketProxy) {
res.status(404)
res.send('Not found')
return
throw new Error('There is no current websocket proxy, should not get here.')
}
// Now, we need to attach an listener for the update event on the server...
// But we don't have access to the server.
// To get this, we will wait for the first request, and then get the server from there!
if (!currentWebsocketUpgradeEvent) {
peertubeHelpers.logger.info(
'Here is the first websocket proxy connection, we are binding the upgrade listener...'
)
/**
* Get the server object to subscribe to server events;
* 'upgrade' for websocket and 'close' for graceful shutdown
*
* NOTE:
* req.socket: node >= 13
* req.connection: node < 13 (Remove this when node 12/13 support is dropped)
*
* This code was inspired by:
* https://github.com/chimurai/http-proxy-middleware, file /src/http-proxy-middleware.ts#L53
*/
const s: any = (req.socket ?? req.connection)
const server = 'server' in s ? s.server : null
if (!server) {
peertubeHelpers.logger.error('Cant access to the ExpressJS server, wont be able to handle websocket.')
} else {
currentWebsocketUpgradeEvent = {
server,
listener: (req: any, socket: any, head: any) => {
// We are not the only websocket server! Peertube has its own. We must match the url.
if (/webchat\/xmpp-websocket/.test(req.url)) {
peertubeHelpers.logger.info('Got an http upgrade event that match the correct path')
currentWebsocketProxy?.ws(req, socket, head)
}
}
}
server.on('upgrade', currentWebsocketUpgradeEvent.listener)
}
}
req.url = 'xmpp-websocket'
currentWebsocketProxy.web(req, res)
} catch (err) {
next(err)
currentWebsocketProxy.ws(request, socket, head)
}
}
)
})
}
router.get('/prosody-list-rooms', asyncMiddleware(
async (req: Request, res: Response, _next: NextFunction) => {
@ -356,10 +311,6 @@ async function disableProxyRoute ({ peertubeHelpers }: RegisterServerOptions): P
currentWebsocketProxy.close()
currentWebsocketProxy = null
}
if (currentWebsocketUpgradeEvent) {
peertubeHelpers.logger.info('Removing the upgrade listener')
currentWebsocketUpgradeEvent.server.off('upgrade', currentWebsocketUpgradeEvent.listener)
}
} catch (err) {
peertubeHelpers.logger.error('Seems that the http bind proxy close has failed: ' + (err as string))
}