Add ability for plugins to register ws routes
This commit is contained in:
parent
9866921cbf
commit
9d4c60dccc
16 changed files with 262 additions and 7 deletions
|
@ -202,6 +202,11 @@ export class PluginService implements ClientHook {
|
||||||
return environment.apiUrl + `${pathPrefix}/${plugin.name}/${plugin.version}/router`
|
return environment.apiUrl + `${pathPrefix}/${plugin.name}/${plugin.version}/router`
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getBaseWebSocketRoute: () => {
|
||||||
|
const pathPrefix = PluginsManager.getPluginPathPrefix(pluginInfo.isTheme)
|
||||||
|
return environment.apiUrl + `${pathPrefix}/${plugin.name}/${plugin.version}/ws`
|
||||||
|
},
|
||||||
|
|
||||||
getBasePluginClientPath: () => {
|
getBasePluginClientPath: () => {
|
||||||
return '/p'
|
return '/p'
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,6 +43,7 @@ export class PeerTubePlugin {
|
||||||
return {
|
return {
|
||||||
getBaseStaticRoute: unimplemented,
|
getBaseStaticRoute: unimplemented,
|
||||||
getBaseRouterRoute: unimplemented,
|
getBaseRouterRoute: unimplemented,
|
||||||
|
getBaseWebSocketRoute: unimplemented,
|
||||||
getBasePluginClientPath: unimplemented,
|
getBasePluginClientPath: unimplemented,
|
||||||
|
|
||||||
getSettings: () => {
|
getSettings: () => {
|
||||||
|
|
|
@ -24,6 +24,9 @@ export type RegisterClientHelpers = {
|
||||||
|
|
||||||
getBaseRouterRoute: () => string
|
getBaseRouterRoute: () => string
|
||||||
|
|
||||||
|
// PeerTube >= 5.0
|
||||||
|
getBaseWebSocketRoute: () => string
|
||||||
|
|
||||||
getBasePluginClientPath: () => string
|
getBasePluginClientPath: () => string
|
||||||
|
|
||||||
isLoggedIn: () => boolean
|
isLoggedIn: () => boolean
|
||||||
|
|
|
@ -328,6 +328,10 @@ async function startApplication () {
|
||||||
GeoIPUpdateScheduler.Instance.enable()
|
GeoIPUpdateScheduler.Instance.enable()
|
||||||
OpenTelemetryMetrics.Instance.registerMetrics()
|
OpenTelemetryMetrics.Instance.registerMetrics()
|
||||||
|
|
||||||
|
PluginManager.Instance.init(server)
|
||||||
|
// Before PeerTubeSocket init
|
||||||
|
PluginManager.Instance.registerWebSocketRouter()
|
||||||
|
|
||||||
PeerTubeSocket.Instance.init(server)
|
PeerTubeSocket.Instance.init(server)
|
||||||
VideoViewsManager.Instance.init()
|
VideoViewsManager.Instance.init()
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
import { Server } from 'http'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { ffprobePromise } from '@server/helpers/ffmpeg/ffprobe-utils'
|
import { ffprobePromise } from '@server/helpers/ffmpeg/ffprobe-utils'
|
||||||
import { buildLogger } from '@server/helpers/logger'
|
import { buildLogger } from '@server/helpers/logger'
|
||||||
|
@ -17,12 +18,12 @@ import { MPlugin, MVideo, UserNotificationModelForApi } from '@server/types/mode
|
||||||
import { PeerTubeHelpers } from '@server/types/plugins'
|
import { PeerTubeHelpers } from '@server/types/plugins'
|
||||||
import { VideoBlacklistCreate, VideoStorage } from '@shared/models'
|
import { VideoBlacklistCreate, VideoStorage } from '@shared/models'
|
||||||
import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist'
|
import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist'
|
||||||
|
import { PeerTubeSocket } from '../peertube-socket'
|
||||||
import { ServerConfigManager } from '../server-config-manager'
|
import { ServerConfigManager } from '../server-config-manager'
|
||||||
import { blacklistVideo, unblacklistVideo } from '../video-blacklist'
|
import { blacklistVideo, unblacklistVideo } from '../video-blacklist'
|
||||||
import { VideoPathManager } from '../video-path-manager'
|
import { VideoPathManager } from '../video-path-manager'
|
||||||
import { PeerTubeSocket } from '../peertube-socket'
|
|
||||||
|
|
||||||
function buildPluginHelpers (pluginModel: MPlugin, npmName: string): PeerTubeHelpers {
|
function buildPluginHelpers (httpServer: Server, pluginModel: MPlugin, npmName: string): PeerTubeHelpers {
|
||||||
const logger = buildPluginLogger(npmName)
|
const logger = buildPluginLogger(npmName)
|
||||||
|
|
||||||
const database = buildDatabaseHelpers()
|
const database = buildDatabaseHelpers()
|
||||||
|
@ -30,7 +31,7 @@ function buildPluginHelpers (pluginModel: MPlugin, npmName: string): PeerTubeHel
|
||||||
|
|
||||||
const config = buildConfigHelpers()
|
const config = buildConfigHelpers()
|
||||||
|
|
||||||
const server = buildServerHelpers()
|
const server = buildServerHelpers(httpServer)
|
||||||
|
|
||||||
const moderation = buildModerationHelpers()
|
const moderation = buildModerationHelpers()
|
||||||
|
|
||||||
|
@ -69,8 +70,10 @@ function buildDatabaseHelpers () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildServerHelpers () {
|
function buildServerHelpers (httpServer: Server) {
|
||||||
return {
|
return {
|
||||||
|
getHTTPServer: () => httpServer,
|
||||||
|
|
||||||
getServerActor: () => getServerActor()
|
getServerActor: () => getServerActor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +221,8 @@ function buildPluginRelatedHelpers (plugin: MPlugin, npmName: string) {
|
||||||
|
|
||||||
getBaseRouterRoute: () => `/plugins/${plugin.name}/${plugin.version}/router/`,
|
getBaseRouterRoute: () => `/plugins/${plugin.name}/${plugin.version}/router/`,
|
||||||
|
|
||||||
|
getBaseWebSocketRoute: () => `/plugins/${plugin.name}/${plugin.version}/ws/`,
|
||||||
|
|
||||||
getDataDirectoryPath: () => join(CONFIG.STORAGE.PLUGINS_DIR, 'data', npmName)
|
getDataDirectoryPath: () => join(CONFIG.STORAGE.PLUGINS_DIR, 'data', npmName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { createReadStream, createWriteStream } from 'fs'
|
import { createReadStream, createWriteStream } from 'fs'
|
||||||
import { ensureDir, outputFile, readJSON } from 'fs-extra'
|
import { ensureDir, outputFile, readJSON } from 'fs-extra'
|
||||||
|
import { Server } from 'http'
|
||||||
import { basename, join } from 'path'
|
import { basename, join } from 'path'
|
||||||
import { decachePlugin } from '@server/helpers/decache'
|
import { decachePlugin } from '@server/helpers/decache'
|
||||||
import { ApplicationModel } from '@server/models/application/application'
|
import { ApplicationModel } from '@server/models/application/application'
|
||||||
|
@ -67,9 +68,37 @@ export class PluginManager implements ServerHook {
|
||||||
private hooks: { [name: string]: HookInformationValue[] } = {}
|
private hooks: { [name: string]: HookInformationValue[] } = {}
|
||||||
private translations: PluginLocalesTranslations = {}
|
private translations: PluginLocalesTranslations = {}
|
||||||
|
|
||||||
|
private server: Server
|
||||||
|
|
||||||
private constructor () {
|
private constructor () {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init (server: Server) {
|
||||||
|
this.server = server
|
||||||
|
}
|
||||||
|
|
||||||
|
registerWebSocketRouter () {
|
||||||
|
this.server.on('upgrade', (request, socket, head) => {
|
||||||
|
const url = request.url
|
||||||
|
|
||||||
|
const matched = url.match(`/plugins/([^/]+)/([^/]+/)?ws(/.*)`)
|
||||||
|
if (!matched) return
|
||||||
|
|
||||||
|
const npmName = PluginModel.buildNpmName(matched[1], PluginType.PLUGIN)
|
||||||
|
const subRoute = matched[3]
|
||||||
|
|
||||||
|
const result = this.getRegisteredPluginOrTheme(npmName)
|
||||||
|
if (!result) return
|
||||||
|
|
||||||
|
const routes = result.registerHelpers.getWebSocketRoutes()
|
||||||
|
|
||||||
|
const wss = routes.find(r => r.route.startsWith(subRoute))
|
||||||
|
if (!wss) return
|
||||||
|
|
||||||
|
wss.handler(request, socket, head)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ###################### Getters ######################
|
// ###################### Getters ######################
|
||||||
|
|
||||||
isRegistered (npmName: string) {
|
isRegistered (npmName: string) {
|
||||||
|
@ -581,7 +610,7 @@ export class PluginManager implements ServerHook {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const registerHelpers = new RegisterHelpers(npmName, plugin, onHookAdded.bind(this))
|
const registerHelpers = new RegisterHelpers(npmName, plugin, this.server, onHookAdded.bind(this))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
registerStore: registerHelpers,
|
registerStore: registerHelpers,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
import { Server } from 'http'
|
||||||
import { logger } from '@server/helpers/logger'
|
import { logger } from '@server/helpers/logger'
|
||||||
import { onExternalUserAuthenticated } from '@server/lib/auth/external-auth'
|
import { onExternalUserAuthenticated } from '@server/lib/auth/external-auth'
|
||||||
import { VideoConstantManagerFactory } from '@server/lib/plugins/video-constant-manager-factory'
|
import { VideoConstantManagerFactory } from '@server/lib/plugins/video-constant-manager-factory'
|
||||||
|
@ -8,7 +9,8 @@ import {
|
||||||
RegisterServerAuthExternalResult,
|
RegisterServerAuthExternalResult,
|
||||||
RegisterServerAuthPassOptions,
|
RegisterServerAuthPassOptions,
|
||||||
RegisterServerExternalAuthenticatedResult,
|
RegisterServerExternalAuthenticatedResult,
|
||||||
RegisterServerOptions
|
RegisterServerOptions,
|
||||||
|
RegisterServerWebSocketRouteOptions
|
||||||
} from '@server/types/plugins'
|
} from '@server/types/plugins'
|
||||||
import {
|
import {
|
||||||
EncoderOptionsBuilder,
|
EncoderOptionsBuilder,
|
||||||
|
@ -49,12 +51,15 @@ export class RegisterHelpers {
|
||||||
|
|
||||||
private readonly onSettingsChangeCallbacks: SettingsChangeCallback[] = []
|
private readonly onSettingsChangeCallbacks: SettingsChangeCallback[] = []
|
||||||
|
|
||||||
|
private readonly webSocketRoutes: RegisterServerWebSocketRouteOptions[] = []
|
||||||
|
|
||||||
private readonly router: express.Router
|
private readonly router: express.Router
|
||||||
private readonly videoConstantManagerFactory: VideoConstantManagerFactory
|
private readonly videoConstantManagerFactory: VideoConstantManagerFactory
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private readonly npmName: string,
|
private readonly npmName: string,
|
||||||
private readonly plugin: PluginModel,
|
private readonly plugin: PluginModel,
|
||||||
|
private readonly server: Server,
|
||||||
private readonly onHookAdded: (options: RegisterServerHookOptions) => void
|
private readonly onHookAdded: (options: RegisterServerHookOptions) => void
|
||||||
) {
|
) {
|
||||||
this.router = express.Router()
|
this.router = express.Router()
|
||||||
|
@ -66,6 +71,7 @@ export class RegisterHelpers {
|
||||||
const registerSetting = this.buildRegisterSetting()
|
const registerSetting = this.buildRegisterSetting()
|
||||||
|
|
||||||
const getRouter = this.buildGetRouter()
|
const getRouter = this.buildGetRouter()
|
||||||
|
const registerWebSocketRoute = this.buildRegisterWebSocketRoute()
|
||||||
|
|
||||||
const settingsManager = this.buildSettingsManager()
|
const settingsManager = this.buildSettingsManager()
|
||||||
const storageManager = this.buildStorageManager()
|
const storageManager = this.buildStorageManager()
|
||||||
|
@ -85,13 +91,14 @@ export class RegisterHelpers {
|
||||||
const unregisterIdAndPassAuth = this.buildUnregisterIdAndPassAuth()
|
const unregisterIdAndPassAuth = this.buildUnregisterIdAndPassAuth()
|
||||||
const unregisterExternalAuth = this.buildUnregisterExternalAuth()
|
const unregisterExternalAuth = this.buildUnregisterExternalAuth()
|
||||||
|
|
||||||
const peertubeHelpers = buildPluginHelpers(this.plugin, this.npmName)
|
const peertubeHelpers = buildPluginHelpers(this.server, this.plugin, this.npmName)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
registerHook,
|
registerHook,
|
||||||
registerSetting,
|
registerSetting,
|
||||||
|
|
||||||
getRouter,
|
getRouter,
|
||||||
|
registerWebSocketRoute,
|
||||||
|
|
||||||
settingsManager,
|
settingsManager,
|
||||||
storageManager,
|
storageManager,
|
||||||
|
@ -180,10 +187,20 @@ export class RegisterHelpers {
|
||||||
return this.onSettingsChangeCallbacks
|
return this.onSettingsChangeCallbacks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWebSocketRoutes () {
|
||||||
|
return this.webSocketRoutes
|
||||||
|
}
|
||||||
|
|
||||||
private buildGetRouter () {
|
private buildGetRouter () {
|
||||||
return () => this.router
|
return () => this.router
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private buildRegisterWebSocketRoute () {
|
||||||
|
return (options: RegisterServerWebSocketRouteOptions) => {
|
||||||
|
this.webSocketRoutes.push(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private buildRegisterSetting () {
|
private buildRegisterSetting () {
|
||||||
return (options: RegisterServerSettingOptions) => {
|
return (options: RegisterServerSettingOptions) => {
|
||||||
this.settings.push(options)
|
this.settings.push(options)
|
||||||
|
|
36
server/tests/fixtures/peertube-plugin-test-websocket/main.js
vendored
Normal file
36
server/tests/fixtures/peertube-plugin-test-websocket/main.js
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
const WebSocketServer = require('ws').WebSocketServer
|
||||||
|
|
||||||
|
async function register ({
|
||||||
|
registerWebSocketRoute
|
||||||
|
}) {
|
||||||
|
const wss = new WebSocketServer({ noServer: true })
|
||||||
|
|
||||||
|
wss.on('connection', function connection(ws) {
|
||||||
|
ws.on('message', function message(data) {
|
||||||
|
if (data.toString() === 'ping') {
|
||||||
|
ws.send('pong')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
registerWebSocketRoute({
|
||||||
|
route: '/toto',
|
||||||
|
|
||||||
|
handler: (request, socket, head) => {
|
||||||
|
wss.handleUpgrade(request, socket, head, ws => {
|
||||||
|
wss.emit('connection', ws, request)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unregister () {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
register,
|
||||||
|
unregister
|
||||||
|
}
|
||||||
|
|
||||||
|
// ###########################################################################
|
20
server/tests/fixtures/peertube-plugin-test-websocket/package.json
vendored
Normal file
20
server/tests/fixtures/peertube-plugin-test-websocket/package.json
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"name": "peertube-plugin-test-websocket",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Plugin test websocket",
|
||||||
|
"engine": {
|
||||||
|
"peertube": ">=1.3.0"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"peertube",
|
||||||
|
"plugin"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/Chocobozzz/PeerTube",
|
||||||
|
"author": "Chocobozzz",
|
||||||
|
"bugs": "https://github.com/Chocobozzz/PeerTube/issues",
|
||||||
|
"library": "./main.js",
|
||||||
|
"staticDirs": {},
|
||||||
|
"css": [],
|
||||||
|
"clientScripts": [],
|
||||||
|
"translations": {}
|
||||||
|
}
|
|
@ -8,5 +8,6 @@ import './plugin-router'
|
||||||
import './plugin-storage'
|
import './plugin-storage'
|
||||||
import './plugin-transcoding'
|
import './plugin-transcoding'
|
||||||
import './plugin-unloading'
|
import './plugin-unloading'
|
||||||
|
import './plugin-websocket'
|
||||||
import './translations'
|
import './translations'
|
||||||
import './video-constants'
|
import './video-constants'
|
||||||
|
|
70
server/tests/plugins/plugin-websocket.ts
Normal file
70
server/tests/plugins/plugin-websocket.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||||
|
|
||||||
|
import WebSocket from 'ws'
|
||||||
|
import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers } from '@shared/server-commands'
|
||||||
|
|
||||||
|
function buildWebSocket (server: PeerTubeServer, path: string) {
|
||||||
|
return new WebSocket('ws://' + server.host + path)
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectErrorOrTimeout (server: PeerTubeServer, path: string, expectedTimeout: number) {
|
||||||
|
return new Promise<void>((res, rej) => {
|
||||||
|
const ws = buildWebSocket(server, path)
|
||||||
|
ws.on('error', () => res())
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => res(), expectedTimeout)
|
||||||
|
|
||||||
|
ws.on('open', () => {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
|
||||||
|
return rej(new Error('Connect did not timeout'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Test plugin websocket', function () {
|
||||||
|
let server: PeerTubeServer
|
||||||
|
const basePaths = [
|
||||||
|
'/plugins/test-websocket/ws/',
|
||||||
|
'/plugins/test-websocket/0.0.1/ws/'
|
||||||
|
]
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
this.timeout(30000)
|
||||||
|
|
||||||
|
server = await createSingleServer(1)
|
||||||
|
await setAccessTokensToServers([ server ])
|
||||||
|
|
||||||
|
await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-websocket') })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should not connect to the websocket without the appropriate path', async function () {
|
||||||
|
const paths = [
|
||||||
|
'/plugins/unknown/ws/',
|
||||||
|
'/plugins/unknown/0.0.1/ws/'
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const path of paths) {
|
||||||
|
await expectErrorOrTimeout(server, path, 1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should not connect to the websocket without the appropriate sub path', async function () {
|
||||||
|
for (const path of basePaths) {
|
||||||
|
await expectErrorOrTimeout(server, path + '/unknown', 1000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should connect to the websocket and receive pong', function (done) {
|
||||||
|
const ws = buildWebSocket(server, basePaths[0])
|
||||||
|
|
||||||
|
ws.on('open', () => ws.send('ping'))
|
||||||
|
ws.on('message', data => {
|
||||||
|
if (data.toString() === 'pong') return done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await cleanupTests([ server ])
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './plugin-library.model'
|
export * from './plugin-library.model'
|
||||||
export * from './register-server-auth.model'
|
export * from './register-server-auth.model'
|
||||||
export * from './register-server-option.model'
|
export * from './register-server-option.model'
|
||||||
|
export * from './register-server-websocket-route.model'
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Response, Router } from 'express'
|
import { Response, Router } from 'express'
|
||||||
|
import { Server } from 'http'
|
||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
import { ActorModel } from '@server/models/actor/actor'
|
import { ActorModel } from '@server/models/actor/actor'
|
||||||
import {
|
import {
|
||||||
|
@ -22,6 +23,7 @@ import {
|
||||||
RegisterServerAuthExternalResult,
|
RegisterServerAuthExternalResult,
|
||||||
RegisterServerAuthPassOptions
|
RegisterServerAuthPassOptions
|
||||||
} from './register-server-auth.model'
|
} from './register-server-auth.model'
|
||||||
|
import { RegisterServerWebSocketRouteOptions } from './register-server-websocket-route.model'
|
||||||
|
|
||||||
export type PeerTubeHelpers = {
|
export type PeerTubeHelpers = {
|
||||||
logger: Logger
|
logger: Logger
|
||||||
|
@ -83,6 +85,9 @@ export type PeerTubeHelpers = {
|
||||||
}
|
}
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
|
// PeerTube >= 5.0
|
||||||
|
getHTTPServer: () => Server
|
||||||
|
|
||||||
getServerActor: () => Promise<ActorModel>
|
getServerActor: () => Promise<ActorModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +102,8 @@ export type PeerTubeHelpers = {
|
||||||
|
|
||||||
// PeerTube >= 3.2
|
// PeerTube >= 3.2
|
||||||
getBaseRouterRoute: () => string
|
getBaseRouterRoute: () => string
|
||||||
|
// PeerTube >= 5.0
|
||||||
|
getBaseWebSocketRoute: () => string
|
||||||
|
|
||||||
// PeerTube >= 3.2
|
// PeerTube >= 3.2
|
||||||
getDataDirectoryPath: () => string
|
getDataDirectoryPath: () => string
|
||||||
|
@ -140,5 +147,12 @@ export type RegisterServerOptions = {
|
||||||
// * /plugins/:pluginName/router/...
|
// * /plugins/:pluginName/router/...
|
||||||
getRouter(): Router
|
getRouter(): Router
|
||||||
|
|
||||||
|
// PeerTube >= 5.0
|
||||||
|
// Register WebSocket route
|
||||||
|
// Base routes of the WebSocket router are
|
||||||
|
// * /plugins/:pluginName/:pluginVersion/ws/...
|
||||||
|
// * /plugins/:pluginName/ws/...
|
||||||
|
registerWebSocketRoute: (options: RegisterServerWebSocketRouteOptions) => void
|
||||||
|
|
||||||
peertubeHelpers: PeerTubeHelpers
|
peertubeHelpers: PeerTubeHelpers
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { IncomingMessage } from 'http'
|
||||||
|
import { Duplex } from 'stream'
|
||||||
|
|
||||||
|
export type RegisterServerWebSocketRouteOptions = {
|
||||||
|
route: string
|
||||||
|
|
||||||
|
handler: (request: IncomingMessage, socket: Duplex, head: Buffer) => any
|
||||||
|
}
|
|
@ -12,6 +12,7 @@
|
||||||
- [Storage](#storage)
|
- [Storage](#storage)
|
||||||
- [Update video constants](#update-video-constants)
|
- [Update video constants](#update-video-constants)
|
||||||
- [Add custom routes](#add-custom-routes)
|
- [Add custom routes](#add-custom-routes)
|
||||||
|
- [Add custom WebSocket handlers](#add-custom-websocket-handlers)
|
||||||
- [Add external auth methods](#add-external-auth-methods)
|
- [Add external auth methods](#add-external-auth-methods)
|
||||||
- [Add new transcoding profiles](#add-new-transcoding-profiles)
|
- [Add new transcoding profiles](#add-new-transcoding-profiles)
|
||||||
- [Server helpers](#server-helpers)
|
- [Server helpers](#server-helpers)
|
||||||
|
@ -317,6 +318,41 @@ The `ping` route can be accessed using:
|
||||||
* Or `/plugins/:pluginName/router/ping`
|
* Or `/plugins/:pluginName/router/ping`
|
||||||
|
|
||||||
|
|
||||||
|
#### Add custom WebSocket handlers
|
||||||
|
|
||||||
|
You can create custom WebSocket servers (like [ws](https://github.com/websockets/ws) for example) using `registerWebSocketRoute`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function register ({
|
||||||
|
registerWebSocketRoute,
|
||||||
|
peertubeHelpers
|
||||||
|
}) {
|
||||||
|
const wss = new WebSocketServer({ noServer: true })
|
||||||
|
|
||||||
|
wss.on('connection', function connection(ws) {
|
||||||
|
peertubeHelpers.logger.info('WebSocket connected!')
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
ws.send('WebSocket message sent by server');
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
registerWebSocketRoute({
|
||||||
|
route: '/my-websocket-route',
|
||||||
|
|
||||||
|
handler: (request, socket, head) => {
|
||||||
|
wss.handleUpgrade(request, socket, head, ws => {
|
||||||
|
wss.emit('connection', ws, request)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `my-websocket-route` route can be accessed using:
|
||||||
|
* `/plugins/:pluginName/:pluginVersion/ws/my-websocket-route`
|
||||||
|
* Or `/plugins/:pluginName/ws/my-websocket-route`
|
||||||
|
|
||||||
#### Add external auth methods
|
#### Add external auth methods
|
||||||
|
|
||||||
If you want to add a classic username/email and password auth method (like [LDAP](https://framagit.org/framasoft/peertube/official-plugins/-/tree/master/peertube-plugin-auth-ldap) for example):
|
If you want to add a classic username/email and password auth method (like [LDAP](https://framagit.org/framasoft/peertube/official-plugins/-/tree/master/peertube-plugin-auth-ldap) for example):
|
||||||
|
|
|
@ -132,6 +132,11 @@ server {
|
||||||
try_files /dev/null @api_websocket;
|
try_files /dev/null @api_websocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Plugin websocket routes
|
||||||
|
location ~ ^/plugins/[^/]+(/[^/]+)?/ws/ {
|
||||||
|
try_files /dev/null @api_websocket;
|
||||||
|
}
|
||||||
|
|
||||||
##
|
##
|
||||||
# Performance optimizations
|
# Performance optimizations
|
||||||
# For extra performance please refer to https://github.com/denji/nginx-tuning
|
# For extra performance please refer to https://github.com/denji/nginx-tuning
|
||||||
|
|
Loading…
Reference in a new issue