Reverting work on DemoBot (it is now an external package).
This commit is contained in:
parent
d01d13a69e
commit
2e7cec04d9
@ -2,14 +2,10 @@
|
||||
|
||||
## (unreleased yet)
|
||||
|
||||
### Features
|
||||
|
||||
* Adding Bots to builtin Prosody mode!
|
||||
* The DemoBot: it is a bot than can join rooms to demonstrate the plugin (it is an hidden feature).
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix spanish translation.
|
||||
* Hide secret keys in diagnostic tool.
|
||||
|
||||
## v5.0.2
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": false,
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"standard-with-typescript"
|
||||
],
|
||||
"globals": {},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"project": [
|
||||
"./bots/tsconfig.json"
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"ignorePatterns": [],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": [2, {"argsIgnorePattern": "^_"}],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||
"@typescript-eslint/return-await": [2, "in-try-catch"], // FIXME: correct?
|
||||
"@typescript-eslint/no-invalid-void-type": "off",
|
||||
"@typescript-eslint/triple-slash-reference": "off",
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 120,
|
||||
"comments": 120
|
||||
}
|
||||
],
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
}
|
70
bots/bots.ts
70
bots/bots.ts
@ -1,70 +0,0 @@
|
||||
import { BotsConfig } from './lib/config'
|
||||
import { logger } from './lib/logger'
|
||||
import { BotComponent } from './lib/bot/component'
|
||||
import { BotHandlerDemo } from './lib/bot/handlers/demo'
|
||||
|
||||
if (!process.argv[2]) {
|
||||
throw new Error('Missing parameter: the demobot configuration file path')
|
||||
}
|
||||
const botsConfig = new BotsConfig(process.argv[2])
|
||||
|
||||
const runningBots: BotComponent[] = []
|
||||
|
||||
async function start (botsConfig: BotsConfig): Promise<void> {
|
||||
await botsConfig.load()
|
||||
|
||||
let atLeastOne: boolean = false
|
||||
if (botsConfig.useDemoBot()) {
|
||||
atLeastOne = true
|
||||
logger.info('Starting DemoBot...')
|
||||
|
||||
const config = botsConfig.getDemoBotConfig()
|
||||
const instance = new BotComponent(
|
||||
'DemoBot',
|
||||
{
|
||||
service: config.service,
|
||||
domain: config.domain,
|
||||
password: config.password
|
||||
},
|
||||
config.mucDomain
|
||||
)
|
||||
runningBots.push(instance)
|
||||
|
||||
instance.connect().then(async () => {
|
||||
for (const roomId of config.rooms) {
|
||||
const room = await instance.joinRoom(roomId, 'DemoBot')
|
||||
room.attachHandler(new BotHandlerDemo(room))
|
||||
}
|
||||
}).catch(err => { throw err })
|
||||
}
|
||||
if (!atLeastOne) {
|
||||
logger.info('No bot to launch, exiting.')
|
||||
process.exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
async function shutdown (): Promise<void> {
|
||||
logger.info('Shutdown...')
|
||||
for (const bot of runningBots) {
|
||||
logger.info('Stopping the bot ' + bot.botName + '...')
|
||||
await bot.disconnect()
|
||||
}
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// catching signals and do something before exit
|
||||
['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
|
||||
'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGTERM'
|
||||
].forEach((sig) => {
|
||||
process.on(sig, () => {
|
||||
logger.debug('Receiving signal: ' + sig)
|
||||
shutdown().catch((err) => {
|
||||
logger.error(`Error on shutting down: ${err as string}`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
start(botsConfig).catch((err) => {
|
||||
logger.error(`Function start failed: ${err as string}`)
|
||||
process.exit(1)
|
||||
})
|
@ -1,115 +0,0 @@
|
||||
import type { XMPPStanza, XMPPStanzaType } from './types'
|
||||
import type { Node } from '@xmpp/xml'
|
||||
import { logger } from '../logger'
|
||||
import { component, xml, Component, Options } from '@xmpp/component'
|
||||
import { parse, JID } from '@xmpp/jid'
|
||||
import { BotRoom } from './room'
|
||||
|
||||
class BotComponent {
|
||||
protected xmpp?: Component
|
||||
protected address?: JID
|
||||
public readonly xml = xml
|
||||
protected rooms: Map<string, BotRoom> = new Map()
|
||||
|
||||
constructor (
|
||||
public readonly botName: string,
|
||||
protected readonly connectionConfig: Options,
|
||||
protected readonly mucDomain: string
|
||||
) {}
|
||||
|
||||
public async connect (): Promise<void> {
|
||||
this.xmpp = component({
|
||||
service: this.connectionConfig.service,
|
||||
domain: this.connectionConfig.domain,
|
||||
password: this.connectionConfig.password
|
||||
})
|
||||
|
||||
this.xmpp.on('error', (err: any) => {
|
||||
logger.error(err)
|
||||
})
|
||||
|
||||
this.xmpp.on('offline', () => {
|
||||
logger.info(`${this.botName} is now offline.`)
|
||||
})
|
||||
|
||||
this.xmpp.on('stanza', (stanza: XMPPStanza) => {
|
||||
logger.debug('stanza received' + stanza.toString())
|
||||
if (!stanza.attrs.from) { return }
|
||||
const jid = parse(stanza.attrs.from)
|
||||
const roomJid = jid.bare() // removing the «resource» part of the jid.
|
||||
const room = this.rooms.get(roomJid.toString())
|
||||
if (!room) {
|
||||
return
|
||||
}
|
||||
room.emit('stanza', stanza, jid.getResource())
|
||||
})
|
||||
|
||||
this.xmpp.on('online', (address) => {
|
||||
logger.debug('Online with address' + address.toString())
|
||||
|
||||
this.address = address
|
||||
|
||||
// 'online' is emitted at reconnection, so we must reset rooms rosters
|
||||
this.rooms.forEach(room => room.emit('reset'))
|
||||
})
|
||||
|
||||
this.xmpp.on('offline', () => {
|
||||
logger.info(`Stoppping process: ${this.botName} is now offline.`)
|
||||
})
|
||||
|
||||
await this.xmpp.start()
|
||||
}
|
||||
|
||||
public async disconnect (): Promise<any> {
|
||||
for (const [roomId, room] of this.rooms) {
|
||||
logger.debug(`Leaving room ${roomId}...`)
|
||||
await room.detachHandlers()
|
||||
await room.part()
|
||||
}
|
||||
await this.xmpp?.stop()
|
||||
this.xmpp = undefined
|
||||
}
|
||||
|
||||
public async sendStanza (
|
||||
type: XMPPStanzaType,
|
||||
attrs: object,
|
||||
...children: Node[]
|
||||
): Promise<void> {
|
||||
attrs = Object.assign({
|
||||
from: this.address?.toString()
|
||||
}, attrs)
|
||||
|
||||
const stanza = this.xml(type, attrs, ...children)
|
||||
logger.debug('stanza to emit: ' + stanza.toString())
|
||||
await this.xmpp?.send(stanza)
|
||||
}
|
||||
|
||||
public async joinRoom (roomId: string, nick: string): Promise<BotRoom> {
|
||||
const roomJID = new JID(roomId, this.mucDomain)
|
||||
const roomJIDstr = roomJID.toString()
|
||||
let room: BotRoom | undefined = this.rooms.get(roomJIDstr)
|
||||
if (!room) {
|
||||
room = new BotRoom(this, roomJID)
|
||||
this.rooms.set(roomJIDstr, room)
|
||||
}
|
||||
await room.join(nick)
|
||||
return room
|
||||
}
|
||||
|
||||
public async partRoom (roomId: string): Promise<void> {
|
||||
const roomJID = new JID(roomId, this.mucDomain)
|
||||
const room = this.rooms.get(roomJID.toString())
|
||||
if (!room) {
|
||||
return
|
||||
}
|
||||
await room.part()
|
||||
}
|
||||
|
||||
public getAddress (): JID | undefined {
|
||||
return this.address
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
BotComponent
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import type { BotRoom } from '../room'
|
||||
|
||||
export abstract class BotHandler {
|
||||
constructor (
|
||||
protected readonly room: BotRoom
|
||||
) {
|
||||
this.init()
|
||||
}
|
||||
|
||||
protected abstract init (): void
|
||||
public abstract stop (): void
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
import type { XMPPUser } from '../types'
|
||||
import { logger } from '../../logger'
|
||||
import { BotHandler } from './base'
|
||||
|
||||
const RANDOM_MESSAGES: string[] = [
|
||||
'🎵🎶',
|
||||
'🎵🎶 I\'m just a bot, I\'m just a bot in the world. 🎵🎶',
|
||||
'You can see who is connected by opening the right panel.',
|
||||
'This is a random message.',
|
||||
'Oh, yet another random message.',
|
||||
'You can mention a user using a @ in front of a user\'s nick. Try to mention me.'
|
||||
]
|
||||
|
||||
export class BotHandlerDemo extends BotHandler {
|
||||
protected readonly lastHellos: Map<string, Date> = new Map()
|
||||
protected randomCount: number = 0
|
||||
protected randomTimeout: NodeJS.Timeout | undefined
|
||||
|
||||
protected init (): void {
|
||||
const room = this.room
|
||||
room.on('room_join', (user: XMPPUser) => {
|
||||
if (user.isMe) {
|
||||
return
|
||||
}
|
||||
if (!room.isOnline()) {
|
||||
return
|
||||
}
|
||||
const lastHello = this.lastHellos.get(user.nick)
|
||||
const now = new Date()
|
||||
let msg: string
|
||||
if (lastHello) {
|
||||
logger.debug(`The user ${user.nick} was already seen at ${lastHello.toString()}`)
|
||||
if ((now.getTime() - lastHello.getTime()) < 3600 * 1000) { // no more than one hello per hour
|
||||
logger.info(`The user ${user.nick} was seen to recently, no message to send.`)
|
||||
return
|
||||
}
|
||||
logger.info(`The user ${user.nick} was seen a long time ago, sending a message.`)
|
||||
msg = `Hello ${user.nick}! Happy to see you again.`
|
||||
} else {
|
||||
logger.info(`The user ${user.nick} is here for the first time. Sending a message.`)
|
||||
msg = `Hello ${user.nick}! I'm the DemoBot, I'm here to demonstrate the chatroom.`
|
||||
}
|
||||
this.lastHellos.set(user.nick, now)
|
||||
room.sendGroupchat(msg).catch(() => {})
|
||||
})
|
||||
|
||||
room.on('room_message', (msg: string, user?: XMPPUser, mentionned?: boolean) => {
|
||||
if (!user || user.isMe) { return }
|
||||
if (!room.isOnline()) { return }
|
||||
if (!mentionned) { return }
|
||||
|
||||
room.sendGroupchat(`Yep @${user.nick}?`).catch(() => {})
|
||||
})
|
||||
|
||||
this.randomTimeout = setInterval(() => {
|
||||
this.sendRandomMessage()
|
||||
}, 60 * 1000)
|
||||
}
|
||||
|
||||
public stop (): void {
|
||||
if (this.randomTimeout) {
|
||||
clearInterval(this.randomTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
protected sendRandomMessage (): void {
|
||||
const room = this.room
|
||||
if (!room.isOnline()) { return }
|
||||
// checking if there is someone to listen...
|
||||
const onlineUserCount = this.room.onlineUserCount()
|
||||
logger.debug(`Online user count in room: ${onlineUserCount}`)
|
||||
if (onlineUserCount < 2) { return }
|
||||
const cpt = this.randomCount++
|
||||
logger.info(`Emitting the random message number ${cpt}.`)
|
||||
this.room.sendGroupchat(RANDOM_MESSAGES[cpt % RANDOM_MESSAGES.length]).catch(() => {})
|
||||
}
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
import type { BotComponent } from './component'
|
||||
import type { BotHandler } from './handlers/base'
|
||||
import type { XMPPStanza, XMPPUser } from './types'
|
||||
import EventEmitter from 'events'
|
||||
import { JID } from '@xmpp/jid'
|
||||
import { logger } from '../logger'
|
||||
|
||||
export class BotRoom extends EventEmitter {
|
||||
protected state: 'offline' | 'online' = 'offline'
|
||||
protected userJID: JID | undefined
|
||||
protected readonly roster: Map<string, XMPPUser> = new Map()
|
||||
|
||||
protected readonly handlers: BotHandler[] = []
|
||||
|
||||
constructor (
|
||||
protected readonly component: BotComponent,
|
||||
protected readonly roomJID: JID
|
||||
) {
|
||||
super()
|
||||
|
||||
this.on('reset', () => {
|
||||
this.state = 'offline'
|
||||
this.roster.clear()
|
||||
})
|
||||
this.on('stanza', (stanza: XMPPStanza, resource?: string) => {
|
||||
this.receiveStanza(stanza, resource)
|
||||
})
|
||||
}
|
||||
|
||||
public isOnline (): boolean {
|
||||
return this.state === 'online'
|
||||
}
|
||||
|
||||
public onlineUserCount (): number {
|
||||
let count = 0
|
||||
this.roster.forEach(user => {
|
||||
if (user.state === 'online') { count++ }
|
||||
})
|
||||
return count
|
||||
}
|
||||
|
||||
public async join (nick: string): Promise<void> {
|
||||
this.userJID = new JID(this.roomJID.getLocal(), this.roomJID.getDomain(), nick)
|
||||
logger.debug(`Emitting a presence for room ${this.roomJID.toString()}...`)
|
||||
await this.component.sendStanza('presence',
|
||||
{
|
||||
to: this.userJID.toString()
|
||||
},
|
||||
this.component.xml('x', {
|
||||
xmlns: 'http://jabber.org/protocol/muc'
|
||||
})
|
||||
)
|
||||
// FIXME: should wait for a presence stanza from the server.
|
||||
// FIXME: should handle used nick errors.
|
||||
}
|
||||
|
||||
public async part (): Promise<void> {
|
||||
if (!this.userJID) { return }
|
||||
logger.debug(`Emitting a presence=unavailable for room ${this.roomJID.toString()}...`)
|
||||
await this.component.sendStanza('presence', {
|
||||
to: this.userJID.toString(),
|
||||
type: 'unavailable'
|
||||
})
|
||||
// FIXME: should wait for a presence stanza from the server.
|
||||
}
|
||||
|
||||
public async sendGroupchat (msg: string): Promise<void> {
|
||||
if (!this.userJID) { return }
|
||||
logger.debug(`Emitting a groupchat message for room ${this.roomJID.toString()}...`)
|
||||
await this.component.sendStanza(
|
||||
'message',
|
||||
{
|
||||
type: 'groupchat',
|
||||
to: this.roomJID.toString()
|
||||
},
|
||||
this.component.xml('body', {}, msg)
|
||||
)
|
||||
}
|
||||
|
||||
public receiveStanza (stanza: XMPPStanza, fromResource?: string): void {
|
||||
if (stanza.name === 'presence') {
|
||||
this.receivePresenceStanza(stanza, fromResource)
|
||||
}
|
||||
if (stanza.name === 'message') {
|
||||
this.receiveMessageStanza(stanza, fromResource)
|
||||
}
|
||||
}
|
||||
|
||||
public receivePresenceStanza (stanza: XMPPStanza, fromResource?: string): void {
|
||||
if (!fromResource) {
|
||||
return
|
||||
}
|
||||
|
||||
const isPresent = stanza.attrs.type !== 'unavailable'
|
||||
|
||||
const statusElems = stanza.getChild('x')?.getChildren('status')
|
||||
const statusCodes = []
|
||||
if (statusElems) {
|
||||
for (const s of statusElems) {
|
||||
statusCodes.push(parseInt(s.attrs.code))
|
||||
}
|
||||
}
|
||||
const isMe = statusCodes.includes(110) // status 110 means that is concern the current user.
|
||||
|
||||
let user = this.roster.get(fromResource)
|
||||
const previousState = user?.state
|
||||
if (!isPresent) {
|
||||
if (!user) {
|
||||
return
|
||||
}
|
||||
user.state = 'offline'
|
||||
if (isMe) {
|
||||
this.state = 'offline'
|
||||
}
|
||||
if (previousState === 'online') {
|
||||
this.emit('room_part', user)
|
||||
}
|
||||
} else {
|
||||
if (!user) {
|
||||
user = {
|
||||
state: 'online',
|
||||
nick: fromResource,
|
||||
isMe: isMe
|
||||
}
|
||||
this.roster.set(fromResource, user)
|
||||
} else {
|
||||
user.state = 'online'
|
||||
}
|
||||
if (isMe) {
|
||||
this.state = 'online'
|
||||
}
|
||||
if (previousState !== 'online') {
|
||||
this.emit('room_join', user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected receiveMessageStanza (stanza: XMPPStanza, fromResource?: string): void {
|
||||
if (stanza.attrs.type !== 'groupchat') {
|
||||
return
|
||||
}
|
||||
// ignoring messages send by the bot himself
|
||||
if (stanza.attrs.from === this.userJID?.toString()) {
|
||||
return
|
||||
}
|
||||
// ignoring history messages
|
||||
if (stanza.getChild('delay')) {
|
||||
return
|
||||
}
|
||||
const body = stanza.getChild('body')
|
||||
// ignoring message without body (subject, ...)
|
||||
if (!body) {
|
||||
return
|
||||
}
|
||||
|
||||
let mentionned: boolean = false // I'm I mentionned?
|
||||
// TODO: fix this ugly code.
|
||||
if (this.userJID) {
|
||||
const references = stanza.getChildren('reference')
|
||||
for (const reference of references) {
|
||||
if (reference.attrs.type === 'mention') {
|
||||
if (reference.attrs.uri === 'xmpp:' + this.userJID.toString()) {
|
||||
mentionned = true
|
||||
} else {
|
||||
const addr = this.component.getAddress()
|
||||
if (addr) {
|
||||
if (reference.attrs.uri === 'xmpp:' + addr.toString()) {
|
||||
mentionned = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const user = fromResource ? this.roster.get(fromResource) : undefined
|
||||
this.emit('room_message', body.toString(), user, mentionned)
|
||||
}
|
||||
|
||||
public attachHandler (handler: BotHandler): void {
|
||||
this.handlers.push(handler)
|
||||
}
|
||||
|
||||
public detachHandlers (): void {
|
||||
for (const handler of this.handlers) {
|
||||
handler.stop()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import type { Element } from '@xmpp/xml'
|
||||
|
||||
export type XMPPStanzaType = 'message' | 'iq' | 'presence'
|
||||
|
||||
export interface XMPPStanza extends Element {
|
||||
name: XMPPStanzaType
|
||||
}
|
||||
|
||||
export interface XMPPUser {
|
||||
state: 'offline' | 'online'
|
||||
nick: string
|
||||
isMe: boolean
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import decache from 'decache'
|
||||
import { logger } from '../lib/logger'
|
||||
|
||||
interface DemoBotConfig {
|
||||
rooms: string[]
|
||||
service: string
|
||||
domain: string
|
||||
mucDomain: string
|
||||
password: string
|
||||
}
|
||||
|
||||
class BotsConfig {
|
||||
protected readonly configDir: string
|
||||
protected configs: {
|
||||
demobot?: DemoBotConfig
|
||||
}
|
||||
|
||||
constructor (configDir: string) {
|
||||
this.configDir = configDir = path.resolve(configDir)
|
||||
|
||||
// Not necessary, but just in case: perform some path checking... (to limit code injection risks)
|
||||
const parts = configDir.split(path.sep)
|
||||
if (!parts.includes('peertube-plugin-livechat')) {
|
||||
// Indeed, the path should contain the plugin name
|
||||
// (/var/www/peertube/storage/plugins/data/peertube-plugin-livechat/...)
|
||||
throw new Error('Bots configuration dir seems invalid (not in peertube-plugin-livechat folder).')
|
||||
}
|
||||
|
||||
this.configs = {}
|
||||
}
|
||||
|
||||
public async load (): Promise<void> {
|
||||
await this.loadDemoBot()
|
||||
}
|
||||
|
||||
protected async loadDemoBot (): Promise<void> {
|
||||
const configPath = path.resolve(this.configDir, 'demobot.js')
|
||||
logger.debug(`Loading DemoBot config from file ${configPath}`)
|
||||
if (!fs.existsSync(configPath)) {
|
||||
logger.debug('The config file for DemoBot does not exist.')
|
||||
delete this.configs.demobot
|
||||
return
|
||||
}
|
||||
|
||||
decache(configPath)
|
||||
|
||||
logger.debug('require DemoBot config file...')
|
||||
const conf = require(configPath).getConf() as DemoBotConfig | null
|
||||
if (!conf) {
|
||||
logger.debug('getConf() returned null for the DemoBot.')
|
||||
delete this.configs.demobot
|
||||
return
|
||||
}
|
||||
if (!conf.rooms || !conf.domain || !conf.mucDomain || !conf.password || !conf.service) {
|
||||
logger.error('Invalid DemoBot configuration: ' + JSON.stringify(conf))
|
||||
delete this.configs.demobot
|
||||
return
|
||||
}
|
||||
|
||||
// Conf seems legit. But if there is no rooms, no need to keep it.
|
||||
if (!conf.rooms.length) {
|
||||
logger.debug('No room in DemoBot config.')
|
||||
delete this.configs.demobot
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: detect changes? avoid reloading when not needed? or should it be by the caller?
|
||||
logger.debug('Config loaded for demobot: ' + JSON.stringify(conf))
|
||||
this.configs.demobot = conf
|
||||
}
|
||||
|
||||
public useDemoBot (): boolean {
|
||||
return (this.configs.demobot?.rooms?.length ?? 0) > 0
|
||||
}
|
||||
|
||||
public getDemoBotConfig (): DemoBotConfig {
|
||||
if (!this.configs.demobot) {
|
||||
throw new Error('Should not call getDemoBotConfig when useDemoBot is false.')
|
||||
}
|
||||
return this.configs.demobot
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
BotsConfig
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
class Logger {
|
||||
public debug (s: string): void {
|
||||
console.log(s)
|
||||
}
|
||||
|
||||
public info (s: string): void {
|
||||
console.info(s)
|
||||
}
|
||||
|
||||
public warn (s: string): void {
|
||||
console.warn(s)
|
||||
}
|
||||
|
||||
public error (s: string): void {
|
||||
console.error(s)
|
||||
}
|
||||
}
|
||||
|
||||
const logger = new Logger()
|
||||
|
||||
export {
|
||||
logger
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
{
|
||||
"extends": "@tsconfig/node12/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node", // Tell tsc to look in node_modules for modules
|
||||
"strict": true, // That implies alwaysStrict, noImplicitAny, noImplicitThis
|
||||
|
||||
"alwaysStrict": true, // should already be true because of strict:true
|
||||
"noImplicitAny": true, // should already be true because of strict:true
|
||||
"noImplicitThis": true, // should already be true because of strict:true
|
||||
"noImplicitReturns": true,
|
||||
"strictBindCallApply": true, // should already be true because of strict:true
|
||||
"noUnusedLocals": true,
|
||||
|
||||
"removeComments": true,
|
||||
"sourceMap": true,
|
||||
|
||||
"baseUrl": "./",
|
||||
"outDir": "../dist/",
|
||||
"paths": {}
|
||||
},
|
||||
"include": [
|
||||
"./**/*",
|
||||
"../shared/**/*"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
@ -211,7 +211,6 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
|
||||
case 'prosody-muc-log-by-default':
|
||||
case 'prosody-muc-expiration':
|
||||
case 'prosody-c2s':
|
||||
case 'prosody-component-port':
|
||||
return options.formValues['chat-type'] !== ('builtin-prosody' as ChatType)
|
||||
case 'prosody-c2s-port':
|
||||
return !(
|
||||
|
@ -122,8 +122,3 @@ When you open the chat room in full screen, there will also be a menu with dedic
|
||||
### OBS Overlay using Matterbridge
|
||||
|
||||
Here is a tutorial to use Matterbridge with the plugin: <https://gitlab.com/refrac/obs-matterbridge-overlay/-/blob/master/documentation/peertube.md>
|
||||
|
||||
### Demobot
|
||||
|
||||
This is a hidden feature. It is a bot that can join rooms, and demonstrate the plugin capacities.
|
||||
This is not documented for now.
|
||||
|
304
package-lock.json
generated
304
package-lock.json
generated
@ -175,15 +175,6 @@
|
||||
"integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/accepts": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz",
|
||||
"integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/async": {
|
||||
"version": "3.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.9.tgz",
|
||||
@ -220,24 +211,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
"integrity": "sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/cookies": {
|
||||
"version": "0.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.7.tgz",
|
||||
"integrity": "sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/connect": "*",
|
||||
"@types/express": "*",
|
||||
"@types/keygrip": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.17.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
|
||||
@ -281,23 +254,11 @@
|
||||
"form-data": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"@types/http-assert": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.3.tgz",
|
||||
"integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/http-cache-semantics": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz",
|
||||
"integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A=="
|
||||
},
|
||||
"@types/http-errors": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.1.tgz",
|
||||
"integrity": "sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
||||
@ -310,12 +271,6 @@
|
||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/keygrip": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz",
|
||||
"integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/keyv": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz",
|
||||
@ -324,37 +279,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/koa": {
|
||||
"version": "2.13.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.13.4.tgz",
|
||||
"integrity": "sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/accepts": "*",
|
||||
"@types/content-disposition": "*",
|
||||
"@types/cookies": "*",
|
||||
"@types/http-assert": "*",
|
||||
"@types/http-errors": "*",
|
||||
"@types/keygrip": "*",
|
||||
"@types/koa-compose": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/koa-compose": {
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.5.tgz",
|
||||
"integrity": "sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/koa": "*"
|
||||
}
|
||||
},
|
||||
"@types/ltx": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ltx/-/ltx-3.0.1.tgz",
|
||||
"integrity": "sha512-X+1EoqEcSZ45MYJmg0rfMvEyQPGydLT00HJcPant+5J3+OM0N+ZVL6BdZ1Iy4K3dA+JBGe1WP7PvTM/GtxN/XA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mime": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||
@ -429,119 +353,6 @@
|
||||
"winston": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__component": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__component/-/xmpp__component-0.13.0.tgz",
|
||||
"integrity": "sha512-4vKLiicgkZwW8bKofmmy0BJpw3MuOW73c5hVPhUtgBPDTh9hj7wQezhpOLX3AhQFto97YpLg2GwWzhnwfSl1BA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/xmpp__component-core": "*",
|
||||
"@types/xmpp__iq": "*",
|
||||
"@types/xmpp__middleware": "*",
|
||||
"@types/xmpp__reconnect": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__component-core": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__component-core/-/xmpp__component-core-0.13.0.tgz",
|
||||
"integrity": "sha512-K9l6SLG91kTcchW/Nt5TL9Kfe5aWDyDcHWvoFgnwvGoF4g0K737HdZMzD0DN1TP7Gb2g/JNCiK245BuDYegAbw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/xmpp__connection-tcp": "*",
|
||||
"@types/xmpp__jid": "*",
|
||||
"@types/xmpp__xml": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__connection": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__connection/-/xmpp__connection-0.13.0.tgz",
|
||||
"integrity": "sha512-YsvLhgOfxY3TbDTeTT0ZrToqh3IsA0nKnXk/NxTES2O6wTxn9lQDRBYNgB6lkq+D50nA8nmT3d53acb0f4Rycw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/xmpp__error": "*",
|
||||
"@types/xmpp__events": "*",
|
||||
"@types/xmpp__jid": "*",
|
||||
"@types/xmpp__xml": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__connection-tcp": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__connection-tcp/-/xmpp__connection-tcp-0.13.0.tgz",
|
||||
"integrity": "sha512-yHvAWck6JVs0H/E2tnoUVOsFPylLj1TX4ARdm1/jFRqOPWynw36B/RU0UW1KNSC8dKA6VAhl0mTICnGUZVtcug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/xmpp__connection": "*",
|
||||
"@types/xmpp__xml": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__error": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__error/-/xmpp__error-0.13.0.tgz",
|
||||
"integrity": "sha512-W+tM0UDj3toruhdjhn/VK1mtjOF+YMz+FdxgkMVi6lwCXA/uDW79elW6WbeM8zhiM92ZoVPSgD2zt9YXmrkiZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/xmpp__xml": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__events": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__events/-/xmpp__events-0.13.0.tgz",
|
||||
"integrity": "sha512-somi0EF9BwaBPmDQk6r1hE6dtXXjv2ztSNk/hStcfGVY9NfD9ErcopWgzzbGdeQg2/WcMNlVwfYXQfIm6w3w+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__iq": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__iq/-/xmpp__iq-0.13.0.tgz",
|
||||
"integrity": "sha512-jy3aTixRMi8uqiIfhbkIxeWB62NTFGXKdZsYOwlgLNQ9BUimnbGR8BmZGSic5meUTPUaEEpCx/xp3AnVYADICQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/koa-compose": "*",
|
||||
"@types/xmpp__events": "*",
|
||||
"@types/xmpp__middleware": "*",
|
||||
"@types/xmpp__xml": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__jid": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__jid/-/xmpp__jid-1.3.2.tgz",
|
||||
"integrity": "sha512-zh5mdcBY1zNzI9XxXZxsuq/XGd6YeSwZzwQJpV5NQEtZUiSJ1+YW19+w2pELLrlV2hoMOcSf8PfPwB9ocPwIDg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/xmpp__middleware": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__middleware/-/xmpp__middleware-0.13.0.tgz",
|
||||
"integrity": "sha512-bgwIFdl5khKt/UQY4f6Ca7pEIUGQPCN3CvZ4ZuYSwp5PY9EpH32Tj/akUwfWMuMqGsybvdTeuq7ewT1ic7hsZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/koa-compose": "*",
|
||||
"@types/xmpp__connection": "*",
|
||||
"@types/xmpp__error": "*",
|
||||
"@types/xmpp__jid": "*",
|
||||
"@types/xmpp__xml": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__reconnect": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__reconnect/-/xmpp__reconnect-0.13.0.tgz",
|
||||
"integrity": "sha512-MGuq9Dl24iU/t1nuGp/5yUsv4yAvQk5DOARw/iPXpAjB5hCBCzzvsN2ttkw8vAVsQ5DSbpgPWI33GQ2xF2MaSQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/xmpp__connection": "*",
|
||||
"@types/xmpp__events": "*"
|
||||
}
|
||||
},
|
||||
"@types/xmpp__xml": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/xmpp__xml/-/xmpp__xml-0.13.1.tgz",
|
||||
"integrity": "sha512-pxRGht/JVPhIwvcFkqv3fsXc1V/qj/C+vkTD75S1whpaNslJJbmA4hphOcbynvIegKdQHxfa56d22sOtHWjDsg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/ltx": "*"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "4.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.0.tgz",
|
||||
@ -879,108 +690,6 @@
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"@xmpp/component": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/component/-/component-0.13.0.tgz",
|
||||
"integrity": "sha512-xl2dCJiM7GH98ncdU86JjiKzGfP7ykTJZW6iSKiAaniUKDRixLDMaKM/X0CR+4sXm3rqvRUTYyzndCmCi8CUpg==",
|
||||
"requires": {
|
||||
"@xmpp/component-core": "^0.13.0",
|
||||
"@xmpp/iq": "^0.13.0",
|
||||
"@xmpp/middleware": "^0.13.0",
|
||||
"@xmpp/reconnect": "^0.13.0"
|
||||
}
|
||||
},
|
||||
"@xmpp/component-core": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/component-core/-/component-core-0.13.0.tgz",
|
||||
"integrity": "sha512-/stz9Eo11Q79z1lJ0yWNv0FsSf8AAYko6ctRjHRlHEGkLhQDw959v4k5eB82YrtApoHLoHCxtJMxDwwWAtlprA==",
|
||||
"requires": {
|
||||
"@xmpp/connection-tcp": "^0.13.0",
|
||||
"@xmpp/jid": "^0.13.0",
|
||||
"@xmpp/xml": "^0.13.0"
|
||||
}
|
||||
},
|
||||
"@xmpp/connection": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/connection/-/connection-0.13.0.tgz",
|
||||
"integrity": "sha512-8aLM+XsHYfI/Q7DsOAClEgA825eHIztCZVP4z+diAYuyhyN1P0e4en1dQjK7QOVvOg+DsA8qTcZ8C0b3pY7EFw==",
|
||||
"requires": {
|
||||
"@xmpp/error": "^0.13.0",
|
||||
"@xmpp/events": "^0.13.0",
|
||||
"@xmpp/jid": "^0.13.0",
|
||||
"@xmpp/xml": "^0.13.0"
|
||||
}
|
||||
},
|
||||
"@xmpp/connection-tcp": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/connection-tcp/-/connection-tcp-0.13.0.tgz",
|
||||
"integrity": "sha512-qsP+/ILYWA6D5MrZfS/7nNtaO469EAPAJ7P9gNA9hj5ZOu5mX6LwGecSBegpnXXP5b378iSlqOLskkVDUmSahg==",
|
||||
"requires": {
|
||||
"@xmpp/connection": "^0.13.0",
|
||||
"@xmpp/xml": "^0.13.0"
|
||||
}
|
||||
},
|
||||
"@xmpp/error": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/error/-/error-0.13.0.tgz",
|
||||
"integrity": "sha512-cTyGMrXzuEulRiG29vvHhaU0vTpOxDQS49dyUAW+2Rj5ex9OXXGiWWbJDodEO9B/rHiUXr1U63818Yv4lxZJBA=="
|
||||
},
|
||||
"@xmpp/events": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/events/-/events-0.13.0.tgz",
|
||||
"integrity": "sha512-G+9NczMWWOawn62r1JIv/N413G2biI+hURiN4iH74FGvjagXwassUeJgPnDUEFp2FTKX3dIrJDkXH49ZcFuo/g==",
|
||||
"requires": {
|
||||
"events": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@xmpp/id": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/id/-/id-0.13.0.tgz",
|
||||
"integrity": "sha512-6m9KAreJ13/FnonnLCeK1a6jJx8PqpdLZfRWxUfQu1Wg4nAlgYrcDSYny+/BUm5ICkAEILjvBtOh/EmJ3wMNmA=="
|
||||
},
|
||||
"@xmpp/iq": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/iq/-/iq-0.13.0.tgz",
|
||||
"integrity": "sha512-3fH7lLIgQ4I/I9nKst+YqFP4WIjV24TVnTDxGQthj7POkmvl2MFo63rlTvA4PV1uRn8FmlyetgP/vbGo+c7yuQ==",
|
||||
"requires": {
|
||||
"@xmpp/events": "^0.13.0",
|
||||
"@xmpp/id": "^0.13.0",
|
||||
"@xmpp/middleware": "^0.13.0",
|
||||
"@xmpp/xml": "^0.13.0"
|
||||
}
|
||||
},
|
||||
"@xmpp/jid": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/jid/-/jid-0.13.0.tgz",
|
||||
"integrity": "sha512-R8XkQOLK7V+wDiXozc9VzoACb4+XPR6K8zno1fur9le7AnUrX/vUvb8/ZcvenFNWVYplvZS6h9GkZPPEGvmUyQ=="
|
||||
},
|
||||
"@xmpp/middleware": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/middleware/-/middleware-0.13.0.tgz",
|
||||
"integrity": "sha512-ZUaArnur2q74nTvwbBckflsxGo73VqEBKk/GaQv0q9Lgg6FjQO/BA6lTlZ597h3V5MBi7SGHPcJ335p1/Rd0uw==",
|
||||
"requires": {
|
||||
"@xmpp/error": "^0.13.0",
|
||||
"@xmpp/jid": "^0.13.0",
|
||||
"@xmpp/xml": "^0.13.0",
|
||||
"koa-compose": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"@xmpp/reconnect": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/reconnect/-/reconnect-0.13.0.tgz",
|
||||
"integrity": "sha512-I0uxzGb6Mr6QlCPjgIGb8eBbPYJc2FauOfpoZ/O7Km+i41MxLmVyNaKP0aY2JhWIxls727X9VMMtjTlK8vE5RQ==",
|
||||
"requires": {
|
||||
"@xmpp/events": "^0.13.0"
|
||||
}
|
||||
},
|
||||
"@xmpp/xml": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@xmpp/xml/-/xml-0.13.0.tgz",
|
||||
"integrity": "sha512-bgKaUzzJXp8nXCQPzVRJLy1XZQlLrcmjzUe1V7127NcXJddEgk1Ie/esVhh1BUMlPgRdl7BCRQkYe40S6KuuXw==",
|
||||
"requires": {
|
||||
"ltx": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@xtuc/ieee754": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
||||
@ -3083,7 +2792,8 @@
|
||||
"events": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"evp_bytestokey": {
|
||||
"version": "1.0.3",
|
||||
@ -4497,11 +4207,6 @@
|
||||
"integrity": "sha512-h9ivI88e1lFNmTT4HovBN33Ysn0OIJG7IPG2mkpx2uniQXFWqo35QdiX7w0TovlUFXfW8aPFblP5/q0jlOr2sA==",
|
||||
"dev": true
|
||||
},
|
||||
"koa-compose": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz",
|
||||
"integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw=="
|
||||
},
|
||||
"kuler": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
@ -4615,11 +4320,6 @@
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"ltx": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ltx/-/ltx-3.0.0.tgz",
|
||||
"integrity": "sha512-bu3/4/ApUmMqVNuIkHaRhqVtEi6didYcBDIF56xhPRCzVpdztCipZ62CUuaxMlMBUzaVL93+4LZRqe02fuAG6A=="
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
||||
|
@ -31,8 +31,6 @@
|
||||
"dist/assets/style.css"
|
||||
],
|
||||
"dependencies": {
|
||||
"@xmpp/component": "^0.13.0",
|
||||
"@xmpp/jid": "^0.13.0",
|
||||
"async": "^3.2.2",
|
||||
"body-parser": "^1.19.0",
|
||||
"decache": "^4.6.0",
|
||||
@ -50,8 +48,6 @@
|
||||
"@types/got": "^9.6.12",
|
||||
"@types/node": "^16.11.6",
|
||||
"@types/winston": "^2.4.4",
|
||||
"@types/xmpp__component": "^0.13.0",
|
||||
"@types/xmpp__jid": "^1.3.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
||||
"@typescript-eslint/parser": "^4.29.0",
|
||||
"eslint": "^7.32.0",
|
||||
@ -86,7 +82,6 @@
|
||||
"clean": "rm -rf dist/* build/*",
|
||||
"clean:light": "rm -rf dist/*",
|
||||
"prepare": "npm run clean && npm run build",
|
||||
"build:bots": "npx tsc --build bots/tsconfig.json",
|
||||
"build:converse": "bash conversejs/build-conversejs.sh",
|
||||
"build:images": "mkdir -p dist/client/images && npx svgo -f public/images/ -o dist/client/images/",
|
||||
"build:webpack": "webpack --mode=production",
|
||||
@ -94,7 +89,7 @@
|
||||
"build:serverconverse": "mkdir -p dist/server/conversejs && cp conversejs/index.html dist/server/conversejs/",
|
||||
"build:prosodymodules": "mkdir -p dist/server/prosody-modules && cp -r prosody-modules/* dist/server/prosody-modules/",
|
||||
"build:styles": "sass assets:dist/assets",
|
||||
"build": "npm-run-all -s clean:light -p build:converse build:images build:webpack build:server build:serverconverse build:prosodymodules build:styles build:bots",
|
||||
"build": "npm-run-all -s clean:light -p build:converse build:images build:webpack build:server build:serverconverse build:prosodymodules build:styles",
|
||||
"lint": "npm-run-all -s lint:script lint:styles",
|
||||
"lint:script": "npx eslint --ext .js --ext .ts .",
|
||||
"lint:styles": "stylelint 'conversejs/**/*.scss' 'assets/**/*.css'",
|
||||
|
@ -3,28 +3,15 @@ For internal API, we will generate an api Key that must be provided as
|
||||
GET parameter for every API call.
|
||||
*/
|
||||
|
||||
async function _getKey ({ storageManager }: RegisterServerOptions, key: string): Promise<string> {
|
||||
let value: string = await storageManager.getData(key)
|
||||
async function getAPIKey ({ storageManager }: RegisterServerOptions): Promise<string> {
|
||||
let value: string = await storageManager.getData('APIKEY')
|
||||
if (!value) {
|
||||
value = Math.random().toString(36).slice(2, 12)
|
||||
await storageManager.storeData(key, value)
|
||||
await storageManager.storeData('APIKEY', value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
async function getAPIKey (options: RegisterServerOptions): Promise<string> {
|
||||
return _getKey(options, 'APIKEY')
|
||||
}
|
||||
|
||||
async function getExternalComponentKey (options: RegisterServerOptions, componentName: string): Promise<string> {
|
||||
if (!/^[A-Z]+$/.test(componentName)) {
|
||||
throw new Error('Invalid component name: ' + componentName)
|
||||
}
|
||||
const key = 'EXTERNALCOMPONENTKEY_' + componentName
|
||||
return _getKey(options, key)
|
||||
}
|
||||
|
||||
export {
|
||||
getAPIKey,
|
||||
getExternalComponentKey
|
||||
getAPIKey
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getProsodyConfig, getWorkingDir } from '../prosody/config'
|
||||
import { getProsodyConfig, getProsodyConfigContentForDiagnostic, getWorkingDir } from '../prosody/config'
|
||||
import { getProsodyAbout, testProsodyCorrectlyRunning } from '../prosody/ctl'
|
||||
import { newResult, TestResult } from './utils'
|
||||
import { getAPIKey } from '../apikey'
|
||||
@ -24,6 +24,7 @@ export async function diagProsody (test: string, options: RegisterServerOptions)
|
||||
let prosodyHost: string
|
||||
try {
|
||||
const wantedConfig = await getProsodyConfig(options)
|
||||
const filePath = wantedConfig.paths.config
|
||||
|
||||
result.messages.push(`Prosody will run on port '${wantedConfig.port}'`)
|
||||
prosodyPort = wantedConfig.port
|
||||
@ -49,44 +50,34 @@ export async function diagProsody (test: string, options: RegisterServerOptions)
|
||||
}
|
||||
result.messages.push(`Room content will be saved for '${wantedConfig.logExpiration.value}'`)
|
||||
|
||||
if (wantedConfig.bots.demobot) {
|
||||
result.messages.push(`The Demo bot is active for videos: ${wantedConfig.bots.demobot.join(', ')}`)
|
||||
}
|
||||
|
||||
const configFiles = wantedConfig.getConfigFiles()
|
||||
for (const configFile of configFiles) {
|
||||
const filePath = configFile.path
|
||||
const configFileKey = configFile.key
|
||||
|
||||
await fs.promises.access(filePath, fs.constants.R_OK) // throw an error if file does not exist.
|
||||
result.messages.push(`The prosody '${configFileKey}' configuration file (${filePath}) exists`)
|
||||
result.messages.push(`The prosody configuration file (${filePath}) exists`)
|
||||
const actualContent = await fs.promises.readFile(filePath, {
|
||||
encoding: 'utf-8'
|
||||
})
|
||||
|
||||
result.debug.push({
|
||||
title: `Current prosody '${configFileKey}' configuration`,
|
||||
title: 'Current prosody configuration',
|
||||
// we have to hide secret keys and other values.
|
||||
// But here, we haven't them for actualContent.
|
||||
// So we will use values in wantedConfig, hopping it is enough.
|
||||
message: wantedConfig.contentForDiagnostic(actualContent)
|
||||
message: getProsodyConfigContentForDiagnostic(wantedConfig, actualContent)
|
||||
})
|
||||
|
||||
const wantedContent = configFile.content
|
||||
const wantedContent = wantedConfig.content
|
||||
if (actualContent === wantedContent) {
|
||||
result.messages.push(`Prosody configuration file '${configFileKey}' content is correct.`)
|
||||
result.messages.push('Prosody configuration file content is correct.')
|
||||
} else {
|
||||
result.messages.push(`Prosody configuration file '${configFileKey}'' content is not correct.`)
|
||||
result.messages.push('Prosody configuration file content is not correct.')
|
||||
result.debug.push({
|
||||
title: `Prosody configuration '${configFileKey}' should be`,
|
||||
title: 'Prosody configuration should be',
|
||||
// we have to hide secret keys and other values:
|
||||
message: wantedConfig.contentForDiagnostic(wantedContent)
|
||||
message: getProsodyConfigContentForDiagnostic(wantedConfig)
|
||||
})
|
||||
return result
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
result.messages.push('Error when testing the prosody config: ' + (error as string))
|
||||
result.messages.push('Error when requiring the prosody config file: ' + (error as string))
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,8 @@ import { getBaseRouterRoute } from '../helpers'
|
||||
import { ProsodyFilePaths } from './config/paths'
|
||||
import { ConfigLogExpiration, ProsodyConfigContent } from './config/content'
|
||||
import { getProsodyDomain } from './config/domain'
|
||||
import { getAPIKey, getExternalComponentKey } from '../apikey'
|
||||
import { getAPIKey } from '../apikey'
|
||||
import type { ProsodyLogLevel } from './config/content'
|
||||
import { parseConfigDemoBotUUIDs } from './config/bots'
|
||||
|
||||
async function getWorkingDir (options: RegisterServerOptions): Promise<string> {
|
||||
const peertubeHelpers = options.peertubeHelpers
|
||||
@ -24,9 +23,9 @@ async function getWorkingDir (options: RegisterServerOptions): Promise<string> {
|
||||
/**
|
||||
* Creates the working dir if needed, and returns it.
|
||||
*/
|
||||
async function ensureWorkingDirs (options: RegisterServerOptions): Promise<string> {
|
||||
async function ensureWorkingDir (options: RegisterServerOptions): Promise<string> {
|
||||
const logger = options.peertubeHelpers.logger
|
||||
logger.debug('Calling ensureworkingDirs')
|
||||
logger.debug('Calling ensureworkingDir')
|
||||
|
||||
const paths = await getProsodyFilePaths(options)
|
||||
const dir = paths.dir
|
||||
@ -39,12 +38,10 @@ async function ensureWorkingDirs (options: RegisterServerOptions): Promise<strin
|
||||
await fs.promises.access(dir, fs.constants.W_OK) // will throw an error if no access
|
||||
logger.debug(`Write access ok on ${dir}`)
|
||||
|
||||
for (const path of [paths.data, paths.bots.dir]) {
|
||||
if (!fs.existsSync(path)) {
|
||||
logger.info(`The data dir ${path} does not exists, trying to create it`)
|
||||
await fs.promises.mkdir(path)
|
||||
logger.debug(`Working dir ${path} was created`)
|
||||
}
|
||||
if (!fs.existsSync(paths.data)) {
|
||||
logger.info(`The data dir ${paths.data} does not exists, trying to create it`)
|
||||
await fs.promises.mkdir(paths.data)
|
||||
logger.debug(`Working dir ${paths.data} was created`)
|
||||
}
|
||||
|
||||
return dir
|
||||
@ -62,61 +59,25 @@ async function getProsodyFilePaths (options: RegisterServerOptions): Promise<Pro
|
||||
log: path.resolve(dir, 'prosody.log'),
|
||||
config: path.resolve(dir, 'prosody.cfg.lua'),
|
||||
data: path.resolve(dir, 'data'),
|
||||
bots: {
|
||||
dir: path.resolve(dir, 'bots'),
|
||||
demobot: path.resolve(dir, 'bots', 'demobot.js')
|
||||
},
|
||||
modules: path.resolve(__dirname, '../../prosody-modules')
|
||||
}
|
||||
}
|
||||
|
||||
interface ProsodyConfigBots {
|
||||
demobot?: string[] // if the demo bot is activated, here are the video UUIDS where it will be.
|
||||
}
|
||||
|
||||
type ProsodyConfigFilesKey = 'prosody' | 'demobot'
|
||||
type ProsodyConfigFiles = Array<{
|
||||
key: ProsodyConfigFilesKey
|
||||
path: string
|
||||
interface ProsodyConfig {
|
||||
content: string
|
||||
}>
|
||||
|
||||
class ProsodyConfig {
|
||||
constructor (
|
||||
private readonly configFiles: ProsodyConfigFiles,
|
||||
public paths: ProsodyFilePaths,
|
||||
public host: string,
|
||||
public port: string,
|
||||
public baseApiUrl: string,
|
||||
public roomType: 'video' | 'channel',
|
||||
public logByDefault: boolean,
|
||||
public logExpiration: ConfigLogExpiration,
|
||||
public bots: ProsodyConfigBots,
|
||||
public valuesToHideInDiagnostic: {[key: string]: string}
|
||||
) {}
|
||||
|
||||
public getConfigFiles (): ProsodyConfigFiles {
|
||||
return this.configFiles
|
||||
paths: ProsodyFilePaths
|
||||
host: string
|
||||
port: string
|
||||
baseApiUrl: string
|
||||
roomType: 'video' | 'channel'
|
||||
logByDefault: boolean
|
||||
logExpiration: ConfigLogExpiration
|
||||
valuesToHideInDiagnostic: {[key: string]: string}
|
||||
}
|
||||
|
||||
public contentForDiagnostic (content: string): string {
|
||||
let r: string = content
|
||||
for (const key in this.valuesToHideInDiagnostic) {
|
||||
// replaceAll not available, using trick:
|
||||
r = r.split(this.valuesToHideInDiagnostic[key]).join(`***${key}***`)
|
||||
}
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
async function getProsodyConfig (options: RegisterServerOptions): Promise<ProsodyConfig> {
|
||||
const logger = options.peertubeHelpers.logger
|
||||
logger.debug('Calling getProsodyConfig')
|
||||
|
||||
let useExternalComponents = false
|
||||
const bots: ProsodyConfigBots = {}
|
||||
const valuesToHideInDiagnostic: {[key: string]: string} = {}
|
||||
|
||||
const settings = await options.settingsManager.getSettings([
|
||||
'prosody-port',
|
||||
'prosody-muc-log-by-default',
|
||||
@ -124,25 +85,20 @@ async function getProsodyConfig (options: RegisterServerOptions): Promise<Prosod
|
||||
'prosody-c2s',
|
||||
'prosody-room-type',
|
||||
'prosody-peertube-uri',
|
||||
'prosody-c2s-port',
|
||||
'prosody-component-port',
|
||||
'chat-videos-list'
|
||||
'prosody-c2s-port'
|
||||
])
|
||||
|
||||
const valuesToHideInDiagnostic: {[key: string]: string} = {}
|
||||
const port = (settings['prosody-port'] as string) || '52800'
|
||||
if (!/^\d+$/.test(port)) {
|
||||
throw new Error('Invalid port')
|
||||
}
|
||||
const externalComponentsPort = (settings['prosody-component-port'] as string) || '53470'
|
||||
if (!/^\d+$/.test(externalComponentsPort)) {
|
||||
throw new Error('Invalid external components port')
|
||||
}
|
||||
const logByDefault = (settings['prosody-muc-log-by-default'] as boolean) ?? true
|
||||
const logExpirationSetting = (settings['prosody-muc-expiration'] as string) ?? DEFAULTLOGEXPIRATION
|
||||
const enableC2s = (settings['prosody-c2s'] as boolean) || false
|
||||
const prosodyDomain = await getProsodyDomain(options)
|
||||
const paths = await getProsodyFilePaths(options)
|
||||
const roomType = (settings['prosody-room-type']) === 'channel' ? 'channel' : 'video'
|
||||
const roomType = settings['prosody-room-type'] === 'channel' ? 'channel' : 'video'
|
||||
|
||||
const apikey = await getAPIKey(options)
|
||||
valuesToHideInDiagnostic.APIKey = apikey
|
||||
@ -196,57 +152,19 @@ async function getProsodyConfig (options: RegisterServerOptions): Promise<Prosod
|
||||
logLevel = 'info'
|
||||
}
|
||||
config.setLog(logLevel)
|
||||
|
||||
const demoBotUUIDs = parseConfigDemoBotUUIDs((settings['chat-videos-list'] as string) || '')
|
||||
let demoBotContentObj: string = 'null'
|
||||
if (demoBotUUIDs?.length > 0) {
|
||||
useExternalComponents = true
|
||||
const componentSecret = await getExternalComponentKey(options, 'DEMOBOT')
|
||||
valuesToHideInDiagnostic.ComponentSecret = componentSecret
|
||||
config.useDemoBot(componentSecret)
|
||||
bots.demobot = demoBotUUIDs
|
||||
demoBotContentObj = JSON.stringify({
|
||||
rooms: demoBotUUIDs,
|
||||
service: 'xmpp://127.0.0.1:' + externalComponentsPort,
|
||||
domain: 'demobot.' + prosodyDomain,
|
||||
mucDomain: 'room.' + prosodyDomain,
|
||||
password: componentSecret
|
||||
})
|
||||
}
|
||||
let demoBotContent = '"use strict";\n'
|
||||
demoBotContent += 'Object.defineProperty(exports, "__esModule", { value: true });\n'
|
||||
demoBotContent += `function getConf () { return ${demoBotContentObj}; }` + '\n'
|
||||
demoBotContent += 'exports.getConf = getConf;\n'
|
||||
|
||||
if (useExternalComponents) {
|
||||
config.useExternalComponents(externalComponentsPort)
|
||||
}
|
||||
|
||||
const content = config.write()
|
||||
|
||||
return new ProsodyConfig(
|
||||
[
|
||||
{
|
||||
key: 'prosody',
|
||||
path: paths.config,
|
||||
content: content
|
||||
},
|
||||
{
|
||||
key: 'demobot',
|
||||
path: paths.bots.demobot,
|
||||
content: demoBotContent
|
||||
}
|
||||
],
|
||||
return {
|
||||
content,
|
||||
paths,
|
||||
prosodyDomain,
|
||||
port,
|
||||
baseApiUrl,
|
||||
host: prosodyDomain,
|
||||
roomType,
|
||||
logByDefault,
|
||||
logExpiration,
|
||||
bots,
|
||||
valuesToHideInDiagnostic
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function writeProsodyConfig (options: RegisterServerOptions): Promise<ProsodyConfig> {
|
||||
@ -254,19 +172,15 @@ async function writeProsodyConfig (options: RegisterServerOptions): Promise<Pros
|
||||
logger.debug('Calling writeProsodyConfig')
|
||||
|
||||
logger.debug('Ensuring that the working dir exists')
|
||||
await ensureWorkingDirs(options)
|
||||
await ensureWorkingDir(options)
|
||||
logger.debug('Computing the Prosody config content')
|
||||
const config = await getProsodyConfig(options)
|
||||
const content = config.content
|
||||
const fileName = config.paths.config
|
||||
|
||||
const configFiles = config.getConfigFiles()
|
||||
for (const configFile of configFiles) {
|
||||
const content = configFile.content
|
||||
const fileName = configFile.path
|
||||
|
||||
logger.info(`Writing prosody configuration file '${configFile.key}' to ${fileName}.`)
|
||||
logger.info(`Writing prosody configuration file to ${fileName}`)
|
||||
await fs.promises.writeFile(fileName, content)
|
||||
logger.debug(`Prosody configuration file '${configFile.key}' writen.`)
|
||||
}
|
||||
logger.debug('Prosody configuration file writen')
|
||||
|
||||
return config
|
||||
}
|
||||
@ -322,10 +236,20 @@ function readLogExpiration (options: RegisterServerOptions, logExpiration: strin
|
||||
}
|
||||
}
|
||||
|
||||
function getProsodyConfigContentForDiagnostic (config: ProsodyConfig, content?: string): string {
|
||||
let r: string = content ?? config.content
|
||||
for (const key in config.valuesToHideInDiagnostic) {
|
||||
// replaceAll not available, using trick:
|
||||
r = r.split(config.valuesToHideInDiagnostic[key]).join(`***${key}***`)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
export {
|
||||
getProsodyConfig,
|
||||
getWorkingDir,
|
||||
ensureWorkingDirs,
|
||||
ensureWorkingDir,
|
||||
getProsodyFilePaths,
|
||||
writeProsodyConfig
|
||||
writeProsodyConfig,
|
||||
getProsodyConfigContentForDiagnostic
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
function parseConfigDemoBotUUIDs (s: string): string[] {
|
||||
if (!s) {
|
||||
return []
|
||||
}
|
||||
let a = s.split('\n')
|
||||
// find lines that are like:
|
||||
// 6432f147-83c7-4fa3-b3b5-e49c2590e825 #!demobot
|
||||
a = a.filter(line => /#!demobot\b/.test(line))
|
||||
a = a.map(line => {
|
||||
return line.replace(/#.*$/, '')
|
||||
.replace(/^\s+/, '')
|
||||
.replace(/\s+$/, '')
|
||||
})
|
||||
return a.filter(line => line !== '')
|
||||
}
|
||||
|
||||
export {
|
||||
parseConfigDemoBotUUIDs
|
||||
}
|
@ -102,20 +102,17 @@ class ProsodyConfigVirtualHost extends ProsodyConfigBlock {
|
||||
|
||||
class ProsodyConfigComponent extends ProsodyConfigBlock {
|
||||
name: string
|
||||
type?: string
|
||||
type: string
|
||||
|
||||
constructor (name: string, type?: string) {
|
||||
constructor (type: string, name: string) {
|
||||
super(' ')
|
||||
this.type = type
|
||||
this.name = name
|
||||
}
|
||||
|
||||
write (): string {
|
||||
if (this.type !== undefined) {
|
||||
return `Component "${this.name}" "${this.type}"\n` + super.write()
|
||||
}
|
||||
return `Component "${this.name}"\n` + super.write()
|
||||
}
|
||||
}
|
||||
|
||||
type ProsodyLogLevel = 'debug' | 'info' | 'warn' | 'error'
|
||||
@ -126,7 +123,6 @@ class ProsodyConfigContent {
|
||||
authenticated?: ProsodyConfigVirtualHost
|
||||
anon: ProsodyConfigVirtualHost
|
||||
muc: ProsodyConfigComponent
|
||||
externalComponents: ProsodyConfigComponent[] = []
|
||||
log: string
|
||||
prosodyDomain: string
|
||||
|
||||
@ -136,7 +132,7 @@ class ProsodyConfigContent {
|
||||
this.log = ''
|
||||
this.prosodyDomain = prosodyDomain
|
||||
this.anon = new ProsodyConfigVirtualHost('anon.' + prosodyDomain)
|
||||
this.muc = new ProsodyConfigComponent('room.' + prosodyDomain, 'muc')
|
||||
this.muc = new ProsodyConfigComponent('muc', 'room.' + prosodyDomain)
|
||||
|
||||
this.global.set('daemonize', false)
|
||||
this.global.set('allow_registration', false)
|
||||
@ -285,21 +281,6 @@ class ProsodyConfigContent {
|
||||
this.muc.set('peertubelivechat_test_peertube_api_url', apiurl)
|
||||
}
|
||||
|
||||
useExternalComponents (componentsPort: string): void {
|
||||
this.global.set('component_ports', [componentsPort])
|
||||
this.global.set('component_interfaces', ['127.0.0.1', '::1'])
|
||||
}
|
||||
|
||||
useDemoBot (componentSecret: string): void {
|
||||
const demoBotComponent = new ProsodyConfigComponent('demobot.' + this.prosodyDomain)
|
||||
demoBotComponent.set('component_secret', componentSecret)
|
||||
|
||||
// If we want the bot to be moderator, should do the trick:
|
||||
// this.global.add('admins', 'demobot.' + this.prosodyDomain)
|
||||
|
||||
this.externalComponents.push(demoBotComponent)
|
||||
}
|
||||
|
||||
setLog (level: ProsodyLogLevel, syslog?: ProsodyLogLevel[]): void {
|
||||
let log = ''
|
||||
log += 'log = {\n'
|
||||
@ -328,11 +309,6 @@ class ProsodyConfigContent {
|
||||
content += '\n\n'
|
||||
content += this.muc.write()
|
||||
content += '\n\n'
|
||||
this.externalComponents.forEach((externalComponent) => {
|
||||
content += '\n\n'
|
||||
content += externalComponent.write()
|
||||
content += '\n\n'
|
||||
})
|
||||
return content
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,6 @@ interface ProsodyFilePaths {
|
||||
log: string
|
||||
config: string
|
||||
data: string
|
||||
bots: {
|
||||
dir: string
|
||||
demobot: string
|
||||
}
|
||||
modules: string
|
||||
}
|
||||
|
||||
|
@ -113,24 +113,21 @@ async function testProsodyCorrectlyRunning (options: RegisterServerOptions): Pro
|
||||
|
||||
try {
|
||||
const wantedConfig = await getProsodyConfig(options)
|
||||
const configFiles = wantedConfig.getConfigFiles()
|
||||
for (const configFile of configFiles) {
|
||||
const filePath = configFile.path
|
||||
const filePath = wantedConfig.paths.config
|
||||
|
||||
await fs.promises.access(filePath, fs.constants.R_OK) // throw an error if file does not exist.
|
||||
result.messages.push(`The prosody configuration file (${configFile.key}: ${filePath}) exists`)
|
||||
result.messages.push(`The prosody configuration file (${filePath}) exists`)
|
||||
const actualContent = await fs.promises.readFile(filePath, {
|
||||
encoding: 'utf-8'
|
||||
})
|
||||
|
||||
const wantedContent = configFile.content
|
||||
const wantedContent = wantedConfig.content
|
||||
if (actualContent === wantedContent) {
|
||||
result.messages.push(`Prosody configuration file '${configFile.key}' content is correct.`)
|
||||
result.messages.push('Prosody configuration file content is correct.')
|
||||
} else {
|
||||
result.messages.push(`Prosody configuration file '${configFile.key}' content is not correct.`)
|
||||
result.messages.push('Prosody configuration file content is not correct.')
|
||||
return result
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
result.messages.push('Error when requiring the prosody config file: ' + (error as string))
|
||||
return result
|
||||
|
@ -359,22 +359,6 @@ archiving for a specific room, by editing its properties.
|
||||
</ul>`
|
||||
})
|
||||
|
||||
registerSetting({
|
||||
name: 'prosody-component-port',
|
||||
label: 'The port to be use for external components',
|
||||
type: 'input',
|
||||
default: '53470',
|
||||
private: true,
|
||||
descriptionHTML:
|
||||
`The port that will be used for extra components used by the builtin Prosody server.<br>
|
||||
This is only used when one of these special features is used:<br>
|
||||
<ul>
|
||||
<li>Demo bot: this is a hidden feature, for demonstration purposes. See the documentation for more information.</li>
|
||||
</ul><br>
|
||||
Change it if this port is already in use on your server.
|
||||
`
|
||||
})
|
||||
|
||||
registerSetting({
|
||||
name: 'prosody-c2s',
|
||||
label: 'Enable client to server connections',
|
||||
|
Loading…
x
Reference in New Issue
Block a user