Demo Bot: WIP.
This commit is contained in:
		
							
								
								
									
										115
									
								
								bots/bots.ts
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								bots/bots.ts
									
									
									
									
									
								
							@ -1,78 +1,65 @@
 | 
			
		||||
import * as path from 'path'
 | 
			
		||||
import { BotsConfig } from './lib/config'
 | 
			
		||||
import { logger } from './lib/logger'
 | 
			
		||||
import { ComponentBot } from './lib/bot/component'
 | 
			
		||||
import { DemoBot } from './lib/bot/demobot'
 | 
			
		||||
 | 
			
		||||
let demoBotConfigFile = process.argv[2]
 | 
			
		||||
if (!demoBotConfigFile) {
 | 
			
		||||
if (!process.argv[2]) {
 | 
			
		||||
  throw new Error('Missing parameter: the demobot configuration file path')
 | 
			
		||||
}
 | 
			
		||||
demoBotConfigFile = path.resolve(demoBotConfigFile)
 | 
			
		||||
const botsConfig = new BotsConfig(process.argv[2])
 | 
			
		||||
 | 
			
		||||
// Not necessary, but just in case: perform some path checking...
 | 
			
		||||
function checkBotConfigFilePath (configPath: string): void {
 | 
			
		||||
  const parts = configPath.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('demobot configuration file path seems invalid (not in peertube-plugin-livechat folder).')
 | 
			
		||||
const runningBots: ComponentBot[] = []
 | 
			
		||||
 | 
			
		||||
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 DemoBot(
 | 
			
		||||
      'DemoBot',
 | 
			
		||||
      {
 | 
			
		||||
        service: config.service,
 | 
			
		||||
        domain: config.domain,
 | 
			
		||||
        password: config.password
 | 
			
		||||
      },
 | 
			
		||||
      config.rooms,
 | 
			
		||||
      'DemoBot' // FIXME: handle the case where the nick is already taken.
 | 
			
		||||
    )
 | 
			
		||||
    runningBots.push(instance)
 | 
			
		||||
    instance.connect().catch(err => { throw err })
 | 
			
		||||
  }
 | 
			
		||||
  if (parts[parts.length - 1] !== 'demobot.js') {
 | 
			
		||||
    throw new Error('demobot configuration file path seems invalid (filename is not demobot.js).')
 | 
			
		||||
  if (!atLeastOne) {
 | 
			
		||||
    logger.info('No bot to launch, exiting.')
 | 
			
		||||
    process.exit(0)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
checkBotConfigFilePath(demoBotConfigFile)
 | 
			
		||||
 | 
			
		||||
const demoBotConf = require(demoBotConfigFile).getConf()
 | 
			
		||||
if (!demoBotConf || !demoBotConf.UUIDs || !demoBotConf.UUIDs.length) {
 | 
			
		||||
async function shutdown (): Promise<void> {
 | 
			
		||||
  logger.info('Shutdown...')
 | 
			
		||||
  for (const bot of runningBots) {
 | 
			
		||||
    logger.info('Stopping the bot ' + bot.botName + '...')
 | 
			
		||||
    await bot.stop()
 | 
			
		||||
  }
 | 
			
		||||
  process.exit(0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const { component, xml } = require('@xmpp/component')
 | 
			
		||||
const xmpp = component({
 | 
			
		||||
  service: demoBotConf.service,
 | 
			
		||||
  domain: demoBotConf.domain,
 | 
			
		||||
  password: demoBotConf.password
 | 
			
		||||
})
 | 
			
		||||
const roomId = `${demoBotConf.UUIDs[0] as string}@${demoBotConf.mucDomain as string}`
 | 
			
		||||
 | 
			
		||||
xmpp.on('error', (err: any) => {
 | 
			
		||||
  console.error(err)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
xmpp.on('offline', () => {
 | 
			
		||||
  console.log('offline')
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
xmpp.on('stanza', async (stanza: any) => {
 | 
			
		||||
  console.log('stanza received' + (stanza?.toString ? ': ' + (stanza.toString() as string) : ''))
 | 
			
		||||
  // if (stanza.is('message')) {
 | 
			
		||||
  //   console.log('stanza was a message: ' + (stanza.toString() as string))
 | 
			
		||||
  // }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
xmpp.on('online', async (address: any) => {
 | 
			
		||||
  console.log('Online with address: ' + JSON.stringify(address))
 | 
			
		||||
 | 
			
		||||
  const presence = xml(
 | 
			
		||||
    'presence',
 | 
			
		||||
    {
 | 
			
		||||
      from: address.toString(),
 | 
			
		||||
      to: roomId + '/DemoBot'
 | 
			
		||||
    },
 | 
			
		||||
    xml('x', {
 | 
			
		||||
      xmlns: 'http://jabber.org/protocol/muc'
 | 
			
		||||
// 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}`)
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
  )
 | 
			
		||||
  console.log('Sending presence...: ' + (presence.toString() as string))
 | 
			
		||||
  await xmpp.send(presence)
 | 
			
		||||
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    const message = xml(
 | 
			
		||||
      'message',
 | 
			
		||||
      { type: 'groupchat', to: roomId, from: address.toString() },
 | 
			
		||||
      xml('body', {}, 'Hello world')
 | 
			
		||||
    )
 | 
			
		||||
    console.log('Sending message...: ' + (message.toString() as string))
 | 
			
		||||
    xmpp.send(message)
 | 
			
		||||
  }, 1000)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
xmpp.start().catch(console.error)
 | 
			
		||||
start(botsConfig).catch((err) => {
 | 
			
		||||
  logger.error(`Function start failed: ${err as string}`)
 | 
			
		||||
  process.exit(1)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										82
									
								
								bots/lib/bot/component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								bots/lib/bot/component.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
/* eslint-disable no-void */
 | 
			
		||||
import { logger } from '../logger'
 | 
			
		||||
import { XMPP, XMPPXmlFunction, XMPPStanza, XMPPAddress } from './types'
 | 
			
		||||
 | 
			
		||||
const { component, xml } = require('@xmpp/component')
 | 
			
		||||
 | 
			
		||||
interface ComponentConnectionConfig {
 | 
			
		||||
  service: string
 | 
			
		||||
  domain: string
 | 
			
		||||
  password: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class ComponentBot {
 | 
			
		||||
  protected xmpp?: XMPP
 | 
			
		||||
  protected address?: XMPPAddress
 | 
			
		||||
 | 
			
		||||
  constructor (
 | 
			
		||||
    public readonly botName: string,
 | 
			
		||||
    protected readonly connectionConfig: ComponentConnectionConfig
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  protected xml: XMPPXmlFunction = (...args) => xml(...args)
 | 
			
		||||
 | 
			
		||||
  public async connect (): Promise<void> {
 | 
			
		||||
    this.xmpp = component({
 | 
			
		||||
      service: this.connectionConfig.service,
 | 
			
		||||
      domain: this.connectionConfig.domain,
 | 
			
		||||
      password: this.connectionConfig.password
 | 
			
		||||
    }) as XMPP
 | 
			
		||||
 | 
			
		||||
    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 ? ': ' + stanza.toString() : ''))
 | 
			
		||||
      if (stanza.is('message')) {
 | 
			
		||||
        void this.onMessage(stanza)
 | 
			
		||||
      }
 | 
			
		||||
      if (stanza.is('presence')) {
 | 
			
		||||
        void this.onPresence(stanza)
 | 
			
		||||
      }
 | 
			
		||||
      if (stanza.is('iq')) {
 | 
			
		||||
        void this.onIq(stanza)
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    this.xmpp.on('online', (address: XMPPAddress) => {
 | 
			
		||||
      logger.debug('Online with address' + address.toString())
 | 
			
		||||
 | 
			
		||||
      this.address = address
 | 
			
		||||
      void this.onOnline()
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    this.xmpp.start()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async stop (): Promise<any> {
 | 
			
		||||
    const p = new Promise((resolve) => {
 | 
			
		||||
      this.xmpp?.on('offline', () => {
 | 
			
		||||
        logger.info(`Stoppping process: ${this.botName} is now offline.`)
 | 
			
		||||
        resolve(true)
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
    await this.xmpp?.stop()
 | 
			
		||||
    await p
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected async onMessage (_stanza: XMPPStanza): Promise<void> {}
 | 
			
		||||
  protected async onIq (_stanza: XMPPStanza): Promise<void> {}
 | 
			
		||||
  protected async onPresence (_stanza: XMPPStanza): Promise<void> {}
 | 
			
		||||
  protected async onOnline (): Promise<void> {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  ComponentConnectionConfig,
 | 
			
		||||
  ComponentBot
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								bots/lib/bot/demobot.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								bots/lib/bot/demobot.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
import { RoomComponentBot } from './room'
 | 
			
		||||
 | 
			
		||||
class DemoBot extends RoomComponentBot {
 | 
			
		||||
  protected async onRoomJoin (roomId: string, nick: string): Promise<void> {
 | 
			
		||||
    await this.sendGroupchat(roomId, `Hello ${nick}! I'm the DemoBot, I'm here to demonstrate the chatroom.`)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  DemoBot
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								bots/lib/bot/room.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								bots/lib/bot/room.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,132 @@
 | 
			
		||||
import { ComponentBot, ComponentConnectionConfig } from './component'
 | 
			
		||||
import { XMPPStanza } from './types'
 | 
			
		||||
import { logger } from '../logger'
 | 
			
		||||
 | 
			
		||||
interface RoomComponentBotRoomDescription {
 | 
			
		||||
  jid: string
 | 
			
		||||
  nick: string
 | 
			
		||||
  users: Map<string, {
 | 
			
		||||
    // TODO: add the current user status somewhere.
 | 
			
		||||
    nick: string
 | 
			
		||||
  }>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class RoomComponentBot extends ComponentBot {
 | 
			
		||||
  protected readonly rooms: {[jid: string]: RoomComponentBotRoomDescription} = {}
 | 
			
		||||
 | 
			
		||||
  constructor (
 | 
			
		||||
    botName: string,
 | 
			
		||||
    connectionConfig: ComponentConnectionConfig,
 | 
			
		||||
    roomIds: string[],
 | 
			
		||||
    protected readonly nick: string
 | 
			
		||||
  ) {
 | 
			
		||||
    super(botName, connectionConfig)
 | 
			
		||||
    for (const roomId of roomIds) {
 | 
			
		||||
      this.rooms[roomId] = {
 | 
			
		||||
        jid: roomId,
 | 
			
		||||
        nick: nick,
 | 
			
		||||
        users: new Map()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async onOnline (): Promise<void> {
 | 
			
		||||
    for (const roomId in this.rooms) {
 | 
			
		||||
      const room = this.rooms[roomId]
 | 
			
		||||
      logger.debug(`Connecting to room ${room.jid}...`)
 | 
			
		||||
      const presence = this.xml(
 | 
			
		||||
        'presence',
 | 
			
		||||
        {
 | 
			
		||||
          from: this.address?.toString(),
 | 
			
		||||
          to: room.jid + '/' + room.nick
 | 
			
		||||
        },
 | 
			
		||||
        this.xml('x', {
 | 
			
		||||
          xmlns: 'http://jabber.org/protocol/muc'
 | 
			
		||||
        })
 | 
			
		||||
      )
 | 
			
		||||
      await this.xmpp?.send(presence)
 | 
			
		||||
    }
 | 
			
		||||
    await super.onOnline()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected async onPresence (stanza: XMPPStanza): Promise<void> {
 | 
			
		||||
    const [stanzaRoomId, stanzaNick] = stanza.attrs?.from.split('/')
 | 
			
		||||
    if (this.rooms[stanzaRoomId]) {
 | 
			
		||||
      await this.onRoomPresence(stanzaRoomId, stanza, stanzaNick)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async sendGroupchat (roomId: string, msg: string): Promise<void> {
 | 
			
		||||
    const room = this.rooms[roomId]
 | 
			
		||||
    if (!room) {
 | 
			
		||||
      logger.error('Trying to send a groupchat on an unknown room: ' + roomId)
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    const message = this.xml(
 | 
			
		||||
      'message',
 | 
			
		||||
      {
 | 
			
		||||
        type: 'groupchat',
 | 
			
		||||
        to: room.jid,
 | 
			
		||||
        from: this.address?.toString()
 | 
			
		||||
      },
 | 
			
		||||
      this.xml('body', {}, msg)
 | 
			
		||||
    )
 | 
			
		||||
    logger.debug('Sending message...: ' + (message.toString() as string))
 | 
			
		||||
    await this.xmpp?.send(message)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async stop (): Promise<any> {
 | 
			
		||||
    for (const roomId in this.rooms) {
 | 
			
		||||
      const room = this.rooms[roomId]
 | 
			
		||||
      logger.debug(`Leaving room ${room.jid}...`)
 | 
			
		||||
      const presence = this.xml(
 | 
			
		||||
        'presence',
 | 
			
		||||
        {
 | 
			
		||||
          from: this.address?.toString(),
 | 
			
		||||
          to: room.jid + '/' + room.nick,
 | 
			
		||||
          type: 'unavailable'
 | 
			
		||||
        }
 | 
			
		||||
      )
 | 
			
		||||
      // FIXME: should wait for a presence stanza from the server.
 | 
			
		||||
      await this.xmpp?.send(presence)
 | 
			
		||||
    }
 | 
			
		||||
    await super.stop()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected async onRoomPresence (
 | 
			
		||||
    roomId: string,
 | 
			
		||||
    stanza: XMPPStanza,
 | 
			
		||||
    nick?: string
 | 
			
		||||
  ): Promise<any> {
 | 
			
		||||
    const room = this.rooms[roomId]
 | 
			
		||||
    if (!room) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    if (!nick) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    const isPresent = stanza.attrs?.type !== 'unavailable'
 | 
			
		||||
    // FIXME: selfPresence should better be tested by searching status=110
 | 
			
		||||
    const selfPresence = room.nick === nick
 | 
			
		||||
    if (!isPresent) {
 | 
			
		||||
      room.users.delete(nick)
 | 
			
		||||
      if (!selfPresence) {
 | 
			
		||||
        await this.onRoomPart(roomId, nick)
 | 
			
		||||
      }
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    room.users.set(nick, {
 | 
			
		||||
      nick
 | 
			
		||||
    })
 | 
			
		||||
    if (!selfPresence) {
 | 
			
		||||
      await this.onRoomJoin(roomId, nick)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected async onRoomJoin (_roomId: string, _nick: string): Promise<void> {}
 | 
			
		||||
  protected async onRoomPart (_roomId: string, _nick: string): Promise<void> {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  RoomComponentBot
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								bots/lib/bot/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								bots/lib/bot/types.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
import { EventEmitter } from 'events'
 | 
			
		||||
 | 
			
		||||
export interface XMPP extends EventEmitter {
 | 
			
		||||
  send: (xml: any) => any
 | 
			
		||||
  start: () => any
 | 
			
		||||
  stop: () => Promise<any>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface XMPPAddress {
 | 
			
		||||
  toString: () => string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type XMPPStanzaType = 'message' | 'iq' | 'presence'
 | 
			
		||||
 | 
			
		||||
export interface XMPPStanza {
 | 
			
		||||
  attrs: any
 | 
			
		||||
  is: (type: XMPPStanzaType) => boolean
 | 
			
		||||
  toString: () => string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type XMPPXmlFunction = (type: string, attrs: object, content?: any) => any
 | 
			
		||||
							
								
								
									
										88
									
								
								bots/lib/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								bots/lib/config.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,88 @@
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								bots/lib/logger.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								bots/lib/logger.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
@ -198,7 +198,7 @@ async function getProsodyConfig (options: RegisterServerOptions): Promise<Prosod
 | 
			
		||||
  config.setLog(logLevel)
 | 
			
		||||
 | 
			
		||||
  const demoBotUUIDs = parseConfigDemoBotUUIDs((settings['chat-videos-list'] as string) || '')
 | 
			
		||||
  let demoBotContentObj: string = JSON.stringify({})
 | 
			
		||||
  let demoBotContentObj: string = 'null'
 | 
			
		||||
  if (demoBotUUIDs?.length > 0) {
 | 
			
		||||
    useExternalComponents = true
 | 
			
		||||
    const componentSecret = await getExternalComponentKey(options, 'DEMOBOT')
 | 
			
		||||
@ -206,7 +206,7 @@ async function getProsodyConfig (options: RegisterServerOptions): Promise<Prosod
 | 
			
		||||
    config.useDemoBot(componentSecret)
 | 
			
		||||
    bots.demobot = demoBotUUIDs
 | 
			
		||||
    demoBotContentObj = JSON.stringify({
 | 
			
		||||
      UUIDs: demoBotUUIDs,
 | 
			
		||||
      rooms: demoBotUUIDs.map((uuid) => `${uuid}@room.${prosodyDomain}`),
 | 
			
		||||
      service: 'xmpp://127.0.0.1:' + externalComponentsPort,
 | 
			
		||||
      domain: 'demobot.' + prosodyDomain,
 | 
			
		||||
      mucDomain: 'room.' + prosodyDomain,
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user