Refactoring server code:

* Split server code in several libs
* improve server/peertube.d.ts.
This commit is contained in:
John Livingston 2021-04-08 02:43:13 +02:00
parent 5d8102c64d
commit 490d6f18c3
7 changed files with 528 additions and 204 deletions

220
package-lock.json generated
View File

@ -30,6 +30,17 @@
"js-tokens": "^4.0.0"
}
},
"@dabh/diagnostics": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz",
"integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==",
"dev": true,
"requires": {
"colorspace": "1.1.x",
"enabled": "2.0.x",
"kuler": "^2.0.0"
}
},
"@eslint/eslintrc": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
@ -218,6 +229,15 @@
"@types/node": "*"
}
},
"@types/winston": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz",
"integrity": "sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw==",
"dev": true,
"requires": {
"winston": "*"
}
},
"@typescript-eslint/eslint-plugin": {
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz",
@ -804,6 +824,12 @@
"integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
"dev": true
},
"async": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==",
"dev": true
},
"async-each": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
@ -1269,6 +1295,16 @@
"object-visit": "^1.0.0"
}
},
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
"dev": true,
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -1284,6 +1320,32 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"color-string": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz",
"integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==",
"dev": true,
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
"dev": true
},
"colorspace": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz",
"integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==",
"dev": true,
"requires": {
"color": "3.0.x",
"text-hex": "1.0.x"
}
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@ -1703,6 +1765,12 @@
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
"dev": true
},
"enabled": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
"dev": true
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@ -2538,6 +2606,12 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"fast-safe-stringify": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
"integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==",
"dev": true
},
"fastq": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
@ -2547,6 +2621,12 @@
"reusify": "^1.0.4"
}
},
"fecha": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz",
"integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==",
"dev": true
},
"figgy-pudding": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
@ -2654,6 +2734,12 @@
"readable-stream": "^2.3.6"
}
},
"fn.name": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
"dev": true
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@ -3314,6 +3400,12 @@
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true
},
"kuler": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
"dev": true
},
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
@ -3386,6 +3478,27 @@
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"dev": true
},
"logform": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz",
"integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==",
"dev": true,
"requires": {
"colors": "^1.2.1",
"fast-safe-stringify": "^2.0.4",
"fecha": "^4.2.0",
"ms": "^2.1.1",
"triple-beam": "^1.3.0"
},
"dependencies": {
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
}
}
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@ -3897,6 +4010,15 @@
"wrappy": "1"
}
},
"one-time": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
"dev": true,
"requires": {
"fn.name": "1.x.x"
}
},
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@ -4617,6 +4739,23 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"dev": true,
"requires": {
"is-arrayish": "^0.3.1"
},
"dependencies": {
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"dev": true
}
}
},
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@ -4882,6 +5021,12 @@
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
"dev": true
},
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
"dev": true
},
"static-extend": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
@ -5211,6 +5356,12 @@
"worker-farm": "^1.7.0"
}
},
"text-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
"dev": true
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -5284,6 +5435,12 @@
"repeat-string": "^1.6.1"
}
},
"triple-beam": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==",
"dev": true
},
"ts-loader": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.1.0.tgz",
@ -5877,6 +6034,69 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"winston": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz",
"integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==",
"dev": true,
"requires": {
"@dabh/diagnostics": "^2.0.2",
"async": "^3.1.0",
"is-stream": "^2.0.0",
"logform": "^2.2.0",
"one-time": "^1.0.0",
"readable-stream": "^3.4.0",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.4.0"
},
"dependencies": {
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
"dev": true
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"winston-transport": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz",
"integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==",
"dev": true,
"requires": {
"readable-stream": "^2.3.7",
"triple-beam": "^1.2.0"
},
"dependencies": {
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
}
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",

View File

@ -27,6 +27,7 @@
"@tsconfig/node12": "^1.0.7",
"@types/express": "^4.17.11",
"@types/node": "^14.14.37",
"@types/winston": "^2.4.4",
"@typescript-eslint/eslint-plugin": "^4.21.0",
"@typescript-eslint/parser": "^4.21.0",
"converse.js": "^7.0.5",

73
server/lib/routers.ts Normal file
View File

@ -0,0 +1,73 @@
import * as path from 'path'
import type { NextFunction, Request, Response } from 'express'
const fs = require('fs').promises
type InitRoutersOptions = Pick<RegisterServerOptions, 'settingsManager' | 'getRouter' | 'peertubeHelpers'>
export async function initRouters ({
settingsManager,
getRouter,
peertubeHelpers
}: InitRoutersOptions): Promise<void> {
const converseJSIndex = await fs.readFile(path.resolve(__dirname, '../conversejs/index.html'))
const router = getRouter()
router.get('/ping', (req: Request, res: Response) => res.json({ message: 'pong' }))
router.get('/webchat', async (req: Request, res: Response, next: NextFunction) => {
try {
const settings = await settingsManager.getSettings([
'chat-use-builtin', 'chat-room', 'chat-server',
'chat-bosh-uri', 'chat-ws-uri'
])
if (!settings['chat-use-builtin']) {
throw new Error('Builtin chat disabled.')
}
if (!settings['chat-server']) {
throw new Error('Missing chat-server settings.')
}
if (!settings['chat-room']) {
throw new Error('Missing chat-room settings.')
}
if (!settings['chat-bosh-uri'] && !settings['chat-ws-uri']) {
throw new Error('Missing BOSH or Websocket uri.')
}
// FIXME: with Peertube 3.0.1 the following method is not available...
// When loadByIdOrUUID is available, change the entry point to
// be /webchat/:videoId
// const id = req.param('videoId')
// const video = await peertubeHelpers.videos.loadByIdOrUUID(id)
let url: string = req.query.url as string || ''
if (!url) {
throw new Error('Missing url parameter)')
}
let video = await peertubeHelpers.videos.loadByUrl(url)
if (!video) {
// FIXME: remove this when loadByIdOrUUID will be available...
// This is a dirty Hack for dev environnements...
url = url.replace(/^https:/, 'http:')
video = await peertubeHelpers.videos.loadByUrl(url)
}
if (!video) {
throw new Error('Video not found')
}
let page = '' + (converseJSIndex as string)
// FIXME: Peertube should provide the static folder path. For now:
const staticRelative = '../static'
page = page.replace(/{{BASE_STATIC_URL}}/g, staticRelative)
page = page.replace(/{{JID}}/g, settings['chat-server'] as string)
const room = (settings['chat-room'] as string).replace(/{{VIDEO_UUID}}/g, video.uuid)
page = page.replace(/{{ROOM}}/g, room)
page = page.replace(/{{BOSH_SERVICE_URL}}/g, settings['chat-bosh-uri'] as string)
page = page.replace(/{{WS_SERVICE_URL}}/g, settings['chat-ws-uri'] as string)
res.status(200)
res.type('html')
res.send(page)
} catch (error) {
return next(error)
}
})
}

134
server/lib/settings.ts Normal file
View File

@ -0,0 +1,134 @@
interface InitSettingsOptions {
registerSetting: (options: RegisterServerSettingOptions) => void
}
export function initSettings ({
registerSetting
}: InitSettingsOptions): void {
registerSetting({
name: 'chat-auto-display',
label: 'Automatically open the chat',
type: 'input-checkbox',
default: false,
private: false
})
registerSetting({
name: 'chat-open-blank',
label: 'Show the «open in new window» button',
private: false,
type: 'input-checkbox',
default: false
})
registerSetting({
name: 'chat-only-locals',
label: 'Chats are only available for local videos.',
type: 'input-checkbox',
default: false, // TODO: set to true when peertube has fixed https://github.com/Chocobozzz/PeerTube/issues/3838
private: false
})
registerSetting({
name: 'chat-all-lives',
label: 'Activate chat for all lives',
type: 'input-checkbox',
default: false,
descriptionHTML: 'If checked, a chat will be added to all lives.',
private: false
})
registerSetting({
name: 'chat-all-non-lives',
label: 'Activate chat for all non-lives',
type: 'input-checkbox',
default: false,
descriptionHTML: 'If checked, a chat will be added to all video that are not lives.',
private: false
})
registerSetting({
name: 'chat-videos-list',
label: 'Activate chat for specific videos',
type: 'input-textarea',
default: '',
descriptionHTML: 'Videos UUIDs for which we want a chat. ' +
'Can be non-live videos. One per line. <br />' +
'You can add comments: everything after the # character will be stripped off, and empty lines ignored.<br />' +
'Don\'t add private videos, the UUIDs will be send to frontend.',
private: false
})
registerSetting({
name: 'chat-use-builtin',
label: 'Use builtin ConverseJS',
type: 'input-checkbox',
default: false, // TODO: set to true when peertube has fixed https://github.com/Chocobozzz/PeerTube/issues/3838
private: false,
descriptionHTML: 'If checked, use a builtin ConverseJS iframe.<br>' +
'You still have to configure an external XMPP service. Please see the ' +
'<a href="https://github.com/JohnXLivingston/peertube-plugin-livechat" target="_blank">documentation<a>.<br>' +
'If you have no running webchat service, you can follow this ' +
// eslint-disable-next-line max-len
'<a href="https://github.com/JohnXLivingston/peertube-plugin-livechat/blob/main/documentation/tutorials/prosody.md" target="blank_">tutorial</a>.'
})
registerSetting({
name: 'chat-server',
label: 'Builtin webchat: XMPP service server',
type: 'input',
default: '',
descriptionHTML: 'When using the built-in converseJS webchat:<br>' +
'Your XMPP server. Without any scheme. Example : peertube.im.your_domain.',
private: true
})
registerSetting({
name: 'chat-room',
label: 'Builtin webchat: XMPP room template',
type: 'input',
default: '',
descriptionHTML: 'When using the built-in converseJS webchat:<br>' +
'Your XMPP room. You can use the placeholder {{VIDEO_UUID}} to add the video UUID.' +
'Without this placeholder, all videos will point to the same chat room.<br>' +
'Example: public@room.peertube.im.your_domain<br>' +
'Example: public_{{VIDEO_UUID}}@room.peertube.im.your_domain',
private: true
})
registerSetting({
name: 'chat-bosh-uri',
label: 'Builtin webchat: BOSH uri',
type: 'input',
default: '',
descriptionHTML: 'When using the built-in converseJS webchat:<br>' +
'URI of the external BOSH server. Please make sure it accept cross origin request from your domain.<br>' +
'You must at least have a BOSH or a Websocket uri.',
private: true
})
registerSetting({
name: 'chat-ws-uri',
label: 'Builtin webchat: WS uri',
type: 'input',
default: '',
descriptionHTML: 'When using the built-in converseJS webchat:<br>' +
'URI of the external WS server. Please make sure it accept cross origin request from your domain.<br>' +
'You must at least have a BOSH or a Websocket uri.',
private: true
})
registerSetting({
name: 'chat-uri',
label: 'Webchat url',
type: 'input',
default: '',
descriptionHTML: '<b>If you dont want to use the builtin ConverseJS webchat:</b><br>' +
'Put here your webchat url. An iframe will be created pointing to this url. ' +
'The placeholder {{VIDEO_UUID}} will be replace by the video UUID if present. ' +
'Example : https://my_domain/conversejs.html?room=video_{{VIDEO_UUID}}.<br>' +
'If this field is empty, it will use the builtin ConverseJS webchat.',
private: false
})
registerSetting({
name: 'chat-style',
label: 'Webchat iframe style attribute',
type: 'input-textarea',
default: '',
descriptionHTML: 'Additional styles to be added on the iframe style attribute. <br>' +
'Example: height:400px;',
private: false
})
}

View File

@ -1,19 +1,5 @@
import type { NextFunction, Request, Response } from 'express'
const path = require('path')
const fs = require('fs').promises
interface RegisterServerOptions {
registerHook: any
registerSetting: any
settingsManager: any
storageManager: any
videoCategoryManager: any
videoLicenceManager: any
videoLanguageManager: any
getRouter: any
peertubeHelpers: any
}
import { initSettings } from './lib/settings'
import { initRouters } from './lib/routers'
async function register ({
registerSetting,
@ -21,193 +7,11 @@ async function register ({
getRouter,
peertubeHelpers
}: RegisterServerOptions): Promise<any> {
registerSetting({
name: 'chat-auto-display',
label: 'Automatically open the chat',
type: 'input-checkbox',
default: false,
private: false
})
registerSetting({
name: 'chat-open-blank',
label: 'Show the «open in new window» button',
private: false,
type: 'input-checkbox',
default: false
})
registerSetting({
name: 'chat-only-locals',
label: 'Chats are only available for local videos.',
type: 'input-checkbox',
default: false, // TODO: set to true when peertube has fixed https://github.com/Chocobozzz/PeerTube/issues/3838
private: false
})
registerSetting({
name: 'chat-all-lives',
label: 'Activate chat for all lives',
type: 'input-checkbox',
default: false,
descriptionHTML: 'If checked, a chat will be added to all lives.',
private: false
})
registerSetting({
name: 'chat-all-non-lives',
label: 'Activate chat for all non-lives',
type: 'input-checkbox',
default: false,
descriptionHTML: 'If checked, a chat will be added to all video that are not lives.',
private: false
})
registerSetting({
name: 'chat-videos-list',
label: 'Activate chat for specific videos',
type: 'input-textarea',
default: '',
descriptionHTML: 'Videos UUIDs for which we want a chat. ' +
'Can be non-live videos. One per line. <br />' +
'You can add comments: everything after the # character will be stripped off, and empty lines ignored.<br />' +
'Don\'t add private videos, the UUIDs will be send to frontend.',
private: false
})
registerSetting({
name: 'chat-use-builtin',
label: 'Use builtin ConverseJS',
type: 'input-checkbox',
default: false, // TODO: set to true when peertube has fixed https://github.com/Chocobozzz/PeerTube/issues/3838
private: false,
descriptionHTML: 'If checked, use a builtin ConverseJS iframe.<br>' +
'You still have to configure an external XMPP service. Please see the ' +
'<a href="https://github.com/JohnXLivingston/peertube-plugin-livechat" target="_blank">documentation<a>.<br>' +
'If you have no running webchat service, you can follow this ' +
// eslint-disable-next-line max-len
'<a href="https://github.com/JohnXLivingston/peertube-plugin-livechat/blob/main/documentation/tutorials/prosody.md" target="blank_">tutorial</a>.'
})
registerSetting({
name: 'chat-server',
label: 'Builtin webchat: XMPP service server',
type: 'input',
default: '',
descriptionHTML: 'When using the built-in converseJS webchat:<br>' +
'Your XMPP server. Without any scheme. Example : peertube.im.your_domain.',
private: true
})
registerSetting({
name: 'chat-room',
label: 'Builtin webchat: XMPP room template',
type: 'input',
default: '',
descriptionHTML: 'When using the built-in converseJS webchat:<br>' +
'Your XMPP room. You can use the placeholder {{VIDEO_UUID}} to add the video UUID.' +
'Without this placeholder, all videos will point to the same chat room.<br>' +
'Example: public@room.peertube.im.your_domain<br>' +
'Example: public_{{VIDEO_UUID}}@room.peertube.im.your_domain',
private: true
})
registerSetting({
name: 'chat-bosh-uri',
label: 'Builtin webchat: BOSH uri',
type: 'input',
default: '',
descriptionHTML: 'When using the built-in converseJS webchat:<br>' +
'URI of the external BOSH server. Please make sure it accept cross origin request from your domain.<br>' +
'You must at least have a BOSH or a Websocket uri.',
private: true
})
registerSetting({
name: 'chat-ws-uri',
label: 'Builtin webchat: WS uri',
type: 'input',
default: '',
descriptionHTML: 'When using the built-in converseJS webchat:<br>' +
'URI of the external WS server. Please make sure it accept cross origin request from your domain.<br>' +
'You must at least have a BOSH or a Websocket uri.',
private: true
})
registerSetting({
name: 'chat-uri',
label: 'Webchat url',
type: 'input',
default: '',
descriptionHTML: '<b>If you dont want to use the builtin ConverseJS webchat:</b><br>' +
'Put here your webchat url. An iframe will be created pointing to this url. ' +
'The placeholder {{VIDEO_UUID}} will be replace by the video UUID if present. ' +
'Example : https://my_domain/conversejs.html?room=video_{{VIDEO_UUID}}.<br>' +
'If this field is empty, it will use the builtin ConverseJS webchat.',
private: false
})
registerSetting({
name: 'chat-style',
label: 'Webchat iframe style attribute',
type: 'input-textarea',
default: '',
descriptionHTML: 'Additional styles to be added on the iframe style attribute. <br>' +
'Example: height:400px;',
private: false
})
const converseJSIndex = await fs.readFile(path.resolve(__dirname, './conversejs/index.html'))
const router = getRouter()
router.get('/ping', (req: Request, res: Response) => res.json({ message: 'pong' }))
router.get('/webchat', async (req: Request, res: Response, next: NextFunction) => {
try {
const settings = await settingsManager.getSettings([
'chat-use-builtin', 'chat-room', 'chat-server',
'chat-bosh-uri', 'chat-ws-uri'
])
if (!settings['chat-use-builtin']) {
throw new Error('Builtin chat disabled.')
}
if (!settings['chat-server']) {
throw new Error('Missing chat-server settings.')
}
if (!settings['chat-room']) {
throw new Error('Missing chat-room settings.')
}
if (!settings['chat-bosh-uri'] && !settings['chat-ws-uri']) {
throw new Error('Missing BOSH or Websocket uri.')
}
// FIXME: with Peertube 3.0.1 the following method is not available...
// When loadByIdOrUUID is available, change the entry point to
// be /webchat/:videoId
// const id = req.param('videoId')
// const video = await peertubeHelpers.videos.loadByIdOrUUID(id)
let url: string = req.query.url as string || ''
if (!url) {
throw new Error('Missing url parameter)')
}
let video = await peertubeHelpers.videos.loadByUrl(url)
if (!video) {
// FIXME: remove this when loadByIdOrUUID will be available...
// This is a dirty Hack for dev environnements...
url = url.replace(/^https:/, 'http:')
video = await peertubeHelpers.videos.loadByUrl(url)
}
if (!video) {
throw new Error('Video not found')
}
let page = '' + (converseJSIndex as string)
// FIXME: Peertube should provide the static folder path. For now:
const staticRelative = '../static'
page = page.replace(/{{BASE_STATIC_URL}}/g, staticRelative)
page = page.replace(/{{JID}}/g, settings['chat-server'])
const room = settings['chat-room'].replace(/{{VIDEO_UUID}}/g, video.uuid)
page = page.replace(/{{ROOM}}/g, room)
page = page.replace(/{{BOSH_SERVICE_URL}}/g, settings['chat-bosh-uri'])
page = page.replace(/{{WS_SERVICE_URL}}/g, settings['chat-ws-uri'])
res.status(200)
res.type('html')
res.send(page)
} catch (error) {
return next(error)
}
await initSettings({ registerSetting })
await initRouters({
settingsManager,
getRouter,
peertubeHelpers
})
}

91
server/peertube.d.ts vendored Normal file
View File

@ -0,0 +1,91 @@
interface RegisterServerHookOptions {
target: string // FIXME
handler: Function
priority?: number
}
interface RegisterServerSettingOptions {
name: string
label: string
type: 'input' | 'input-checkbox' | 'input-password' | 'input-textarea' | 'markdown-text' | 'markdown-enhanced'
descriptionHTML?: string
default?: string | boolean
private: boolean
}
interface PluginSettingsManager {
getSetting: (name: string) => Promise<string | boolean>
getSettings: (names: string[]) => Promise<{ [settingName: string]: string | boolean }>
setSetting: (name: string, value: string) => Promise<any>
onSettingsChange: (cb: (names: string[]) => void) => void
}
interface PluginStorageManager {
getData: (key: string) => Promise<string>
storeData: (key: string, data: any) => Promise<any>
}
interface PluginVideoCategoryManager {
addCategory: (categoryKey: number, categoryLabel: string) => boolean
deleteCategory: (categoryKey: number) => boolean
}
interface PluginVideoLicenceManager {
addLicence: (licenceKey: number, licenceLabel: string) => boolean
deleteLicence: (licenceKey: number) => boolean
}
interface PluginVideoLanguageManager {
addLanguage: (languageKey: string, languageLabel: string) => boolean
deleteLanguage: (languageKey: string) => boolean
}
type MVideoThumbnail = any // FIXME
interface VideoBlacklistCreate {
reason?: string
unfederate?: boolean
}
type ActorModel = any // FIXME
interface PeerTubeHelpers {
logger: Logger
database: {
query: Function
}
videos: {
loadByUrl: (url: string) => Promise<MVideoThumbnail>
// NB: loadByIdOrUUID was introduced in v3.1.0
loadByIdOrUUID?: (id: number | string) => Promise<MVideoThumbnail>
removeVideo: (videoId: number) => Promise<void>
}
config: {
getWebserverUrl: () => string
}
moderation: {
blockServer: (options: { byAccountId: number, hostToBlock: string }) => Promise<void>
unblockServer: (options: { byAccountId: number, hostToUnblock: string }) => Promise<void>
blockAccount: (options: { byAccountId: number, handleToBlock: string }) => Promise<void>
unblockAccount: (options: { byAccountId: number, handleToUnblock: string }) => Promise<void>
blacklistVideo: (
options: { videoIdOrUUID: number | string, createOptions: VideoBlacklistCreate }
) => Promise<void>
unblacklistVideo: (options: { videoIdOrUUID: number | string }) => Promise<void>
}
server: {
getServerActor: () => Promise<ActorModel>
}
}
interface RegisterServerOptions {
registerHook: (options: RegisterServerHookOptions) => void
registerSetting: (options: RegisterServerSettingOptions) => void
settingsManager: PluginSettingsManager
storageManager: PluginStorageManager
videoCategoryManager: PluginVideoCategoryManager
videoLicenceManager: PluginVideoLicenceManager
videoLanguageManager: PluginVideoLanguageManager
getRouter: () => Router
peertubeHelpers: PeerTubeHelpers
}

View File

@ -14,8 +14,9 @@
"removeComments": true,
"sourceMap": true,
"baseUrl": "./",
"outDir": "../dist/server",
"paths": {},
"paths": {}
},
"include": ["./**/*"],
"exclude": []