pomelo-client-websocket
Version:
multi-client supported pomelo-client-websocket
1,721 lines (1,462 loc) • 48.2 kB
JavaScript
var localRoot = {}
var has = Object.prototype.hasOwnProperty
/* Refer to https://github.com/componentjs/require/blob/master/lib/require.js */
function pomeloClient_require (path, parent, orig) { // eslint-disable-line
var resolved = pomeloClient_require.resolve(path)
// lookup failed
if (resolved === null) {
orig = orig || path
parent = parent || 'root'
var err = new Error('Failed to require "' + orig + '" from "' + parent + '"')
err.path = orig
err.parent = parent
err.pomeloClient_require = true
throw err
}
var module = pomeloClient_require.modules[resolved]
// perform real require()
// by invoking the module's
// registered function
if (!module.exports) {
module.exports = {}
module.client = module.component = true
module.call(this, module.exports, pomeloClient_require.relative(resolved), module)
}
return module.exports
}
pomeloClient_require.modules = {}
pomeloClient_require.aliases = {}
pomeloClient_require.resolve = function (path) {
if (path.charAt(0) === '/') path = path.slice(1)
var index = path + '/index.js'
var paths = [
path,
path + '.js',
path + '.json',
path + '/index.js',
path + '/index.json'
]
for (var i = 0; i < paths.length; i++) {
var path = paths[i] // eslint-disable-line
if (has.call(pomeloClient_require.modules, path)) return path
}
if (has.call(pomeloClient_require.aliases, index)) {
return pomeloClient_require.aliases[index]
}
}
pomeloClient_require.normalize = function (curr, path) {
var segs = []
if (path.charAt(0) !== '.') return path
curr = curr.split('/')
path = path.split('/')
for (var i = 0; i < path.length; ++i) {
if (path[i] === '..') {
curr.pop()
} else if (path[i] !== '.' && path[i] !== '') {
segs.push(path[i])
}
}
return curr.concat(segs).join('/')
}
pomeloClient_require.register = function (path, definition) {
pomeloClient_require.modules[path] = definition
}
pomeloClient_require.alias = function (from, to) {
if (!has.call(pomeloClient_require.modules, from)) {
throw new Error('Failed to alias "' + from + '", it does not exist')
}
pomeloClient_require.aliases[to] = from
}
pomeloClient_require.relative = function (parent) {
var p = pomeloClient_require.normalize(parent, '..')
/**
* lastIndexOf helper.
*/
function lastIndexOf (arr, obj) {
var i = arr.length
while (i--) {
if (arr[i] === obj) return i
}
return -1
}
/**
* The relative require() itself.
*/
function localRequire (path) {
var resolved = localRequire.resolve(path)
return pomeloClient_require(resolved, parent, path)
}
/**
* Resolve relative to the parent.
*/
localRequire.resolve = function (path) {
var c = path.charAt(0)
if (c === '/') return path.slice(1)
if (c === '.') return pomeloClient_require.normalize(p, path)
// resolve deps by returning
// the dep in the nearest "deps"
// directory
var segs = parent.split('/')
var i = lastIndexOf(segs, 'deps') + 1
if (!i) i = 0
path = segs.slice(0, i + 1).join('/') + '/deps/' + path
return path
}
/**
* Check if module is defined at `path`.
*/
localRequire.exists = function (path) {
return has.call(pomeloClient_require.modules, localRequire.resolve(path))
}
return localRequire
}
pomeloClient_require.register('component-indexof/index.js', function (exports, require, module) {
var indexOf = [].indexOf
module.exports = function (arr, obj) {
if (indexOf) return arr.indexOf(obj)
for (var i = 0; i < arr.length; ++i) {
if (arr[i] === obj) return i
}
return -1
}
})
pomeloClient_require.register('component-emitter/index.js', function (exports, require, module) {
var index = require('indexof')
module.exports = Emitter
function Emitter (obj) {
if (obj) return mixin(obj)
}
function mixin (obj) {
for (var key in Emitter.prototype) {
obj[key] = Emitter.prototype[key]
}
return obj
}
Emitter.prototype.on = function (event, fn) {
this._callbacks = this._callbacks || {};
(this._callbacks[event] = this._callbacks[event] || [])
.push(fn)
return this
}
Emitter.prototype.once = function (event, fn) {
var self = this
this._callbacks = this._callbacks || {}
function on () {
self.off(event, on)
fn.apply(this, arguments)
}
fn._off = on
this.on(event, on)
return this
}
function off (event, fn) {
this._callbacks = this._callbacks || {}
// all
if (arguments.length === 0) {
this._callbacks = {}
return this
}
// specific event
var callbacks = this._callbacks[event]
if (!callbacks) return this
// remove all handlers
if (arguments.length === 1) {
delete this._callbacks[event]
return this
}
// remove specific handler
var i = index(callbacks, fn._off || fn)
if (~i) callbacks.splice(i, 1)
return this
};
Emitter.prototype.off = off
Emitter.prototype.removeListener = off
Emitter.prototype.removeAllListeners = off
Emitter.prototype.emit = function (event) {
this._callbacks = this._callbacks || {}
var args = [].slice.call(arguments, 1)
var callbacks = this._callbacks[event]
if (callbacks) {
callbacks = callbacks.slice(0)
for (var i = 0, len = callbacks.length; i < len; ++i) {
callbacks[i].apply(this, args)
}
}
return this
}
Emitter.prototype.listeners = function (event) {
this._callbacks = this._callbacks || {}
return this._callbacks[event] || []
}
Emitter.prototype.hasListeners = function (event) {
return !!this.listeners(event).length
}
})
pomeloClient_require.register('NetEase-pomelo-protocol/lib/protocol.js', function (exports, require, module) {
(function (exports, ByteArray, global) {
var Protocol = exports
var PKG_HEAD_BYTES = 4
var MSG_FLAG_BYTES = 1
var MSG_ROUTE_CODE_BYTES = 2
var MSG_ID_MAX_BYTES = 5 // eslint-disable-line
var MSG_ROUTE_LEN_BYTES = 1
var MSG_ROUTE_CODE_MAX = 0xffff
var MSG_COMPRESS_ROUTE_MASK = 0x1
var MSG_TYPE_MASK = 0x7
var Package = Protocol.Package = {}
var Message = Protocol.Message = {}
Package.TYPE_HANDSHAKE = 1
Package.TYPE_HANDSHAKE_ACK = 2
Package.TYPE_HEARTBEAT = 3
Package.TYPE_DATA = 4
Package.TYPE_KICK = 5
Message.TYPE_REQUEST = 0
Message.TYPE_NOTIFY = 1
Message.TYPE_RESPONSE = 2
Message.TYPE_PUSH = 3
function UTF8Length (input) {
var output = 0
for (var i = 0; i < input.length; i++) {
var charCode = input.charCodeAt(i)
if (charCode > 0x7FF) {
// Surrogate pair means its a 4 byte character
// https://unicode.org/charts/PDF/UD800.pdf
if (charCode >= 0xD800 && charCode <= 0xDBFF) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
i++
output++
}
output += 3 // 1110xxxx 10xxxxxx 10xxxxxx
} else if (charCode > 0x7F) { // 110xxxxx 10xxxxxx
output += 2
} else {
output++ // 0xxxxxxx
}
}
return output
}
/**
* pomele client encode
* id message id;
* route message route
* msg message body
* socketio current support string
*/
Protocol.strencode = function (str) {
if (typeof Buffer !== 'undefined' && ByteArray === Buffer) {
// encoding defaults to 'utf8'
return (new Buffer(str)) // eslint-disable-line
} else {
var byteArray = new ByteArray(UTF8Length(str))
var offset = 0
for (var i = 0; i < str.length; i++) {
var charCode = str.charCodeAt(i)
var codes = null
if (charCode <= 0x7f) {
codes = [charCode]
} else if (charCode <= 0x7ff) {
codes = [0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f)]
} else if (charCode <= 0xffff) {
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
var lowCharCode = str.charCodeAt(++i) // 低位代理
if (isNaN(lowCharCode)) {
throw new Error('低位代理为空,非法数据')
}
charCode = ((charCode - 0xD800) << 10) + (lowCharCode - 0xDC00) + 0x10000
codes = [0xf0 | (charCode >> 18), 0x80 | ((charCode & 0x3f000) >> 12), 0x80 | ((charCode & 0xfc0) >> 6), 0x80 | (charCode & 0x3f)]
} else {
codes = [0xe0 | (charCode >> 12), 0x80 | ((charCode & 0xfc0) >> 6), 0x80 | (charCode & 0x3f)]
}
}
for (var j = 0; j < codes.length; j++) {
byteArray[offset] = codes[j]
++offset
}
}
var _buffer = new ByteArray(offset)
copyArray(_buffer, 0, byteArray, 0, offset)
return _buffer
}
}
/**
* client decode
* msg String data
* return Message Object
*/
Protocol.strdecode = function (buffer) {
if (typeof Buffer !== 'undefined' && ByteArray === Buffer) {
// encoding defaults to 'utf8'
return buffer.toString()
} else {
var bytes = new ByteArray(buffer)
var output = ''
var offset = 0
var charCode = 0
var end = bytes.length
while (offset < end) {
if (bytes[offset] < 128) { // 0x80
charCode = bytes[offset]
offset += 1
} else if (bytes[offset] < 224) { // 0xe0
if (bytes[offset + 1] < 0) {
throw new Error('非法数据')
}
charCode = ((bytes[offset] & 0x1f) << 6) + (bytes[offset + 1] & 0x3f)
offset += 2
} else {
if (bytes[offset + 2] < 0) {
throw new Error('非法数据')
}
if (bytes[offset] < 240) { // 0xf0
charCode = ((bytes[offset] & 0x0f) << 12) + ((bytes[offset + 1] & 0x3f) << 6) + (bytes[offset + 2] & 0x3f)
offset += 3
} else {
charCode = ((bytes[offset] & 0x07) << 18) + ((bytes[offset + 1] & 0x3f) << 12) + ((bytes[offset + 2] & 0x3f) << 6) + (bytes[offset + 3] & 0x3f)
offset += 4
}
}
if (charCode > 0xFFFF) {
charCode -= 0x10000
output += String.fromCharCode(0xD800 + (charCode >> 10)) // 高位
charCode = 0xDC00 + (charCode & 0x3FF) // 低位
}
output += String.fromCharCode(charCode)
}
return output
}
}
/**
* Package protocol encode.
*
* Pomelo package format:
* +------+-------------+------------------+
* | type | body length | body |
* +------+-------------+------------------+
*
* Head: 4bytes
* 0: package type,
* 1 - handshake,
* 2 - handshake ack,
* 3 - heartbeat,
* 4 - data
* 5 - kick
* 1 - 3: big-endian body length
* Body: body length bytes
*
* @param {Number} type package type
* @param {ByteArray} body body content in bytes
* @return {ByteArray} new byte array that contains encode result
*/
Package.encode = function (type, body) {
var length = body ? body.length : 0
var buffer = new ByteArray(PKG_HEAD_BYTES + length)
var index = 0
buffer[index++] = type & 0xff
buffer[index++] = (length >> 16) & 0xff
buffer[index++] = (length >> 8) & 0xff
buffer[index++] = length & 0xff
if (body) {
copyArray(buffer, index, body, 0, length)
}
return buffer
}
/**
* Package protocol decode.
* See encode for package format.
*
* @param {ByteArray} buffer byte array containing package content
* @return {Object} {type: package type, buffer: body byte array}
*/
Package.decode = function (buffer) {
var bytes = new ByteArray(buffer)
var type = bytes[0]
var index = 1
var length = ((bytes[index++]) << 16 | (bytes[index++]) << 8 | bytes[index++]) >>> 0
var body = length ? new ByteArray(length) : null
copyArray(body, 0, bytes, PKG_HEAD_BYTES, length)
return {'type': type, 'body': body}
}
/**
* Message protocol encode.
*
* @param {Number} id message id
* @param {Number} type message type
* @param {Number} compressRoute whether compress route
* @param {Number|String} route route code or route string
* @param {Buffer} msg message body bytes
* @return {Buffer} encode result
*/
Message.encode = function (id, type, compressRoute, route, msg) {
// caculate message max length
var idBytes = msgHasId(type) ? caculateMsgIdBytes(id) : 0
var msgLen = MSG_FLAG_BYTES + idBytes
if (msgHasRoute(type)) {
if (compressRoute) {
if (typeof route !== 'number') {
throw new Error('error flag for number route!')
}
msgLen += MSG_ROUTE_CODE_BYTES
} else {
msgLen += MSG_ROUTE_LEN_BYTES
if (route) {
route = Protocol.strencode(route)
if (route.length > 255) {
throw new Error('route maxlength is overflow')
}
msgLen += route.length
}
}
}
if (msg) {
msgLen += msg.length
}
var buffer = new ByteArray(msgLen)
var offset = 0 // eslint-disable-line
// add flag
offset = encodeMsgFlag(type, compressRoute, buffer, offset)
// add message id
if (msgHasId(type)) {
offset = encodeMsgId(id, idBytes, buffer, offset)
}
// add route
if (msgHasRoute(type)) {
offset = encodeMsgRoute(compressRoute, route, buffer, offset)
}
// add body
if (msg) {
offset = encodeMsgBody(msg, buffer, offset)
}
return buffer
}
/**
* Message protocol decode.
*
* @param {Buffer|Uint8Array} buffer message bytes
* @return {Object} message object
*/
Message.decode = function (buffer) {
var bytes = new ByteArray(buffer)
var bytesLen = bytes.length || bytes.byteLength
var offset = 0
var id = 0
var route = null
// parse flag
var flag = bytes[offset++]
var compressRoute = flag & MSG_COMPRESS_ROUTE_MASK
var type = (flag >> 1) & MSG_TYPE_MASK
// parse id
if (msgHasId(type)) {
var byte = bytes[offset++]
id = byte & 0x7f
while (byte & 0x80) {
id <<= 7
byte = bytes[offset++]
id |= byte & 0x7f
}
}
// parse route
if (msgHasRoute(type)) {
if (compressRoute) {
route = (bytes[offset++]) << 8 | bytes[offset++]
} else {
var routeLen = bytes[offset++]
if (routeLen) {
route = new ByteArray(routeLen)
copyArray(route, 0, bytes, offset, routeLen)
route = Protocol.strdecode(route)
} else {
route = ''
}
offset += routeLen
}
}
// parse body
var bodyLen = bytesLen - offset
var body = new ByteArray(bodyLen)
copyArray(body, 0, bytes, offset, bodyLen)
return {
'id': id,
'type': type,
'compressRoute': compressRoute,
'route': route,
'body': body
}
}
var copyArray = function (dest, doffset, src, soffset, length) {
if (typeof src.copy === 'function') {
// Buffer
src.copy(dest, doffset, soffset, soffset + length)
} else {
// Uint8Array
for (var index = 0; index < length; index++) {
dest[doffset++] = src[soffset++]
}
}
}
var msgHasId = function (type) {
return type === Message.TYPE_REQUEST || type === Message.TYPE_RESPONSE
}
var msgHasRoute = function (type) {
return type === Message.TYPE_REQUEST || type === Message.TYPE_NOTIFY ||
type === Message.TYPE_PUSH
}
var caculateMsgIdBytes = function (id) {
var len = 0
do {
len += 1
id >>= 7
} while (id > 0)
return len
}
var encodeMsgFlag = function (type, compressRoute, buffer, offset) {
if (type !== Message.TYPE_REQUEST && type !== Message.TYPE_NOTIFY &&
type !== Message.TYPE_RESPONSE && type !== Message.TYPE_PUSH) {
throw new Error('unkonw message type: ' + type)
}
buffer[offset] = (type << 1) | (compressRoute ? 1 : 0)
return offset + MSG_FLAG_BYTES
}
var encodeMsgId = function (id, idBytes, buffer, offset) {
var index = offset + idBytes - 1
buffer[index--] = id & 0x7f
while (index >= offset) {
id >>= 7
buffer[index--] = id & 0x7f | 0x80
}
return offset + idBytes
}
var encodeMsgRoute = function (compressRoute, route, buffer, offset) {
if (compressRoute) {
if (route > MSG_ROUTE_CODE_MAX) {
throw new Error('route number is overflow')
}
buffer[offset++] = (route >> 8) & 0xff
buffer[offset++] = route & 0xff
} else {
if (route) {
buffer[offset++] = route.length & 0xff
copyArray(buffer, offset, route, 0, route.length)
offset += route.length
} else {
buffer[offset++] = 0
}
}
return offset
}
var encodeMsgBody = function (msg, buffer, offset) {
copyArray(buffer, offset, msg, 0, msg.length)
return offset + msg.length
}
module.exports = Protocol
})(typeof module === 'object' ? module.exports : (localRoot.Protocol = {}), typeof module === 'object' ? Buffer : Uint8Array, localRoot)
})
pomeloClient_require.register('pomelonode-pomelo-protobuf/lib/client/protobuf.js', function (exports, require, module) {
/* ProtocolBuffer client 0.1.0 */
/**
* pomelo-protobuf
* @author <zhang0935@gmail.com>
*/
/**
* Protocol buffer root
* In browser, it will be localRoot.protobuf
*/
(function (exports, global) {
var Protobuf = exports
Protobuf.init = function (opts) {
// On the serverside, use serverProtos to encode messages send to client
Protobuf.encoder.init(opts.encoderProtos)
// On the serverside, user clientProtos to decode messages receive from clients
Protobuf.decoder.init(opts.decoderProtos)
}
Protobuf.encode = function (key, msg) {
return Protobuf.encoder.encode(key, msg)
}
Protobuf.decode = function (key, msg) {
return Protobuf.decoder.decode(key, msg)
}
// exports to support for components
module.exports = Protobuf
})(typeof module === 'object' ? module.exports : (localRoot.protobuf = {}), localRoot);
/**
* constants
*/
(function (exports, global) {
var constants = exports.constants = {}
constants.TYPES = {
uInt32: 0,
sInt32: 0,
int32: 0,
double: 1,
string: 2,
message: 2,
float: 5
}
})(typeof protobuf !== 'undefined' ? localRoot.protobuf : module.exports, localRoot);
/**
* util module
*/
(function (exports, global) {
var Util = exports.util = {}
Util.isSimpleType = function (type) {
return (type === 'uInt32' ||
type === 'sInt32' ||
type === 'int32' ||
type === 'uInt64' ||
type === 'sInt64' ||
type === 'float' ||
type === 'double')
}
})(typeof protobuf !== 'undefined' ? localRoot.protobuf : module.exports, localRoot);
/**
* codec module
*/
(function (exports, global) {
var Codec = exports.codec = {}
var buffer = new ArrayBuffer(8)
var float32Array = new Float32Array(buffer)
var float64Array = new Float64Array(buffer)
var uInt8Array = new Uint8Array(buffer)
Codec.encodeUInt32 = function (n) {
var n = parseInt(n) // eslint-disable-line
if (isNaN(n) || n < 0) {
return null
}
var result = []
do {
var tmp = n % 128
var next = Math.floor(n / 128)
if (next !== 0) {
tmp = tmp + 128
}
result.push(tmp)
n = next
} while (n !== 0)
return result
}
Codec.encodeSInt32 = function (n) {
var n = parseInt(n) // eslint-disable-line
if (isNaN(n)) {
return null
}
n = n < 0 ? (Math.abs(n) * 2 - 1) : n * 2
return Codec.encodeUInt32(n)
}
Codec.decodeUInt32 = function (bytes) {
var n = 0
for (var i = 0; i < bytes.length; i++) {
var m = parseInt(bytes[i])
n = n + ((m & 0x7f) * Math.pow(2, (7 * i)))
if (m < 128) {
return n
}
}
return n
}
Codec.decodeSInt32 = function (bytes) {
var n = this.decodeUInt32(bytes)
var flag = ((n % 2) === 1) ? -1 : 1
n = ((n % 2 + n) / 2) * flag
return n
}
Codec.encodeFloat = function (float) {
float32Array[0] = float
return uInt8Array
}
Codec.decodeFloat = function (bytes, offset) {
if (!bytes || bytes.length < (offset + 4)) {
return null
}
for (var i = 0; i < 4; i++) {
uInt8Array[i] = bytes[offset + i]
}
return float32Array[0]
}
Codec.encodeDouble = function (double) {
float64Array[0] = double
return uInt8Array.subarray(0, 8)
}
Codec.decodeDouble = function (bytes, offset) {
if (!bytes || bytes.length < (8 + offset)) {
return null
}
for (var i = 0; i < 8; i++) {
uInt8Array[i] = bytes[offset + i]
}
return float64Array[0]
}
Codec.encodeStr = function (bytes, offset, str) {
for (var i = 0; i < str.length; i++) {
var code = str.charCodeAt(i)
var codes = encode2UTF8(code)
for (var j = 0; j < codes.length; j++) {
bytes[offset] = codes[j]
offset++
}
}
return offset
}
/**
* Decode string from utf8 bytes
*/
Codec.decodeStr = function (bytes, offset, length) {
var array = []
var end = offset + length
while (offset < end) {
var code = 0
if (bytes[offset] < 128) {
code = bytes[offset]
offset += 1
} else if (bytes[offset] < 224) {
code = ((bytes[offset] & 0x3f) << 6) + (bytes[offset + 1] & 0x3f)
offset += 2
} else {
code = ((bytes[offset] & 0x0f) << 12) + ((bytes[offset + 1] & 0x3f) << 6) + (bytes[offset + 2] & 0x3f)
offset += 3
}
array.push(code)
}
var str = ''
for (var i = 0; i < array.length;) {
str += String.fromCharCode.apply(null, array.slice(i, i + 10000))
i += 10000
}
return str
}
/**
* Return the byte length of the str use utf8
*/
Codec.byteLength = function (str) {
if (typeof (str) !== 'string') {
return -1
}
var length = 0
for (var i = 0; i < str.length; i++) {
var code = str.charCodeAt(i)
length += codeLength(code)
}
return length
}
/**
* Encode a unicode16 char code to utf8 bytes
*/
function encode2UTF8 (charCode) {
if (charCode <= 0x7f) {
return [charCode]
} else if (charCode <= 0x7ff) {
return [0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f)]
} else {
return [0xe0 | (charCode >> 12), 0x80 | ((charCode & 0xfc0) >> 6), 0x80 | (charCode & 0x3f)]
}
}
function codeLength (code) {
if (code <= 0x7f) {
return 1
} else if (code <= 0x7ff) {
return 2
} else {
return 3
}
}
})(typeof protobuf !== 'undefined' ? localRoot.protobuf : module.exports, localRoot);
/**
* encoder module
*/
(function (exports, global) {
var protobuf = exports
var MsgEncoder = exports.encoder = {}
var codec = protobuf.codec
var constant = protobuf.constants
var util = protobuf.util
MsgEncoder.init = function (protos) {
this.protos = protos || {}
}
MsgEncoder.encode = function (route, msg) {
// Get protos from protos map use the route as key
var protos = this.protos[route]
// Check msg
if (!checkMsg(msg, protos)) {
return null
}
// Set the length of the buffer 2 times bigger to prevent overflow
var length = codec.byteLength(JSON.stringify(msg))
// Init buffer and offset
var buffer = new ArrayBuffer(length)
var uInt8Array = new Uint8Array(buffer)
var offset = 0
if (protos) {
offset = encodeMsg(uInt8Array, offset, protos, msg)
if (offset > 0) {
return uInt8Array.subarray(0, offset)
}
}
return null
}
/**
* Check if the msg follow the defination in the protos
*/
function checkMsg (msg, protos) {
if (!protos) {
return false
}
for (var name in protos) {
var proto = protos[name]
// All required element must exist
switch (proto.option) {
case 'required' :
if (typeof (msg[name]) === 'undefined') {
return false
}
break
case 'optional' :
if (typeof (msg[name]) !== 'undefined') {
if (protos.__messages[proto.type]) {
checkMsg(msg[name], protos.__messages[proto.type])
}
}
break
case 'repeated' :
// Check nest message in repeated elements
if (!!msg[name] && !!protos.__messages[proto.type]) {
for (var i = 0; i < msg[name].length; i++) {
if (!checkMsg(msg[name][i], protos.__messages[proto.type])) {
return false
}
}
}
break
}
}
return true
}
function encodeMsg (buffer, offset, protos, msg) {
for (var name in msg) {
if (protos[name]) {
var proto = protos[name]
switch (proto.option) {
case 'required' :
case 'optional' :
offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag))
offset = encodeProp(msg[name], proto.type, offset, buffer, protos)
break
case 'repeated' :
if (msg[name].length > 0) {
offset = encodeArray(msg[name], proto, offset, buffer, protos)
}
break
}
}
}
return offset
}
function encodeProp (value, type, offset, buffer, protos) {
switch (type) {
case 'uInt32':
offset = writeBytes(buffer, offset, codec.encodeUInt32(value))
break
case 'int32' :
case 'sInt32':
offset = writeBytes(buffer, offset, codec.encodeSInt32(value))
break
case 'float':
writeBytes(buffer, offset, codec.encodeFloat(value))
offset += 4
break
case 'double':
writeBytes(buffer, offset, codec.encodeDouble(value))
offset += 8
break
case 'string':
var length = codec.byteLength(value)
// Encode length
offset = writeBytes(buffer, offset, codec.encodeUInt32(length))
// write string
codec.encodeStr(buffer, offset, value)
offset += length
break
default :
if (protos.__messages[type]) {
// Use a tmp buffer to build an internal msg
var tmpBuffer = new ArrayBuffer(codec.byteLength(JSON.stringify(value)))
var length = 0 // eslint-disable-line
length = encodeMsg(tmpBuffer, length, protos.__messages[type], value)
// Encode length
offset = writeBytes(buffer, offset, codec.encodeUInt32(length))
// contact the object
for (var i = 0; i < length; i++) {
buffer[offset] = tmpBuffer[i]
offset++
}
}
break
}
return offset
}
/**
* Encode reapeated properties, simple msg and object are decode differented
*/
function encodeArray (array, proto, offset, buffer, protos) {
var i = 0
if (util.isSimpleType(proto.type)) {
offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag))
offset = writeBytes(buffer, offset, codec.encodeUInt32(array.length))
for (i = 0; i < array.length; i++) {
offset = encodeProp(array[i], proto.type, offset, buffer)
}
} else {
for (i = 0; i < array.length; i++) {
offset = writeBytes(buffer, offset, encodeTag(proto.type, proto.tag))
offset = encodeProp(array[i], proto.type, offset, buffer, protos)
}
}
return offset
}
function writeBytes (buffer, offset, bytes) {
for (var i = 0; i < bytes.length; i++, offset++) {
buffer[offset] = bytes[i]
}
return offset
}
function encodeTag (type, tag) {
var value = constant.TYPES[type] || 2
return codec.encodeUInt32((tag << 3) | value)
}
})(typeof protobuf !== 'undefined' ? localRoot.protobuf : module.exports, localRoot);
/**
* decoder module
*/
(function (exports, global) {
var protobuf = exports
var MsgDecoder = exports.decoder = {}
var codec = protobuf.codec
var util = protobuf.util
var buffer
var offset = 0
MsgDecoder.init = function (protos) {
this.protos = protos || {}
}
MsgDecoder.setProtos = function (protos) {
if (protos) {
this.protos = protos
}
}
MsgDecoder.decode = function (route, buf) {
var protos = this.protos[route]
buffer = buf
offset = 0
if (protos) {
return decodeMsg({}, protos, buffer.length)
}
return null
}
function decodeMsg (msg, protos, length) {
while (offset < length) {
var head = getHead()
var type = head.type // eslint-disable-line
var tag = head.tag
var name = protos.__tags[tag]
switch (protos[name].option) {
case 'optional' :
case 'required' :
msg[name] = decodeProp(protos[name].type, protos)
break
case 'repeated' :
if (!msg[name]) {
msg[name] = []
}
decodeArray(msg[name], protos[name].type, protos)
break
}
}
return msg
}
/**
* Test if the given msg is finished
*/
function isFinish (msg, protos) { // eslint-disable-line
return (!protos.__tags[peekHead().tag])
}
/**
* Get property head from protobuf
*/
function getHead () {
var tag = codec.decodeUInt32(getBytes())
return {
type: tag & 0x7,
tag: tag >> 3
}
}
/**
* Get tag head without move the offset
*/
function peekHead () {
var tag = codec.decodeUInt32(peekBytes())
return {
type: tag & 0x7,
tag: tag >> 3
}
}
function decodeProp (type, protos) {
switch (type) {
case 'uInt32':
return codec.decodeUInt32(getBytes())
case 'int32' :
case 'sInt32' :
return codec.decodeSInt32(getBytes())
case 'float' :
var float = codec.decodeFloat(buffer, offset)
offset += 4
return float
case 'double' :
var double = codec.decodeDouble(buffer, offset)
offset += 8
return double
case 'string' :
var length = codec.decodeUInt32(getBytes())
var str = codec.decodeStr(buffer, offset, length)
offset += length
return str
default :
if (!!protos && !!protos.__messages[type]) {
var length = codec.decodeUInt32(getBytes()) // eslint-disable-line
var msg = {}
decodeMsg(msg, protos.__messages[type], offset + length)
return msg
}
break
}
}
function decodeArray (array, type, protos) {
if (util.isSimpleType(type)) {
var length = codec.decodeUInt32(getBytes())
for (var i = 0; i < length; i++) {
array.push(decodeProp(type))
}
} else {
array.push(decodeProp(type, protos))
}
}
function getBytes (flag) {
var bytes = []
var pos = offset
flag = flag || false
var b
do {
b = buffer[pos]
bytes.push(b)
pos++
} while (b >= 128)
if (!flag) {
offset = pos
}
return bytes
}
function peekBytes () {
return getBytes(true)
}
})(typeof protobuf !== 'undefined' ? localRoot.protobuf : module.exports, localRoot)
})
pomeloClient_require.register('pomelonode-pomelo-jsclient-websocket/lib/pomelo-client.js', function (exports, require, module) {
(function () {
var JS_WS_CLIENT_TYPE = 'js-websocket'
var JS_WS_CLIENT_VERSION = '0.0.1'
var Protocol = localRoot.Protocol
var protobuf = localRoot.protobuf
var Package = Protocol.Package
var Message = Protocol.Message
var EventEmitter = localRoot.EventEmitter
var RES_OK = 200
var RES_FAIL = 500 // eslint-disable-line
var RES_OLD_CLIENT = 501
var DEFAULT_MAX_RECONNECT_ATTEMPTS = 5
var DEFAULT_RECONNECTION_DELAY = 5000
var OMITTED_PORTS = [80, 443]
function Pomelo () {
this.socket = null
this.reqId = 0
this.callbacks = {}
this.handlers = {}
this.handlers[Package.TYPE_HANDSHAKE] = handshake.bind(this)
this.handlers[Package.TYPE_HEARTBEAT] = heartbeat.bind(this)
this.handlers[Package.TYPE_DATA] = onData.bind(this)
this.handlers[Package.TYPE_KICK] = onKick.bind(this)
// Map from request id to route
this.routeMap = {}
this.heartbeatInterval = 0
this.heartbeatTimeout = 0
this.nextHeartbeatTimeout = 0
this.gapThreshold = 100 // heartbeat gap threashold
this.heartbeatId = null
this.heartbeatTimeoutId = null
this.handshakeCallback = null
// 可配置
this.reconnect = false // 是否允许重连
this.maxReconnectAttempts = DEFAULT_MAX_RECONNECT_ATTEMPTS
this.reconnectionDelay = DEFAULT_RECONNECTION_DELAY
this.originalReconnectionDelay = DEFAULT_RECONNECTION_DELAY
this.reconnecting = false
this.reconnectUrl = null
this.reconnectAttempts = 0
this.reconnectTimer = null
this.handshakeBuffer = {
'sys': {
type: JS_WS_CLIENT_TYPE,
version: JS_WS_CLIENT_VERSION
},
'user': {}
}
this.initCallback = function () {}
}
Pomelo.prototype = new EventEmitter()
var pro = Pomelo.prototype
pro.init = function (params, cb) {
this.initCallback = cb
var host = params.host
var port = params.port
var scheme = params.scheme || 'ws'
var path = params.path
this.log = !!params.log
var url = scheme + '://' + host
if (port && OMITTED_PORTS.indexOf(port) === -1) {
url += ':' + port
}
url += (path || '')
this.reconnect = !!params.reconnect
if (params.maxReconnectAttempts > 0) {
this.maxReconnectAttempts = +params.maxReconnectAttempts
}
if (params.reconnectionDelay > 0) {
this.reconnectionDelay = +params.reconnectionDelay
this.originalReconnectionDelay = +params.reconnectionDelay
}
this.reconnectUrl = url
this.handshakeBuffer.user = params.user
this.handshakeCallback = params.handshakeCallback
this.initWebSocket(url, cb)
return this
}
pro.initByUrl = function (url, params, cb) {
this.initCallback = cb
this.log = !!params.log
this.reconnect = !!params.reconnect
if (params.maxReconnectAttempts > 0) {
this.maxReconnectAttempts = +params.maxReconnectAttempts
}
if (params.reconnectionDelay > 0) {
this.reconnectionDelay = +params.reconnectionDelay
this.originalReconnectionDelay = +params.reconnectionDelay
}
this.reconnectUrl = url
this.handshakeBuffer.user = params.user
this.handshakeCallback = params.handshakeCallback
this.initWebSocket(url, cb)
return this
}
var onopen = function (event) {
if (this.reconnecting) {
this.emit('reconnect')
}
// 重连成功要重置重连信息
this.resetReconnectConfig()
var obj = Package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(this.handshakeBuffer)))
this.send(obj)
}
var onmessage = function (cb, event) {
this.processPackage(Package.decode(event.data), cb)
// new package arrived, update the heartbeat timeout
if (this.heartbeatTimeout) {
this.nextHeartbeatTimeout = Date.now() + this.heartbeatTimeout
}
}
var onerror = function (event) {
this.emit('io-error', event)
this.log && console.error('socket error: ', event)
if (this.reconnect && this.reconnectAttempts < this.maxReconnectAttempts) {
this.connecting = true
this.reconnectAttempts++
this.log && console.info('socket reconnect: ', this.reconnectAttempts)
var self = this
this.reconnectTimer = setTimeout(function () {
self.initWebSocket(self.reconnectUrl, self.initCallback.bind(self))
}, this.reconnectionDelay)
this.reconnectionDelay *= 2
} else {
this.log && console.info('未开启重连或重连尝试次数已用尽')
}
}
var onclose = function (event) {
this.emit('close', event)
this.emit('disconnect', event)
this.log && console.warn('socket close: ', event)
if (this.reconnect && this.reconnectAttempts < this.maxReconnectAttempts) {
this.connecting = true
this.reconnectAttempts++
this.log && console.info('socket reconnect: ', this.reconnectAttempts)
var self = this
this.reconnectTimer = setTimeout(function () {
self.initWebSocket(self.reconnectUrl, self.initCallback.bind(self))
}, this.reconnectionDelay)
this.reconnectionDelay *= 2
} else {
this.log && console.info('未开启重连或重连尝试次数已用尽')
}
}
pro.initWebSocket = function (url, cb) {
this.log && console.info('connect to ' + url)
this.socket = new WebSocket(url) // eslint-disable-line
this.socket.binaryType = 'arraybuffer'
this.socket.onopen = onopen.bind(this)
this.socket.onmessage = onmessage.bind(this, cb)
this.socket.onerror = onerror.bind(this)
this.socket.onclose = onclose.bind(this)
}
pro.disconnect = function () {
if (this.socket) {
if (this.socket.disconnect) this.socket.disconnect()
if (this.socket.close) this.socket.close()
this.log && console.info('disconnect')
this.socket = null
}
if (this.heartbeatId) {
clearTimeout(this.heartbeatId)
this.heartbeatId = null
}
if (this.heartbeatTimeoutId) {
clearTimeout(this.heartbeatTimeoutId)
this.heartbeatTimeoutId = null
}
}
pro.resetReconnectConfig = function () {
this.reconnectAttempts = 0
this.reconnectionDelay = this.originalReconnectionDelay
clearTimeout(this.reconnectTimer)
}
pro.request = function (route, msg, cb) {
this.log && console.log('%c发出消息: ' + route, 'color: green;border: 1px solid #ccc', msg)
if (arguments.length === 2 && typeof msg === 'function') {
cb = msg
msg = {}
} else {
msg = msg || {}
}
route = route || msg.route
if (!route) {
return
}
this.reqId++
this.sendMessage(this.reqId, route, msg)
this.callbacks[this.reqId] = cb
this.routeMap[this.reqId] = route
}
pro.notify = function (route, msg) {
msg = msg || {}
this.sendMessage(0, route, msg)
}
pro.sendMessage = function (reqId, route, msg) {
var type = reqId ? Message.TYPE_REQUEST : Message.TYPE_NOTIFY
// compress message by protobuf
var protos = this.data.protos ? this.data.protos.client : {}
if (protos[route]) {
msg = protobuf.encode(route, msg)
} else {
msg = Protocol.strencode(JSON.stringify(msg))
}
var compressRoute = 0
if (this.dict && this.dict[route]) {
route = this.dict[route]
compressRoute = 1
}
msg = Message.encode(reqId, type, compressRoute, route, msg)
var packet = Package.encode(Package.TYPE_DATA, msg)
this.send(packet)
}
pro.send = function (packet) {
if (this.socket && this.socket.readyState === WebSocket.OPEN) { // eslint-disable-line
this.socket.send(packet.buffer)
} else {
this.log && console.warn('socket is not open: readyState ' + (this.socket ? this.socket.readyState : -1))
}
}
function heartbeatTimeoutCb () {
var gap = this.nextHeartbeatTimeout - Date.now()
if (gap > this.gapThreshold) {
this.heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb.bind(this), gap)
} else {
this.log && console.error('server heartbeat timeout')
this.emit('heartbeat timeout')
this.disconnect()
}
}
function heartbeat (data) {
if (!this.heartbeatInterval) {
// no heartbeat
return
}
var obj = Package.encode(Package.TYPE_HEARTBEAT)
if (this.heartbeatTimeoutId) {
clearTimeout(this.heartbeatTimeoutId)
this.heartbeatTimeoutId = null
}
if (this.heartbeatId) {
// already in a heartbeat interval
return
}
var self = this
this.heartbeatId = setTimeout(function () {
self.heartbeatId = null
self.send(obj)
self.nextHeartbeatTimeout = Date.now() + self.heartbeatTimeout
self.heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb.bind(self), self.heartbeatTimeout)
}, this.heartbeatInterval)
}
function handshake (data) {
data = JSON.parse(Protocol.strdecode(data))
if (data.code === RES_OLD_CLIENT) {
this.emit('error', 'client version not fullfill')
return
}
if (data.code !== RES_OK) {
this.emit('error', 'handshake fail')
return
}
this.handshakeInit(data)
var obj = Package.encode(Package.TYPE_HANDSHAKE_ACK)
this.send(obj)
this.emit('connect')
if (this.initCallback) {
this.initCallback(this.socket)
}
}
function onData (data) {
// probuff decode
var msg = Message.decode(data)
if (msg.id > 0) {
msg.route = this.routeMap[msg.id]
delete this.routeMap[msg.id]
if (!msg.route) {
return
}
}
msg.body = this.deCompose(msg)
this.processMessage(msg)
}
function onKick (data) {
this.emit('onKick')
}
pro.processPackage = function (msg) {
this.handlers[msg.type](msg.body)
}
pro.processMessage = function (msg) {
if (!msg.id) {
// server push message
this.emit('__CLIENT_ROUTE', msg.route, msg.body)
this.emit(msg.route, msg.body)
this.log && console.log('%c收到消息: ' + msg.route, 'color: #DFC149;border: 1px solid #ccc', msg.body)
return
}
// if have a id then find the callback function with the request
var cb = this.callbacks[msg.id]
delete this.callbacks[msg.id]
if (typeof cb !== 'function') {
return
}
this.emit('__CLIENT_RESPONSE', msg.body)
this.log && console.log('%c收到消息: ', 'color: #DFC149;border: 1px solid #ccc', msg.body)
cb(msg.body)
}
pro.processMessageBatch = function (msgs) {
for (var i = 0, l = msgs.length; i < l; i++) {
this.processMessage(msgs[i])
}
}
pro.deCompose = function (msg) {
var protos = this.data.protos ? this.data.protos.server : {}
var abbrs = this.data.abbrs
var route = msg.route
// Decompose route from dict
if (msg.compressRoute) {
if (!abbrs[route]) {
return {}
}
route = msg.route = abbrs[route]
}
if (protos[route]) {
return protobuf.decode(route, msg.body)
} else {
return JSON.parse(Protocol.strdecode(msg.body))
}
}
pro.handshakeInit = function (data) {
if (data.sys && data.sys['heartbeat']) {
this.heartbeatInterval = data.sys['heartbeat'] * 1000 // heartbeat interval
this.heartbeatTimeout = this.heartbeatInterval * 2 // max heartbeat timeout
} else {
this.heartbeatInterval = 0
this.heartbeatTimeout = 0
}
this.initData(data)
if (typeof this.handshakeCallback === 'function') {
this.handshakeCallback(data.user)
}
}
pro.initData = function (data) {
if (!data || !data.sys) {
return
}
this.data = this.data || {}
var dict = data.sys.dict
var protos = data.sys.protos
// Init compress dict
if (dict) {
this.data.dict = dict
this.data.abbrs = {}
for (var route in dict) {
this.data.abbrs[dict[route]] = route
}
}
// Init protobuf protos
if (protos) {
this.data.protos = {
server: protos.server || {},
client: protos.client || {}
}
if (protobuf) {
protobuf.init({encoderProtos: protos.client, decoderProtos: protos.server})
}
}
}
module.exports = Pomelo
})()
})
pomeloClient_require.register('boot/index.js', function (exports, require, module) {
var Emitter = require('emitter')
localRoot.EventEmitter = Emitter
var protocol = require('pomelo-protocol')
localRoot.Protocol = protocol
var protobuf = require('pomelo-protobuf')
localRoot.protobuf = protobuf
var Pomelo = require('pomelo-jsclient-websocket')
localRoot.Pomelo = Pomelo
})
pomeloClient_require.alias('boot/index.js', 'pomelo-client/deps/boot/index.js')
pomeloClient_require.alias('component-emitter/index.js', 'boot/deps/emitter/index.js')
pomeloClient_require.alias('component-indexof/index.js', 'component-emitter/deps/indexof/index.js')
pomeloClient_require.alias('NetEase-pomelo-protocol/lib/protocol.js', 'boot/deps/pomelo-protocol/lib/protocol.js')
pomeloClient_require.alias('NetEase-pomelo-protocol/lib/protocol.js', 'boot/deps/pomelo-protocol/index.js')
pomeloClient_require.alias('NetEase-pomelo-protocol/lib/protocol.js', 'NetEase-pomelo-protocol/index.js')
pomeloClient_require.alias('pomelonode-pomelo-protobuf/lib/client/protobuf.js', 'boot/deps/pomelo-protobuf/lib/client/protobuf.js')
pomeloClient_require.alias('pomelonode-pomelo-protobuf/lib/client/protobuf.js', 'boot/deps/pomelo-protobuf/index.js')
pomeloClient_require.alias('pomelonode-pomelo-protobuf/lib/client/protobuf.js', 'pomelonode-pomelo-protobuf/index.js')
pomeloClient_require.alias('pomelonode-pomelo-jsclient-websocket/lib/pomelo-client.js', 'boot/deps/pomelo-jsclient-websocket/lib/pomelo-client.js')
pomeloClient_require.alias('pomelonode-pomelo-jsclient-websocket/lib/pomelo-client.js', 'boot/deps/pomelo-jsclient-websocket/index.js')
pomeloClient_require.alias('pomelonode-pomelo-jsclient-websocket/lib/pomelo-client.js', 'pomelonode-pomelo-jsclient-websocket/index.js')
pomeloClient_require('boot');
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['Pomelo'], factory())
} else if (typeof exports === 'object') {
module.exports = factory()
} else {
root.Pomelo = factory()
}
}(this, function () {
return localRoot.Pomelo
}))