X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Fplugins%2Fregister-helpers.ts;h=f5b5733702105ad1a53d0cf029c61deb8b5ccf20;hb=428ccb8b7a44ce60cabb7401a5464cf5fcbd4dba;hp=4c0935a05b76a9c3e9685148ae1876eee056edfb;hpb=1b05d82d861f42c27766e9f24d8d55e68b0cf098;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/plugins/register-helpers.ts b/server/lib/plugins/register-helpers.ts index 4c0935a05..f5b573370 100644 --- a/server/lib/plugins/register-helpers.ts +++ b/server/lib/plugins/register-helpers.ts @@ -1,180 +1,448 @@ -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 * as express from 'express' import { logger } from '@server/helpers/logger' - -type AlterableVideoConstant = 'language' | 'licence' | 'category' +import { + VIDEO_CATEGORIES, + VIDEO_LANGUAGES, + VIDEO_LICENCES, + VIDEO_PLAYLIST_PRIVACIES, + VIDEO_PRIVACIES +} from '@server/initializers/constants' +import { onExternalUserAuthenticated } from '@server/lib/auth/external-auth' +import { PluginModel } from '@server/models/server/plugin' +import { + RegisterServerAuthExternalOptions, + RegisterServerAuthExternalResult, + RegisterServerAuthPassOptions, + RegisterServerExternalAuthenticatedResult, + RegisterServerOptions +} from '@server/types/plugins' +import { + EncoderOptionsBuilder, + PluginPlaylistPrivacyManager, + PluginSettingsManager, + PluginStorageManager, + PluginVideoCategoryManager, + PluginVideoLanguageManager, + PluginVideoLicenceManager, + PluginVideoPrivacyManager, + RegisterServerHookOptions, + RegisterServerSettingOptions, + serverHookObject +} from '@shared/models' +import { VideoTranscodingProfilesManager } from '../transcoding/video-transcoding-profiles' +import { buildPluginHelpers } from './plugin-helpers-builder' + +type AlterableVideoConstant = 'language' | 'licence' | 'category' | 'privacy' | 'playlistPrivacy' 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 }[] - } + added: { key: number | string, label: string }[] + deleted: { key: number | string, label: string }[] } } -const updatedVideoConstants: UpdatedVideoConstant = { - language: {}, - licence: {}, - category: {} -} +export class RegisterHelpers { + private readonly updatedVideoConstants: UpdatedVideoConstant = { + playlistPrivacy: { added: [], deleted: [] }, + privacy: { added: [], deleted: [] }, + language: { added: [], deleted: [] }, + licence: { added: [], deleted: [] }, + category: { added: [], deleted: [] } + } + + 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: ((settings: any) => Promise)[] = [] + + private readonly router: express.Router + + constructor ( + private readonly npmName: string, + private readonly plugin: PluginModel, + private readonly onHookAdded: (options: RegisterServerHookOptions) => void + ) { + this.router = express.Router() + } + + buildRegisterHelpers (): RegisterServerOptions { + const registerHook = this.buildRegisterHook() + const registerSetting = this.buildRegisterSetting() + + const getRouter = this.buildGetRouter() + + const settingsManager = this.buildSettingsManager() + const storageManager = this.buildStorageManager() -function buildRegisterHelpers (npmName: string, plugin: PluginModel): Omit { - const settingsManager = buildSettingsManager(plugin) - const storageManager = buildStorageManager(plugin) + const videoLanguageManager = this.buildVideoLanguageManager() - const videoLanguageManager = buildVideoLanguageManager(npmName) + const videoLicenceManager = this.buildVideoLicenceManager() + const videoCategoryManager = this.buildVideoCategoryManager() - const videoCategoryManager = buildVideoCategoryManager(npmName) - const videoLicenceManager = buildVideoLicenceManager(npmName) + const videoPrivacyManager = this.buildVideoPrivacyManager() + const playlistPrivacyManager = this.buildPlaylistPrivacyManager() - const peertubeHelpers = buildPluginHelpers(npmName) + const transcodingManager = this.buildTranscodingManager() - return { - settingsManager, - storageManager, - videoLanguageManager, - videoCategoryManager, - videoLicenceManager, - peertubeHelpers + const registerIdAndPassAuth = this.buildRegisterIdAndPassAuth() + const registerExternalAuth = this.buildRegisterExternalAuth() + const unregisterIdAndPassAuth = this.buildUnregisterIdAndPassAuth() + const unregisterExternalAuth = this.buildUnregisterExternalAuth() + + const peertubeHelpers = buildPluginHelpers(this.plugin, this.npmName) + + return { + registerHook, + registerSetting, + + getRouter, + + settingsManager, + storageManager, + + videoLanguageManager, + videoCategoryManager, + videoLicenceManager, + + videoPrivacyManager, + playlistPrivacyManager, + + transcodingManager, + + registerIdAndPassAuth, + registerExternalAuth, + unregisterIdAndPassAuth, + unregisterExternalAuth, + + peertubeHelpers + } } -} -function reinitVideoConstants (npmName: string) { - const hash = { - language: VIDEO_LANGUAGES, - licence: VIDEO_LICENCES, - category: VIDEO_CATEGORIES + reinitVideoConstants (npmName: string) { + const hash = { + language: VIDEO_LANGUAGES, + licence: VIDEO_LICENCES, + category: VIDEO_CATEGORIES, + privacy: VIDEO_PRIVACIES, + playlistPrivacy: VIDEO_PLAYLIST_PRIVACIES + } + const types: AlterableVideoConstant[] = [ 'language', 'licence', 'category', 'privacy', 'playlistPrivacy' ] + + for (const type of types) { + const updatedConstants = this.updatedVideoConstants[type][npmName] + if (!updatedConstants) continue + + for (const added of updatedConstants.added) { + delete hash[type][added.key] + } + + for (const deleted of updatedConstants.deleted) { + hash[type][deleted.key] = deleted.label + } + + delete this.updatedVideoConstants[type][npmName] + } } - const types: AlterableVideoConstant[] = [ 'language', 'licence', 'category' ] - for (const type of types) { - const updatedConstants = updatedVideoConstants[type][npmName] - if (!updatedConstants) continue + reinitTranscodingProfilesAndEncoders (npmName: string) { + const profiles = this.transcodingProfiles[npmName] + if (Array.isArray(profiles)) { + for (const profile of profiles) { + VideoTranscodingProfilesManager.Instance.removeProfile(profile) + } + } - for (const added of updatedConstants.added) { - delete hash[type][added.key] + 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) + } } + } + + getSettings () { + return this.settings + } + + getRouter () { + return this.router + } + + getIdAndPassAuths () { + return this.idAndPassAuths + } - for (const deleted of updatedConstants.deleted) { - hash[type][deleted.key] = deleted.label + getExternalAuths () { + return this.externalAuths + } + + getOnSettingsChangedCallbacks () { + return this.onSettingsChangeCallbacks + } + + private buildGetRouter () { + return () => this.router + } + + private buildRegisterSetting () { + return (options: RegisterServerSettingOptions) => { + this.settings.push(options) } + } + + private buildRegisterHook () { + return (options: RegisterServerHookOptions) => { + if (serverHookObject[options.target] !== true) { + logger.warn('Unknown hook %s of plugin %s. Skipping.', options.target, this.npmName) + return + } - delete updatedVideoConstants[type][npmName] + return this.onHookAdded(options) + } } -} -export { - buildRegisterHelpers, - reinitVideoConstants -} + 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 + } + + this.idAndPassAuths.push(options) + } + } -// --------------------------------------------------------------------------- + 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 buildSettingsManager (plugin: PluginModel): PluginSettingsManager { - return { - getSetting: (name: string) => PluginModel.getSetting(plugin.name, plugin.type, name), + private buildUnregisterExternalAuth () { + return (authName: string) => { + this.externalAuths = this.externalAuths.filter(a => a.authName !== authName) + } + } - setSetting: (name: string, value: string) => PluginModel.setSetting(plugin.name, plugin.type, name, value) + private buildUnregisterIdAndPassAuth () { + return (authName: string) => { + this.idAndPassAuths = this.idAndPassAuths.filter(a => a.authName !== authName) + } } -} -function buildStorageManager (plugin: PluginModel): PluginStorageManager { - return { - getData: (key: string) => PluginModel.getData(plugin.name, plugin.type, key), + private buildSettingsManager (): PluginSettingsManager { + return { + getSetting: (name: string) => PluginModel.getSetting(this.plugin.name, this.plugin.type, name, this.settings), - storeData: (key: string, data: any) => PluginModel.storeData(plugin.name, plugin.type, key, data) + getSettings: (names: string[]) => PluginModel.getSettings(this.plugin.name, this.plugin.type, names, this.settings), + + setSetting: (name: string, value: string) => PluginModel.setSetting(this.plugin.name, this.plugin.type, name, value), + + onSettingsChange: (cb: (settings: any) => Promise) => this.onSettingsChangeCallbacks.push(cb) + } } -} -function buildVideoLanguageManager (npmName: string): PluginVideoLanguageManager { - return { - addLanguage: (key: string, label: string) => addConstant({ npmName, type: 'language', obj: VIDEO_LANGUAGES, key, label }), + private buildStorageManager (): PluginStorageManager { + return { + getData: (key: string) => PluginModel.getData(this.plugin.name, this.plugin.type, key), - deleteLanguage: (key: string) => deleteConstant({ npmName, type: 'language', obj: VIDEO_LANGUAGES, key }) + storeData: (key: string, data: any) => PluginModel.storeData(this.plugin.name, this.plugin.type, key, data) + } } -} -function buildVideoCategoryManager (npmName: string): PluginVideoCategoryManager { - return { - addCategory: (key: number, label: string) => { - return addConstant({ npmName, type: 'category', obj: VIDEO_CATEGORIES, key, label }) - }, + private buildVideoLanguageManager (): PluginVideoLanguageManager { + return { + addLanguage: (key: string, label: string) => { + return this.addConstant({ npmName: this.npmName, type: 'language', obj: VIDEO_LANGUAGES, key, label }) + }, - deleteCategory: (key: number) => { - return deleteConstant({ npmName, type: 'category', obj: VIDEO_CATEGORIES, key }) + deleteLanguage: (key: string) => { + return this.deleteConstant({ npmName: this.npmName, type: 'language', obj: VIDEO_LANGUAGES, key }) + } } } -} -function buildVideoLicenceManager (npmName: string): PluginVideoLicenceManager { - return { - addLicence: (key: number, label: string) => { - return addConstant({ npmName, type: 'licence', obj: VIDEO_LICENCES, key, label }) - }, + private buildVideoCategoryManager (): PluginVideoCategoryManager { + return { + addCategory: (key: number, label: string) => { + return this.addConstant({ npmName: this.npmName, type: 'category', obj: VIDEO_CATEGORIES, key, label }) + }, - deleteLicence: (key: number) => { - return deleteConstant({ npmName, type: 'licence', obj: VIDEO_LICENCES, key }) + deleteCategory: (key: number) => { + return this.deleteConstant({ npmName: this.npmName, type: 'category', obj: VIDEO_CATEGORIES, key }) + } } } -} -function addConstant (parameters: { - npmName: string - type: AlterableVideoConstant - obj: VideoConstant - key: T - label: string -}) { - const { npmName, type, obj, key, label } = parameters + private buildVideoPrivacyManager (): PluginVideoPrivacyManager { + return { + deletePrivacy: (key: number) => { + return this.deleteConstant({ npmName: this.npmName, type: 'privacy', obj: VIDEO_PRIVACIES, key }) + } + } + } - if (obj[key]) { - logger.warn('Cannot add %s %s by plugin %s: key already exists.', type, npmName, key) - return false + private buildPlaylistPrivacyManager (): PluginPlaylistPrivacyManager { + return { + deletePlaylistPrivacy: (key: number) => { + return this.deleteConstant({ npmName: this.npmName, type: 'playlistPrivacy', obj: VIDEO_PLAYLIST_PRIVACIES, key }) + } + } } - if (!updatedVideoConstants[type][npmName]) { - updatedVideoConstants[type][npmName] = { - added: [], - deleted: [] + private buildVideoLicenceManager (): PluginVideoLicenceManager { + return { + addLicence: (key: number, label: string) => { + return this.addConstant({ npmName: this.npmName, type: 'licence', obj: VIDEO_LICENCES, key, label }) + }, + + deleteLicence: (key: number) => { + return this.deleteConstant({ npmName: this.npmName, type: 'licence', obj: VIDEO_LICENCES, key }) + } } } - updatedVideoConstants[type][npmName].added.push({ key, label }) - obj[key] = label + private addConstant (parameters: { + npmName: string + type: AlterableVideoConstant + obj: VideoConstant + key: T + label: string + }) { + const { npmName, type, obj, key, label } = parameters + + if (obj[key]) { + logger.warn('Cannot add %s %s by plugin %s: key already exists.', type, npmName, key) + return false + } - return true -} + if (!this.updatedVideoConstants[type][npmName]) { + this.updatedVideoConstants[type][npmName] = { + added: [], + deleted: [] + } + } -function deleteConstant (parameters: { - npmName: string - type: AlterableVideoConstant - obj: VideoConstant - key: T -}) { - const { npmName, type, obj, key } = parameters + this.updatedVideoConstants[type][npmName].added.push({ key, label }) + obj[key] = label - if (!obj[key]) { - logger.warn('Cannot delete %s %s by plugin %s: key does not exist.', type, npmName, key) - return false + return true } - if (!updatedVideoConstants[type][npmName]) { - updatedVideoConstants[type][npmName] = { - added: [], - deleted: [] + private deleteConstant (parameters: { + npmName: string + type: AlterableVideoConstant + obj: VideoConstant + key: T + }) { + const { npmName, type, obj, key } = parameters + + if (!obj[key]) { + logger.warn('Cannot delete %s %s by plugin %s: key does not exist.', type, npmName, key) + return false + } + + if (!this.updatedVideoConstants[type][npmName]) { + this.updatedVideoConstants[type][npmName] = { + added: [], + deleted: [] + } } + + this.updatedVideoConstants[type][npmName].deleted.push({ key, label: obj[key] }) + delete obj[key] + + return true } - updatedVideoConstants[type][npmName].deleted.push({ key, label: obj[key] }) - delete obj[key] + private buildTranscodingManager () { + const self = this + + 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 }) - return true + return true + } + + function addEncoderPriority (type: 'live' | 'vod', streamType: 'audio' | 'video', encoder: string, priority: number) { + VideoTranscodingProfilesManager.Instance.addEncoderPriority(type, streamType, encoder, priority) + + if (!self.transcodingEncoders[self.npmName]) self.transcodingEncoders[self.npmName] = [] + self.transcodingEncoders[self.npmName].push({ type, streamType, encoder, priority }) + } + + return { + addLiveProfile (encoder: string, profile: string, builder: EncoderOptionsBuilder) { + return addProfile('live', encoder, profile, builder) + }, + + addVODProfile (encoder: string, profile: string, builder: EncoderOptionsBuilder) { + return addProfile('vod', encoder, profile, builder) + }, + + addLiveEncoderPriority (streamType: 'audio' | 'video', encoder: string, priority: number) { + return addEncoderPriority('live', streamType, encoder, priority) + }, + + addVODEncoderPriority (streamType: 'audio' | 'video', encoder: string, priority: number) { + return addEncoderPriority('vod', streamType, encoder, priority) + }, + + removeAllProfilesAndEncoderPriorities () { + return self.reinitTranscodingProfilesAndEncoders(self.npmName) + } + } + } }