提交 b6aafe59 编写于 作者: Huan (李卓桓)'s avatar Huan (李卓桓)

remove socket.io library, use native WebSocket with ws (#502)

上级 152d1f5b
......@@ -16,21 +16,25 @@
* limitations under the License.
*
*/
import * as io from 'socket.io'
import * as https from 'https'
import * as bodyParser from 'body-parser'
import * as express from 'express'
import { EventEmitter } from 'events'
import * as express from 'express'
import * as https from 'https'
import * as WebSocket from 'ws'
import { log } from '../config'
export interface WechatyBroEvent {
name: string,
data: string | object,
}
export class Server extends EventEmitter {
private express: express.Application
private httpsServer: https.Server | null
public socketServer: SocketIO.Server | null
public socketClient: SocketIO.Socket | null
public socketServer: WebSocket.Server | null
public socketClient: WebSocket | null
constructor(private port: number) {
super()
......@@ -44,7 +48,7 @@ export class Server extends EventEmitter {
try {
this.createExpress()
await this.createHttpsServer(this.express)
this.createSocketIo(this.httpsServer)
this.createWebSocketServer(this.httpsServer)
return
......@@ -105,30 +109,32 @@ export class Server extends EventEmitter {
/**
* Socket IO
*/
public createSocketIo(httpsServer): SocketIO.Server {
this.socketServer = io.listen(httpsServer, {
// log: true
public createWebSocketServer(httpsServer): WebSocket.Server {
this.socketServer = new WebSocket.Server({
server: httpsServer,
})
this.socketServer.sockets.on('connection', (s) => {
log.verbose('PuppetWebServer', 'createSocketIo() got connection from browser')
// console.log(s.handshake)
this.socketServer.on('connection', client => {
log.verbose('PuppetWebServer', 'createWebSocketServer() got connection from browser')
if (this.socketClient) {
log.warn('PuppetWebServer', 'createSocketIo() on(connection) there already has a this.socketClient')
log.warn('PuppetWebServer', 'createWebSocketServer() on(connection) there already has a this.socketClient')
this.socketClient = null // close() ???
}
this.socketClient = s
this.initEventsFromClient(s)
this.socketClient = client
this.initEventsFromClient(client)
})
return this.socketServer
}
private initEventsFromClient(client: SocketIO.Socket): void {
private initEventsFromClient(client: WebSocket): void {
log.verbose('PuppetWebServer', 'initEventFromClient()')
this.emit('connection', client)
client.on('open', () => {
log.silly('PuppetWebServer', 'initEventsFromClient() on(open) WebSocket opened')
})
client.on('disconnect', e => {
log.silly('PuppetWebServer', 'initEventsFromClient() on(disconnect) socket.io disconnect: %s', e)
client.on('close', e => {
log.silly('PuppetWebServer', 'initEventsFromClient() on(disconnect) WebSocket disconnect: %s', e)
// 1. Browser reload / 2. Lost connection(Bad network)
this.socketClient = null
this.emit('disconnect', e)
......@@ -139,23 +145,27 @@ export class Server extends EventEmitter {
log.error('PuppetWebServer', 'initEventsFromClient() on(error): %s', e.stack)
})
// Events from Wechaty@Broswer --to--> Server
; // MUST KEEP: seprator
[
'message',
'scan',
'login',
'logout',
'log',
'unload', // @depreciated 20160825 zixia
// when `unload` there should always be a `disconnect` event?
'ding',
].map(e => {
client.on(e, data => {
// log.silly('PuppetWebServer', `initEventsFromClient() forward client event[${e}](${data}) from browser by emit it`)
this.emit(e, data)
})
client.on('message', data => {
const obj = JSON.parse(data as string) as WechatyBroEvent
this.emit(obj.name, obj.data)
})
// Events from Wechaty@Broswer --to--> Server
// ; // MUST KEEP: seprator
// [
// 'message',
// 'scan',
// 'login',
// 'logout',
// 'log',
// 'unload', // @depreciated 20160825 zixia
// // when `unload` there should always be a `disconnect` event?
// 'ding',
// ].map(e => {
// client.on(e, data => {
// // log.silly('PuppetWebServer', `initEventsFromClient() forward client event[${e}](${data}) from browser by emit it`)
// this.emit(e, data)
// })
// })
return
}
......@@ -181,3 +191,6 @@ export class Server extends EventEmitter {
}
export default Server
export {
Server as PuppetWebServer,
}
......@@ -146,14 +146,15 @@
*/
function emit(event, data) {
var eventsBuf = WechatyBro.vars.eventsBuf
if (!eventsBuf.map) {
if (!Array.isArray(eventsBuf)) {
throw new Error('WechatyBro.vars.eventsBuf must be a Array')
}
if (event) {
eventsBuf.unshift([event, data])
}
var socket = WechatyBro.vars.socket
if (!socket) {
// readyState: A value of 1 indicates that the connection is established and communication is possible.
if (!socket || socket.readyState !== 1) {
clog('WechatyBro.vars.socket not ready')
return setTimeout(emit, 1000) // resent eventsBuf after 1000ms
}
......@@ -165,8 +166,15 @@
var eventData = eventsBuf.pop()
if (eventData && eventData.map && eventData.length===2) {
clog('emiting ' + eventData[0])
socket.emit(eventData[0], eventData[1])
} else { clog('WechatyBro.emit() got invalid eventData: ' + eventData[0] + ', ' + eventData[1] + ', length: ' + eventData.length) }
// socket.emit(eventData[0], eventData[1])
var obj = {
name: eventData[0],
data: eventData[1],
}
socket.send(JSON.stringify(obj))
} else {
clog('WechatyBro.emit() got invalid eventData: ' + eventData[0] + ', ' + eventData[1] + ', length: ' + eventData.length)
}
}
if (bufLen > 1) { clog('WechatyBro.vars.eventsBuf[' + bufLen + '] all sent') }
......@@ -380,31 +388,34 @@
}
function connectSocket() {
log('connectSocket()')
if (typeof io !== 'function') {
log('connectSocket: io not found. loading lib...')
// http://stackoverflow.com/a/3248500/1123955
var script = document.createElement('script')
script.onload = function() {
log('socket io lib loaded.')
connectSocket()
/*global socket*/ // WechatyBro global variable: socket
var socket = WechatyBro.vars.socket = new WebSocket('wss://127.0.0.1:' + port)
socket.onmessage = function(messageEvent) {
var data = messageEvent.data
log('socket.onmessage: ' + data)
var recvObj = JSON.parse(data)
var name = recvObj.name
var data = recvObj.data
switch (name) {
// ding -> dong. for test & live check purpose
// ping/pong are reserved by socket.io https://github.com/socketio/socket.io/issues/2414
case 'ding':
var obj = {
name: 'dong',
data: data,
}
socket.send(JSON.stringify(obj))
break
default:
clog('unknown event name: ' + name)
}
script.src = '//cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.5/socket.io.min.js'
document.getElementsByTagName('head')[0].appendChild(script)
return // wait to be called via script.onload()
}
/*global io*/ // WechatyBro global variable: socket
var socket = WechatyBro.vars.socket = io.connect('wss://127.0.0.1:' + port/*, {transports: ['websocket']}*/)
// ding -> dong. for test & live check purpose
// ping/pong are reserved by socket.io https://github.com/socketio/socket.io/issues/2414
socket.on('ding', function(data) {
log('received socket io event: ding(' + data + '). emit dong...')
socket.emit('dong', data)
})
socket.on('connect' , function(e) { clog('connected to server:' + e) })
socket.on('disconnect', function(e) { clog('socket disconnect:' + e) })
socket.onopen = function(e) { clog('connected to server:' + e) }
socket.onclose = function(e) { clog('socket disconnect:' + e) }
socket.onerror = function(e) { clog('WebSocket error:' + e) }
}
/**
......
......@@ -16,14 +16,17 @@
* limitations under the License.
*
*/
import { test } from 'ava'
import { test } from 'ava'
import {
config,
log,
} from '../../src/config'
import PuppetWeb from '../../src/puppet-web'
import PuppetWebServer from '../../src/puppet-web/server'
} from '../../src/config'
import PuppetWeb from '../../src/puppet-web'
import {
PuppetWebServer,
WechatyBroEvent,
} from '../../src/puppet-web/server'
/**
* the reason why use `test.serial` here is:
......@@ -85,7 +88,7 @@ test.serial('server/browser socketio ding', async t => {
/////////////////////////////////////////////////////////////////////////////
function dingSocket(server: PuppetWebServer) {
function dingSocket(server: PuppetWebServer): Promise<string> {
const maxTime = 60000 // 60s
const waitTime = 3000
let totalTime = 0
......@@ -112,15 +115,21 @@ test.serial('server/browser socketio ding', async t => {
setTimeout(testDing, waitTime)
return
}
log.silly('TestPuppetWeb', 'dingSocket() server.socketClient: %s', server.socketClient)
server.socketClient.once('dong', data => {
// server.socketClient is set
log.silly('TestPuppetWeb', 'dingSocket() server.socketClient: %s', server.socketClient.readyState)
server.once('dong', data => {
log.verbose('TestPuppetWeb', 'socket recv event dong: ' + data)
clearTimeout(timeoutTimer)
return resolve(data)
})
server.socketClient.emit('ding', EXPECTED_DING_DATA)
const obj: WechatyBroEvent = {
name: 'ding',
data: EXPECTED_DING_DATA,
}
server.socketClient.send(JSON.stringify(obj))
}
})
}
......
......@@ -41,8 +41,8 @@ test('create & close', async t => {
t.is(typeof httpsServer, 'object', 'create https server')
httpsServer.on('close', _ => spy('onClose'))
const socketio = s.createSocketIo(httpsServer)
t.is(typeof socketio, 'object', 'should created socket io instance')
const socket = s.createWebSocketServer(httpsServer)
t.is(typeof socket, 'object', 'should created WebSocket instance')
const retClose = await new Promise((resolve, reject) => {
; (httpsServer as any).close(_ => {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册