X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Fplugins%2Fregister-helpers.ts;h=1aaef36068486a892208a37db43b7660d1aa01a2;hb=f50bff17f5b69c576960360857e25224cea13c0a;hp=58bc96f04429cba90303b35c314392c3ef428305;hpb=bc0d801bb7a0cc503c1637f4a07bb51d68d85608;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/plugins/register-helpers.ts b/server/lib/plugins/register-helpers.ts index 58bc96f04..1aaef3606 100644 --- a/server/lib/plugins/register-helpers.ts +++ b/server/lib/plugins/register-helpers.ts @@ -1,180 +1,340 @@ -import { PluginSettingsManager } from '@shared/models/plugins/plugin-settings-manager.model' -import { PluginModel } from '@server/models/server/plugin' -import { PluginStorageManager } from '@shared/models/plugins/plugin-storage-manager.model' -import { PluginVideoLanguageManager } from '@shared/models/plugins/plugin-video-language-manager.model' -import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES } from '@server/initializers/constants' -import { PluginVideoLicenceManager } from '@shared/models/plugins/plugin-video-licence-manager.model' -import { PluginVideoCategoryManager } from '@shared/models/plugins/plugin-video-category-manager.model' -import { RegisterServerOptions } from '@server/typings/plugins' -import { buildPluginHelpers } from './plugin-helpers' +import express from 'express' +import { Server } from 'http' import { logger } from '@server/helpers/logger' +import { onExternalUserAuthenticated } from '@server/lib/auth/external-auth' +import { VideoConstantManagerFactory } from '@server/lib/plugins/video-constant-manager-factory' +import { PluginModel } from '@server/models/server/plugin' +import { + RegisterServerAuthExternalOptions, + RegisterServerAuthExternalResult, + RegisterServerAuthPassOptions, + RegisterServerExternalAuthenticatedResult, + RegisterServerOptions, + RegisterServerWebSocketRouteOptions +} from '@server/types/plugins' +import { + EncoderOptionsBuilder, + PluginSettingsManager, + PluginStorageManager, + RegisterServerHookOptions, + RegisterServerSettingOptions, + serverHookObject, + SettingsChangeCallback, + VideoPlaylistPrivacy, + VideoPrivacy +} from '@shared/models' +import { VideoTranscodingProfilesManager } from '../transcoding/default-transcoding-profiles' +import { buildPluginHelpers } from './plugin-helpers-builder' + +export class RegisterHelpers { + private readonly transcodingProfiles: { + [ npmName: string ]: { + type: 'vod' | 'live' + encoder: string + profile: string + }[] + } = {} + + private readonly transcodingEncoders: { + [ npmName: string ]: { + type: 'vod' | 'live' + streamType: 'audio' | 'video' + encoder: string + priority: number + }[] + } = {} + + private readonly settings: RegisterServerSettingOptions[] = [] + + private idAndPassAuths: RegisterServerAuthPassOptions[] = [] + private externalAuths: RegisterServerAuthExternalOptions[] = [] + + private readonly onSettingsChangeCallbacks: SettingsChangeCallback[] = [] + + private readonly webSocketRoutes: RegisterServerWebSocketRouteOptions[] = [] + + private readonly router: express.Router + private readonly videoConstantManagerFactory: VideoConstantManagerFactory + + constructor ( + private readonly npmName: string, + private readonly plugin: PluginModel, + private readonly server: Server, + private readonly onHookAdded: (options: RegisterServerHookOptions) => void + ) { + this.router = express.Router() + this.videoConstantManagerFactory = new VideoConstantManagerFactory(this.npmName) + } -type AlterableVideoConstant = 'language' | 'licence' | 'category' -type VideoConstant = { [key in number | string]: string } -type UpdatedVideoConstant = { - [name in AlterableVideoConstant]: { - [npmName: string]: { - added: { key: number | string, label: string }[] - deleted: { key: number | string, label: string }[] + buildRegisterHelpers (): RegisterServerOptions { + const registerHook = this.buildRegisterHook() + const registerSetting = this.buildRegisterSetting() + + const getRouter = this.buildGetRouter() + const registerWebSocketRoute = this.buildRegisterWebSocketRoute() + + const settingsManager = this.buildSettingsManager() + const storageManager = this.buildStorageManager() + + const videoLanguageManager = this.videoConstantManagerFactory.createVideoConstantManager('language') + + const videoLicenceManager = this.videoConstantManagerFactory.createVideoConstantManager('licence') + const videoCategoryManager = this.videoConstantManagerFactory.createVideoConstantManager('category') + + const videoPrivacyManager = this.videoConstantManagerFactory.createVideoConstantManager('privacy') + const playlistPrivacyManager = this.videoConstantManagerFactory.createVideoConstantManager('playlistPrivacy') + + const transcodingManager = this.buildTranscodingManager() + + const registerIdAndPassAuth = this.buildRegisterIdAndPassAuth() + const registerExternalAuth = this.buildRegisterExternalAuth() + const unregisterIdAndPassAuth = this.buildUnregisterIdAndPassAuth() + const unregisterExternalAuth = this.buildUnregisterExternalAuth() + + const peertubeHelpers = buildPluginHelpers(this.server, this.plugin, this.npmName) + + return { + registerHook, + registerSetting, + + getRouter, + registerWebSocketRoute, + + settingsManager, + storageManager, + + videoLanguageManager: { + ...videoLanguageManager, + /** @deprecated use `addConstant` instead **/ + addLanguage: videoLanguageManager.addConstant, + /** @deprecated use `deleteConstant` instead **/ + deleteLanguage: videoLanguageManager.deleteConstant + }, + videoCategoryManager: { + ...videoCategoryManager, + /** @deprecated use `addConstant` instead **/ + addCategory: videoCategoryManager.addConstant, + /** @deprecated use `deleteConstant` instead **/ + deleteCategory: videoCategoryManager.deleteConstant + }, + videoLicenceManager: { + ...videoLicenceManager, + /** @deprecated use `addConstant` instead **/ + addLicence: videoLicenceManager.addConstant, + /** @deprecated use `deleteConstant` instead **/ + deleteLicence: videoLicenceManager.deleteConstant + }, + + videoPrivacyManager: { + ...videoPrivacyManager, + /** @deprecated use `deleteConstant` instead **/ + deletePrivacy: videoPrivacyManager.deleteConstant + }, + playlistPrivacyManager: { + ...playlistPrivacyManager, + /** @deprecated use `deleteConstant` instead **/ + deletePlaylistPrivacy: playlistPrivacyManager.deleteConstant + }, + + transcodingManager, + + registerIdAndPassAuth, + registerExternalAuth, + unregisterIdAndPassAuth, + unregisterExternalAuth, + + peertubeHelpers } } -} -const updatedVideoConstants: UpdatedVideoConstant = { - language: {}, - licence: {}, - category: {} -} + reinitVideoConstants (npmName: string) { + this.videoConstantManagerFactory.resetVideoConstants(npmName) + } -function buildRegisterHelpers (npmName: string, plugin: PluginModel): Omit { - const settingsManager = buildSettingsManager(plugin) - const storageManager = buildStorageManager(plugin) + reinitTranscodingProfilesAndEncoders (npmName: string) { + const profiles = this.transcodingProfiles[npmName] + if (Array.isArray(profiles)) { + for (const profile of profiles) { + VideoTranscodingProfilesManager.Instance.removeProfile(profile) + } + } - const videoLanguageManager = buildVideoLanguageManager(npmName) + const encoders = this.transcodingEncoders[npmName] + if (Array.isArray(encoders)) { + for (const o of encoders) { + VideoTranscodingProfilesManager.Instance.removeEncoderPriority(o.type, o.streamType, o.encoder, o.priority) + } + } + } - const videoCategoryManager = buildVideoCategoryManager(npmName) - const videoLicenceManager = buildVideoLicenceManager(npmName) + getSettings () { + return this.settings + } - const peertubeHelpers = buildPluginHelpers(npmName, plugin) + getRouter () { + return this.router + } - return { - settingsManager, - storageManager, - videoLanguageManager, - videoCategoryManager, - videoLicenceManager, - peertubeHelpers + getIdAndPassAuths () { + return this.idAndPassAuths } -} -function reinitVideoConstants (npmName: string) { - const hash = { - language: VIDEO_LANGUAGES, - licence: VIDEO_LICENCES, - category: VIDEO_CATEGORIES + getExternalAuths () { + return this.externalAuths } - const types: AlterableVideoConstant[] = [ 'language', 'licence', 'category' ] - for (const type of types) { - const updatedConstants = updatedVideoConstants[type][npmName] - if (!updatedConstants) continue + getOnSettingsChangedCallbacks () { + return this.onSettingsChangeCallbacks + } - for (const added of updatedConstants.added) { - delete hash[type][added.key] - } + getWebSocketRoutes () { + return this.webSocketRoutes + } - for (const deleted of updatedConstants.deleted) { - hash[type][deleted.key] = deleted.label + private buildGetRouter () { + return () => this.router + } + + private buildRegisterWebSocketRoute () { + return (options: RegisterServerWebSocketRouteOptions) => { + this.webSocketRoutes.push(options) } + } - delete updatedVideoConstants[type][npmName] + private buildRegisterSetting () { + return (options: RegisterServerSettingOptions) => { + this.settings.push(options) + } } -} -export { - buildRegisterHelpers, - reinitVideoConstants -} + private buildRegisterHook () { + return (options: RegisterServerHookOptions) => { + if (serverHookObject[options.target] !== true) { + logger.warn('Unknown hook %s of plugin %s. Skipping.', options.target, this.npmName) + return + } -// --------------------------------------------------------------------------- + return this.onHookAdded(options) + } + } -function buildSettingsManager (plugin: PluginModel): PluginSettingsManager { - return { - getSetting: (name: string) => PluginModel.getSetting(plugin.name, plugin.type, name), + private buildRegisterIdAndPassAuth () { + return (options: RegisterServerAuthPassOptions) => { + if (!options.authName || typeof options.getWeight !== 'function' || typeof options.login !== 'function') { + logger.error('Cannot register auth plugin %s: authName, getWeight or login are not valid.', this.npmName, { options }) + return + } - setSetting: (name: string, value: string) => PluginModel.setSetting(plugin.name, plugin.type, name, value) + this.idAndPassAuths.push(options) + } } -} - -function buildStorageManager (plugin: PluginModel): PluginStorageManager { - return { - getData: (key: string) => PluginModel.getData(plugin.name, plugin.type, key), - storeData: (key: string, data: any) => PluginModel.storeData(plugin.name, plugin.type, key, data) + private buildRegisterExternalAuth () { + const self = this + + return (options: RegisterServerAuthExternalOptions) => { + if (!options.authName || typeof options.authDisplayName !== 'function' || typeof options.onAuthRequest !== 'function') { + logger.error('Cannot register auth plugin %s: authName, authDisplayName or onAuthRequest are not valid.', this.npmName, { options }) + return + } + + this.externalAuths.push(options) + + return { + userAuthenticated (result: RegisterServerExternalAuthenticatedResult): void { + onExternalUserAuthenticated({ + npmName: self.npmName, + authName: options.authName, + authResult: result + }).catch(err => { + logger.error('Cannot execute onExternalUserAuthenticated.', { npmName: self.npmName, authName: options.authName, err }) + }) + } + } as RegisterServerAuthExternalResult + } } -} -function buildVideoLanguageManager (npmName: string): PluginVideoLanguageManager { - return { - addLanguage: (key: string, label: string) => addConstant({ npmName, type: 'language', obj: VIDEO_LANGUAGES, key, label }), + private buildUnregisterExternalAuth () { + return (authName: string) => { + this.externalAuths = this.externalAuths.filter(a => a.authName !== authName) + } + } - deleteLanguage: (key: string) => deleteConstant({ npmName, type: 'language', obj: VIDEO_LANGUAGES, key }) + private buildUnregisterIdAndPassAuth () { + return (authName: string) => { + this.idAndPassAuths = this.idAndPassAuths.filter(a => a.authName !== authName) + } } -} -function buildVideoCategoryManager (npmName: string): PluginVideoCategoryManager { - return { - addCategory: (key: number, label: string) => { - return addConstant({ npmName, type: 'category', obj: VIDEO_CATEGORIES, key, label }) - }, + private buildSettingsManager (): PluginSettingsManager { + return { + getSetting: (name: string) => PluginModel.getSetting(this.plugin.name, this.plugin.type, name, this.settings), + + getSettings: (names: string[]) => PluginModel.getSettings(this.plugin.name, this.plugin.type, names, this.settings), - deleteCategory: (key: number) => { - return deleteConstant({ npmName, type: 'category', obj: VIDEO_CATEGORIES, key }) + setSetting: (name: string, value: string) => PluginModel.setSetting(this.plugin.name, this.plugin.type, name, value), + + onSettingsChange: (cb: SettingsChangeCallback) => this.onSettingsChangeCallbacks.push(cb) } } -} -function buildVideoLicenceManager (npmName: string): PluginVideoLicenceManager { - return { - addLicence: (key: number, label: string) => { - return addConstant({ npmName, type: 'licence', obj: VIDEO_LICENCES, key, label }) - }, + private buildStorageManager (): PluginStorageManager { + return { + getData: (key: string) => PluginModel.getData(this.plugin.name, this.plugin.type, key), - deleteLicence: (key: number) => { - return deleteConstant({ npmName, type: 'licence', obj: VIDEO_LICENCES, key }) + storeData: (key: string, data: any) => PluginModel.storeData(this.plugin.name, this.plugin.type, key, data) } } -} -function addConstant (parameters: { - npmName: string - type: AlterableVideoConstant - obj: VideoConstant - key: T - label: string -}) { - const { npmName, type, obj, key, label } = parameters + private buildTranscodingManager () { + const self = this - if (obj[key]) { - logger.warn('Cannot add %s %s by plugin %s: key already exists.', type, npmName, key) - return false - } + function addProfile (type: 'live' | 'vod', encoder: string, profile: string, builder: EncoderOptionsBuilder) { + if (profile === 'default') { + logger.error('A plugin cannot add a default live transcoding profile') + return false + } + + VideoTranscodingProfilesManager.Instance.addProfile({ + type, + encoder, + profile, + builder + }) + + if (!self.transcodingProfiles[self.npmName]) self.transcodingProfiles[self.npmName] = [] + self.transcodingProfiles[self.npmName].push({ type, encoder, profile }) - if (!updatedVideoConstants[type][npmName]) { - updatedVideoConstants[type][npmName] = { - added: [], - deleted: [] + return true } - } - updatedVideoConstants[type][npmName].added.push({ key, label }) - obj[key] = label + function addEncoderPriority (type: 'live' | 'vod', streamType: 'audio' | 'video', encoder: string, priority: number) { + VideoTranscodingProfilesManager.Instance.addEncoderPriority(type, streamType, encoder, priority) - return true -} + if (!self.transcodingEncoders[self.npmName]) self.transcodingEncoders[self.npmName] = [] + self.transcodingEncoders[self.npmName].push({ type, streamType, encoder, priority }) + } -function deleteConstant (parameters: { - npmName: string - type: AlterableVideoConstant - obj: VideoConstant - key: T -}) { - const { npmName, type, obj, key } = parameters + return { + addLiveProfile (encoder: string, profile: string, builder: EncoderOptionsBuilder) { + return addProfile('live', encoder, profile, builder) + }, - if (!obj[key]) { - logger.warn('Cannot delete %s %s by plugin %s: key does not exist.', type, npmName, key) - return false - } + addVODProfile (encoder: string, profile: string, builder: EncoderOptionsBuilder) { + return addProfile('vod', encoder, profile, builder) + }, - if (!updatedVideoConstants[type][npmName]) { - updatedVideoConstants[type][npmName] = { - added: [], - deleted: [] - } - } + addLiveEncoderPriority (streamType: 'audio' | 'video', encoder: string, priority: number) { + return addEncoderPriority('live', streamType, encoder, priority) + }, - updatedVideoConstants[type][npmName].deleted.push({ key, label: obj[key] }) - delete obj[key] + addVODEncoderPriority (streamType: 'audio' | 'video', encoder: string, priority: number) { + return addEncoderPriority('vod', streamType, encoder, priority) + }, - return true + removeAllProfilesAndEncoderPriorities () { + return self.reinitTranscodingProfilesAndEncoders(self.npmName) + } + } + } }