Skip to content

Commit

Permalink
Multiple change
Browse files Browse the repository at this point in the history
new: Add support custom parser without extends class
new: Add support for send same name header
new: Add force stop timeout on graceful stop
change: Correction naming style
fix: Bug on client
  • Loading branch information
hans00 committed Dec 21, 2019
1 parent 1fa0e43 commit a57f853
Show file tree
Hide file tree
Showing 16 changed files with 301 additions and 198 deletions.
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,15 @@ app.listen(3000, () => {
# Feature

- [x] Simple to use
- [x] Auto serve static file and cache.
- [x] WebSocket reply event
- [x] Auto reload SSL when signal(1)
- [x] Auto graceful shutdown
- [x] Auto parse message
- [x] URL params to object
- [x] Can use built-in template engine or custom template engine
- [x] Serve static files
- [x] Simple WebSocket Framework
- [x] Reload SSL when system signal HUP(1)
- [x] Graceful shutdown
- [x] Parse body data
- [x] URL params parser
- [x] Support for template engine
- [x] Response from pipe stream
- [x] Support cache
- [ ] Support for Socket.io
- [ ] Support for TypeScript
- [ ] Sub-route likes Express.js
36 changes: 19 additions & 17 deletions client/base.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
const Replicator = require('replicator')
const { EventEmitter } = require('events')

const replicator = new Replicator()

const PING = '\x0F'
const PONG = '\x0E'
const DATA_START = '\x01'
Expand All @@ -17,33 +15,34 @@ class WSClientBase extends EventEmitter {
constructor (options = {}) {
super()
this.options = options
this.replicator = new Replicator(options.parserOptions)
this.connectState = 0
this.internalEvents = ['open', 'close', 'disconnect', 'connect', 'ping', 'pong', 'message', 'binary', 'error']
this.client = null
this._return_id_counter = 0
this._event_return = {}
}

static getPayload (data, type = 'message') {
getPayload (data, type = 'message') {
if (type === 'event') {
if (data.replyId === undefined || data.replyId === null) {
data.replyId = ''
}
return EVENT + eventId(data.event) + IDLE + data.replyId + WSClientBase.getPayload(data.data)
return EVENT + eventId(data.event) + IDLE + data.replyId + this.getPayload(data.data)
} else if (type === 'ping') {
return PING + new Date().valueOf().toString()
} else if (type === 'pong') {
return PONG + data.toString()
} else if (type === 'message') {
return DATA_START + replicator.encode(data) + DATA_END
return DATA_START + this.replicator.encode(data) + DATA_END
} else {
return ''
}
}

static parsePayload (payload) {
parsePayload (payload) {
if (payload[0] === DATA_START && payload[payload.length - 1] === DATA_END) {
return { type: 'message', data: replicator.decode(payload.slice(1, -1)) }
return { type: 'message', data: this.replicator.decode(payload.slice(1, -1)) }
} else if (payload[0] === PING) {
return { type: 'ping', data: Number(payload.slice(1)) }
} else if (payload[0] === PONG) {
Expand All @@ -52,11 +51,11 @@ class WSClientBase extends EventEmitter {
const splitIndex = payload.indexOf(DATA_START)
const id = Number(payload.slice(1, splitIndex))
const data = payload.slice(splitIndex)
return { type: 'returnData', id, data: WSClientBase.parsePayload(data).data }
return { type: 'returnData', id, data: this.parsePayload(data).data }
} else if (payload[0] === EVENT) {
const splitIndex = payload.indexOf(DATA_START)
const data = payload.slice(splitIndex)
return { type: 'event', event: payload.slice(1, splitIndex), data: WSClientBase.parsePayload(data).data }
return { type: 'event', event: payload.slice(1, splitIndex), data: this.parsePayload(data).data }
}
}

Expand All @@ -66,17 +65,17 @@ class WSClientBase extends EventEmitter {

incomingPacket (payload) {
if (payload.constructor.name === 'ArrayBuffer' || payload.constructor.name === 'Blob') {
this.emit('binary', payload)
super.emit('binary', payload)
} else {
const incoming = WSClientBase.parsePayload(payload)
const incoming = this.parsePayload(payload)
if (incoming.type === 'event') {
this.emit(incoming.event, incoming.data)
super.emit(incoming.event, incoming.data)
} else if (incoming.type === 'returnData') {
if (this._event_return[incoming.id]) {
this._event_return[incoming.id](incoming)
}
} else {
this.emit(incoming.type, incoming.data)
super.emit(incoming.type, incoming.data)
}
}
}
Expand Down Expand Up @@ -125,7 +124,10 @@ class WSClientBase extends EventEmitter {
this.client.close()
}

send (event, data, waitReturn = false) {
emit (event, data, waitReturn = false) {
if (this.internalEvents.includes(event)) {
return super.emit(event, data)
}
return new Promise((resolve, reject) => {
let replyId
if (waitReturn) {
Expand All @@ -134,7 +136,7 @@ class WSClientBase extends EventEmitter {
this._return_id_counter = 0
}
}
this.client.send(WSClientBase.getPayload({ event, data, replyId }, 'event'))
this.client.send(this.getPayload({ event, data, replyId }, 'event'))
if (waitReturn) {
const timeOut = setTimeout(() => {
reject(new Error('Response timeout.'))
Expand All @@ -152,8 +154,8 @@ class WSClientBase extends EventEmitter {
})
}

sendMessage (data) {
this.client.send(WSClientBase.getPayload(data))
send (data) {
this.client.send(this.getPayload(data))
}

sendBinary (data) {
Expand Down
12 changes: 6 additions & 6 deletions client/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ class WSClient extends Base {
super(options)
this.client = new WebSocket(endpoint, 'fast-ws')
this.client.onerror = error => {
this.emit('error', error)
super.emit('error', error)
}
this.client.onopen = () => {
this.connectState = 1
this.emit('open')
super.emit('open')
this._heartbeat = setInterval(() => {
this.ping()
}, options.pingInterval || 30000)
}
this.client.onclose = () => {
this.emit('close')
super.emit('close')
this.connectState = -1
clearInterval(this._heartbeat)
this.emit('disconnect')
super.emit('disconnect')
}
this.client.onmessage = ({ type, data }) => {
if (this.connectState !== 2) {
if (data === '\x00\x02') {
this.connectState = 2
this.emit('connect')
super.emit('connect')
} else {
this.emit('error', new Error('Client version mismatch.'))
super.emit('error', new Error('Client version mismatch.'))
}
} else {
this.incomingPacket(data)
Expand Down
14 changes: 7 additions & 7 deletions client/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class WSClient extends Base {
super(options)
this.client = new WebSocket(endpoint, 'fast-ws', options)
this.client.on('error', error => {
this.emit('error', error)
super.emit('error', error)
})
this.client.on('open', () => {
this.connectState = 1
Expand All @@ -17,28 +17,28 @@ class WSClient extends Base {
this.client.on('close', () => {
this.connectState = -1
clearInterval(this._heartbeat)
this.emit('disconnect')
super.emit('disconnect')
})
this.client.on('message', (message) => {
if (this.connectState !== 2) {
if (message === '\x00\x02') {
this.connectState = 2
this.emit('connect')
super.emit('connect')
} else {
this.emit('error', new Error('Client version mismatch.'))
super.emit('error', new Error('Client version mismatch.'))
}
} else {
this.incomingPacket(message)
}
})
this.client.on('ping', () => {
this.emit('ping')
super.emit('ping')
})
this.client.on('pong', (data) => {
if (data.length) {
this.emit('pong', new Date().valueOf() - data.toString())
super.emit('pong', new Date().valueOf() - data.toString())
} else {
this.emit('pong')
super.emit('pong')
}
})
}
Expand Down
8 changes: 5 additions & 3 deletions docs/Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const ws = new Client(
pingInterval: 30000, // Default (ms)
// Reply Timeout (Event reply)
replyTimeout: 5000, // Default (ms)
// parser options (same as server)
parserOptions: {},
...// Others options for package 'ws'
}
)
Expand All @@ -30,11 +32,11 @@ const ws = new Client(

> Remove all listeners by event name
### `send(event, data)`
### `emit(event, data)`

> Send custom event to server
> Emit custom event to server
### `sendMessage(data)`
### `send(data)`

> Send message to server
Expand Down
25 changes: 24 additions & 1 deletion docs/Server.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ app.listen(host, port, () => {

## Directory Structure

> `@` is your execute dir
> `@` is your execute dir (`process.cwd()`)
- `@/stctic/*` => Static files
- `@/template/*` => Template files
Expand Down Expand Up @@ -150,6 +150,29 @@ app.ws(
protocol: 'fast-ws',
// Custom protocol object (must extends `fast-ws/server/ws-protocol/basic`)
protocol: Object,

/*== Protocol Options : basic ==*/
protocolOptions: {
// Parse message (default)
parser: {
parse: (payload) => payload,
stringify: (payload) => payload
},
// Parse message using JSON
parser: JSON,
// Or you can create wour own parser
},

/*== Protocol Options : fast-ws ==*/
protocolOptions: {
// parser options, serialize to BSON
parserOptions: {
serialize: (val) => BSON.serialize(val, false, true, false),
deserialize: BSON.deserialize
},
// Detail see: https://github.com/inikulin/replicator#readme
},

/*== uWS options ==*/
// Compression
compression: 'default', // equal shared
Expand Down
32 changes: 8 additions & 24 deletions docs/WSClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@

> Send binary to client
### `broadcast(channel, message[, compress=true])`
### `sendToChannel(channel, message[, compress=true])`

> Broadcast message to channel
> Send message to channel
### `broadcastBinary(data[, compress=true])`
### `sendBinaryToChannel(data[, compress=true])`

> Broadcast binary to channel
> Send binary to channel
### `close()`

Expand All @@ -76,29 +76,13 @@ ws.on('message', (message) => {
})
```

### `send(event, data[, compress=true])`
### `emit(event, data[, compress=true])`

> Send event to client
> Emit event to client
### `sendMessage(data[, compress=true])`
### `emitToChannel(channel, event, data[, compress=true])`

> Send message to client
### `sendBinary(data[, compress=true])`

> Send binary to client
### `broadcast(channel, event, data[, compress=true])`

> Broadcast event to channel
### `broadcastMessage(channel, data[, compress=true])`

> Broadcast message to channel
### `broadcastBinary(channel, data[, compress=true])`

> Broadcast binary to channel
> Emit event to channel
### `WSEvent`

Expand Down
Loading

0 comments on commit a57f853

Please sign in to comment.