UNPKG

botium-core

Version:
220 lines (196 loc) 7.23 kB
const util = require('util') const opn = require('opn') const path = require('path') const async = require('async') const findRoot = require('find-root') const HttpServer = require('tiny-server') const socket = require('socket.io') const debug = require('debug')('botium-WebSpeechContainer') const Capabilities = require('../Capabilities') const Events = require('../Events') const BaseContainer = require('./BaseContainer') const BotiumMockMessage = require('../mocks/BotiumMockMessage') const botiumPackageRootDir = findRoot() module.exports = class WebSpeechContainer extends BaseContainer { Validate () { return super.Validate().then(() => { this._AssertCapabilityExists(Capabilities.WEBSPEECH_SERVER_PORT) this._AssertCapabilityExists(Capabilities.WEBSPEECH_LANGUAGE) }) } Build () { this.browserConfig = { WEBSPEECH_LANGUAGE: this.caps[Capabilities.WEBSPEECH_LANGUAGE], WEBSPEECH_PITCH: this.caps[Capabilities.WEBSPEECH_PITCH], WEBSPEECH_RATE: this.caps[Capabilities.WEBSPEECH_RATE], WEBSPEECH_VOLUME: this.caps[Capabilities.WEBSPEECH_VOLUME], WEBSPEECH_VOICE: this.caps[Capabilities.WEBSPEECH_VOICE] } return new Promise((resolve, reject) => { async.series([ (baseComplete) => { super.Build().then(() => baseComplete()).catch(baseComplete) }, (httpServerComplete) => { this.httpServer = new HttpServer(path.resolve(botiumPackageRootDir, 'src', 'containers', 'webspeech')) this.io = socket(this.httpServer) this.io.on('connection', (clientSocket) => { debug('browser connected to socket') this.clientSocket = clientSocket this.clientSocket.on('disconnect', () => { debug('browser disconnecteded from socket') this.clientSocket = null }) this.clientSocket.on('log', (msg) => { debug(`browser log: ${msg}`) }) this.clientSocket.on('botsays', (msg) => { debug(`browser botsays: ${msg}`) if (msg) { const botMsg = { sender: 'bot', messageText: msg } this._QueueBotSays(new BotiumMockMessage(botMsg)) } }) this.clientSocket.on('usersaid', (msg) => { if (this.usersaidResolve) { this.usersaidResolve() this.usersaidResolve = null } }) this.clientSocket.emit('startrecognize', this.browserConfig) if (this.connectResolve) { this.connectResolve() this.connectResolve = null } }) this.httpServer.listen(this.caps[Capabilities.WEBSPEECH_SERVER_PORT], () => { debug(`waiting for browser connection on port ${this.caps[Capabilities.WEBSPEECH_SERVER_PORT]}`) httpServerComplete() }).once('error', (err) => { if (err.code === 'EADDRINUSE') { debug(`port ${this.caps[Capabilities.WEBSPEECH_SERVER_PORT]} already in use.`) httpServerComplete(err) } }) } ], (err) => { if (err) { return reject(new Error(`Cannot build webspeech container: ${util.inspect(err)}`)) } resolve(this) }) }) } Start () { this.eventEmitter.emit(Events.CONTAINER_STARTING, this) return new Promise((resolve, reject) => { async.series([ (baseComplete) => { super.Start().then(() => baseComplete()).catch(baseComplete) }, (opnComplete) => { if (this.clientSocket) { opnComplete() } else { this.connectResolve = opnComplete const opnOptions = { } if (this.caps[Capabilities.WEBSPEECH_BROWSER_APP]) { opnOptions.app = this.caps[Capabilities.WEBSPEECH_BROWSER_APP] } const browserUrl = `http://127.0.0.1:${this.caps[Capabilities.WEBSPEECH_SERVER_PORT]}/WebSpeechContainer.html` debug(`opening browser process to point to url ${browserUrl}`) opn(browserUrl, opnOptions).then((cp) => { debug('browser process running') this.clientProcess = cp }) } } ], (err) => { if (err) { this.eventEmitter.emit(Events.CONTAINER_START_ERROR, this, err) return reject(new Error(`Start failed ${util.inspect(err)}`)) } this.eventEmitter.emit(Events.CONTAINER_STARTED, this) resolve(this) }) }) } UserSays (mockMsg) { return new Promise((resolve, reject) => { if (this.clientSocket) { this.usersaidResolve = () => { this.eventEmitter.emit(Events.MESSAGE_SENTTOBOT, this, mockMsg) resolve(this) } this.clientSocket.emit('usersays', this.browserConfig, mockMsg) } else { this.eventEmitter.emit(Events.MESSAGE_SENDTOBOT_ERROR, this, 'browser connection not online') reject(new Error('browser connection not online')) } }) } Stop () { this.eventEmitter.emit(Events.CONTAINER_STOPPING, this) return new Promise((resolve, reject) => { async.series([ (baseComplete) => { super.Stop().then(() => baseComplete()).catch(baseComplete) } ], (err) => { if (err) { this.eventEmitter.emit(Events.CONTAINER_STOP_ERROR, this, err) return reject(new Error(`Stop failed ${util.inspect(err)}`)) } this.eventEmitter.emit(Events.CONTAINER_STOPPED, this) resolve(this) }) }) } Clean () { this.eventEmitter.emit(Events.CONTAINER_CLEANING, this) return new Promise((resolve, reject) => { async.series([ (baseComplete) => { super.Clean().then(() => baseComplete()).catch(baseComplete) }, (httpServerStopped) => { this.io = null if (this.clientSocket) { if (this.caps[Capabilities.WEBSPEECH_CLOSEBROWSER]) { this.clientSocket.emit('close') } this.clientSocket.disconnect(true) this.clientSocket = null } if (this.httpServer) { debug('closing http server') this.httpServer.close(() => { debug('stopped browser listening.') this.httpServer = null httpServerStopped() }) } else { httpServerStopped() } }, (clientProcessStopped) => { if (this.caps[Capabilities.WEBSPEECH_CLOSEBROWSER]) { if (this.clientProcess) { debug('killing browser process') this.clientProcess.kill() } } this.clientProcess = null clientProcessStopped() } ], (err) => { if (err) { this.eventEmitter.emit(Events.CONTAINER_CLEAN_ERROR, this, err) return reject(new Error(`Cleanup failed ${util.inspect(err)}`)) } this.eventEmitter.emit(Events.CONTAINER_CLEANED, this) resolve(this) }) }) } }