Files
fc/dev/project/library/imports/2a/2ae25839-db90-4a5e-8a78-4e887033bd3b.js
T
2026-05-24 10:21:26 +08:00

644 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
cc._RF.push(module, '2ae25g525BKXop4TohwM707', 'SocketService');
// Scripts/client/socket/SocketService.js
"use strict";
/**
* @author: kevin
* @dateTime: 2018-06-15 10:52:51
* @description: 封装socket连接(websocket)
* @copyright: Copyright(c) 2018 League_h5
* rfc6455#section-7.4
* close code: 1006,1005,1004
*/
// net error code
var ErrorCode = {
SUCC: 0,
// 成功
FAIL: 1,
// 失败
ERR_ALREADY_CONNECTED: 2,
// 已经连接
FAIL_NOT_SUPPORT: 3 // 不支持
};
// net status(ws)
var NetStatus = {
UNKNOWN: 0,
// 未知,尚未连接,或者已经断开
CONNECTING: 1,
// 连接中
CONNECTED: 2 // 已经连接
};
// for connect pool
var this_connect_pool = [];
// for WebSocket
var WebSocketClass = null;
/*
@method: check_time_num10(i)
@desc: 检测时间数字,小于10前面加0
@return: [string]
*/
function check_time_num10(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
/*
@method: get_str_curr_time()
@desc: 当前时间,格式:11:04:26
@return: [string]
*/
function get_str_curr_time() {
var today = new Date();
return check_time_num10(today.getHours()) + ":" + check_time_num10(today.getMinutes()) + ":" + check_time_num10(today.getSeconds());
}
/*
@method: get_str_curr_datetime()
@desc: 当前日期时间,格式:2022-03-01 11:04:26
@return: [string]
*/
function get_str_curr_datetime() {
var today = new Date();
return today.getFullYear() + "-" + check_time_num10(today.getMonth() + 1) + "-" + check_time_num10(today.getDate()) + " " + check_time_num10(today.getHours()) + ":" + check_time_num10(today.getMinutes()) + ":" + check_time_num10(today.getSeconds());
}
/*
@interface: SocketConnect
@desc: for socket connect
@param: [boolean]is_ssl 是否启用ssl加密
*/
function SocketConnect(is_ssl) {
this.is_ssl = !!is_ssl;
//是否重连
this.ip = '127.0.0.1';
this.port = 0;
this.ws = null;
this.status = NetStatus.UNKNOWN;
// 通知事件
this.call_self = null;
this.fn_on_open = null;
this.fn_on_message = null;
this.fn_on_close = null;
this.fn_on_error = null;
// 消息处理函数
this.fn_on_receive = null;
this.fn_on_send = null;
// 队列
this.send_msg_queue = [];
// 心跳
this.heart_beat_handle = null;
this.fn_heart_beat_ms = 0;
this.fn_heart_beat_msg = null;
}
/*
@method: SetSSL(is_ssl=false)
@desc: 设置ssl
@param: [boolean]is_ssl 是否启用ssl加密
@return: [boolean]
*/
SocketConnect.prototype.SetSSL = function (is_ssl) {
if (is_ssl == null) {
is_ssl = false;
}
this.is_ssl = is_ssl;
return true;
};
/*
@method: GetStatus()
@desc: 返回状态
@return: [boolean]
*/
SocketConnect.prototype.GetStatus = function () {
return this.status;
};
/*
@method: CanSendMsg()
@desc: 是否可发送消息,连接中或者重连也开放(开启发送池)
@return: [boolean]
*/
SocketConnect.prototype.CanSendMsg = function () {
if (this.status == NetStatus.CONNECTED || this.status == NetStatus.CONNECTING) {
return true;
}
return false;
};
/*
@method: GetIp()
@desc: 返回: ip
@return: [string]
*/
SocketConnect.prototype.GetIp = function () {
return this.ip;
};
/*
@method: GetPort()
@desc: 返回: port
@return: [int]
*/
SocketConnect.prototype.GetPort = function () {
return this.port;
};
/*
@method: Init(call_self,fn_on_open,fn_on_message,fn_on_close,fn_on_error)
@desc: 初始化,附加处理函数
@param: [object]call_self 操作句柄
@param: [fn]fn_on_open on open,原型: function(self,is_reconnect,err)
@param: [fn]fn_on_message on message,原型:function(self,object,data)
@param: [fn]fn_on_close on close,原型:function(self,need_reconnect,err)
@param: [fn]fn_on_error on error,原型:function(self,err)
@return: [boolean]
*/
SocketConnect.prototype.Init = function (call_self, fn_on_open, fn_on_message, fn_on_close, fn_on_error) {
this.call_self = call_self;
this.fn_on_open = fn_on_open;
this.fn_on_message = fn_on_message;
this.fn_on_close = fn_on_close;
this.fn_on_error = fn_on_error;
return true;
};
/*
@method: AttachMessage(fn_on_receive=null,fn_on_send=null)
@desc: 附加消息处理函数
@param: [fn]fn_on_receive on receive,原型: function(data,function(is_success,data,dst_data){})
@param: [fn]fn_on_send on send,原型:function(data,function(is_success,dst_data){})
@return: [boolean]
*/
SocketConnect.prototype.AttachMessage = function (fn_on_receive, fn_on_send) {
this.fn_on_receive = fn_on_receive;
this.fn_on_send = fn_on_send;
return true;
};
/*
@method: AttachBeartbeat(fn_heart_beat_ms=0,fn_heart_beat_msg=null)
@desc: 启用服务器客户端心跳
@param: [int]fn_heart_beat_ms 心跳时间,单位ms0表示不启用
@param: [fn]fn_heart_beat_msg on send,原型:function(call_self)
@return: [boolean]
*/
SocketConnect.prototype.AttachBeartbeat = function (fn_heart_beat_ms, fn_heart_beat_msg) {
if (fn_heart_beat_ms == null) {
fn_heart_beat_ms = 0;
}
this.fn_heart_beat_ms = fn_heart_beat_ms;
this.fn_heart_beat_msg = fn_heart_beat_msg;
if (this.fn_heart_beat_msg == null) {
this.fn_heart_beat_ms = 0;
}
return true;
};
/*
@method: Release()
@desc: 释放
@return: [boolean]
*/
SocketConnect.prototype.Release = function () {
this.ReleseHeart_Beat();
this.fn_heart_beat_ms = 0;
this.fn_heart_beat_msg = null;
this.status = NetStatus.UNKNOWN;
this.ws = null;
this.fn_on_open = null;
this.fn_on_message = null;
this.fn_on_close = null;
this.fn_on_error = null;
this.fn_on_receive = null;
this.fn_on_send = null;
this.send_msg_queue = [];
return true;
};
/*
@method: ReleseHeart_Beat()
@desc: 释放心跳
@return: [boolean]
*/
SocketConnect.prototype.ReleseHeart_Beat = function () {
if (this.heart_beat_handle != null) {
clearTimeout(this.heart_beat_handle);
this.heart_beat_handle = null;
}
return true;
};
/*
@method: StartHeart_Beat()
@desc: 启动心跳
@return: [boolean]
*/
SocketConnect.prototype.StartHeart_Beat = function () {
this.ReleseHeart_Beat();
var self = this;
self.heart_beat_handle = setTimeout(function () {
self.CallHeart_Beat(self);
}, self.fn_heart_beat_ms);
return true;
};
/*
@method: CallHeart_Beat(self)
@desc: 回调心跳
@return: [boolean]
*/
SocketConnect.prototype.CallHeart_Beat = function (self) {
self.heart_beat_handle = null;
var p_msg = self.fn_heart_beat_msg(self.call_self);
if (p_msg == null) {
return false;
}
var ret = self.Send(p_msg);
if (!ret) {
return false;
}
self.heart_beat_handle = setTimeout(function () {
self.CallHeart_Beat(self);
}, self.fn_heart_beat_ms);
return true;
};
/*
@method: Connect(ip=null,port=null)
@desc: 连接服务器
@param: [string]ip
@param: [int]port
@return: [int] ErrorCode.SUCC;
*/
SocketConnect.prototype.Connect = function (ip, port) {
if (ip == null || port == null) {
return ErrorCode.FAIL;
}
// 重复连接
if (this.status == NetStatus.CONNECTED && this.ip == ip && this.port == port) {
console.log('[ws_connect] 重复连接,忽略本次操作, ip=%s,port=%d', ip, port);
return ErrorCode.ERR_ALREADY_CONNECTED;
}
var self = this;
self.ws = null;
self.DisConnect();
self.ip = ip;
self.port = parseInt(port);
if (self.port <= 0) {
console.log('[ws_connect] invalid, ip=%s,port=%d', ip, port);
return ErrorCode.FAIL;
}
// 开始连接
self.status = NetStatus.CONNECTING;
var remote_url = "";
if (self.is_ssl) {
// remote_url = "wss://"+self.ip+":"+self.port+ "/websocket";//旧版本
remote_url = "wss://" + self.ip + ":443/wss" + self.port; //新版本
} else {
remote_url = "ws://" + self.ip + ":" + self.port + "/websocket";
}
if (WebSocketClass == null) {
console.log('[ws_connect] not support, ip=%s,port=%d', ip, port);
self.status = NetStatus.UNKNOWN;
return ErrorCode.FAIL_NOT_SUPPORT;
}
self.ws = new WebSocketClass(remote_url);
if (self.ws == null) {
console.log('[ws_connect] failure, ip=%s,port=%d', ip, port);
self.status = NetStatus.UNKNOWN;
return ErrorCode.FAIL;
}
self.ws.binaryType = "arraybuffer";
// 连接成功
self.ws.onopen = function (e) {
self.msg_queue = [];
if (self.queue_ticker) {
clearInterval(self.queue_ticker);
self.queue_ticker = null;
}
self.status = NetStatus.CONNECTED;
if (self.fn_on_open != null) {
self.fn_on_open(self.call_self, false, e);
}
//启动心跳
if (self.fn_heart_beat_ms > 0) {
self.StartHeart_Beat();
}
// //延迟发送
self.Try_Delay();
};
// 消息接收
self.ws.onmessage = function (e) {
if (!self.fn_on_message) {
return;
}
if (!self.fn_on_receive) {
self.fn_on_message(self.call_self, e.data, e.data);
return;
}
self.fn_on_receive(e.data, function (is_success, s_data, p_data) {
if (!is_success) {
console.error("[%s][recv] is failure(data)", get_str_curr_time());
return false;
}
self.fn_on_message(self.call_self, p_data, s_data);
return true;
});
};
// 关闭
self.ws.onclose = function (e) {
self.ws = null;
self.status = NetStatus.UNKNOWN;
self.msg_queue = [];
if (self.queue_ticker) {
clearInterval(self.queue_ticker);
self.queue_ticker = null;
}
if (self.fn_on_close) {
self.fn_on_close(self.call_self, false, e);
}
return true;
};
// 错误
self.ws.onerror = function (e) {
self.DisConnect();
if (self.fn_on_error) {
self.fn_on_error(self.call_self, e);
}
};
console.log('[ws_connect] error, ip=%s,port=%d', ip, port, ErrorCode.SUCC);
return ErrorCode.SUCC;
};
/*
@method: ReConnect()
@desc: 重新连接
@return: [int] ErrorCode.SUCC;
*/
SocketConnect.prototype.ReConnect = function () {
if (this.port <= 0) {
console.log('[ws_reconnect] failure, ip=%s,port=%d', this.ip, this.port);
return ErrorCode.FAIL;
}
return this.Connect(this.ip, this.port);
};
/*
@method: DisConnect()
@desc: 断开连接
@return: [boolean]
*/
SocketConnect.prototype.DisConnect = function () {
this.status = NetStatus.UNKNOWN;
this.send_msg_queue = [];
this.ReleseHeart_Beat();
if (this.ws != null) {
this.ws.close();
this.ws = null;
}
return true;
};
/*
@method: Send(data)
@desc: 发送消息
@param: [var]data 发送报文
@return: [boolean]
*/
SocketConnect.prototype.Send = function (data) {
var _this = this;
if (data == null || this.status != NetStatus.CONNECTED) {
console.warn("$Socket:发送失败..a");
return false;
}
if (!this.ws || this.ws.readyState != WebSocketClass.OPEN) {
console.warn("$Socket:发送失败..b");
return false;
}
this.msg_queue.push(data);
if (!this.queue_ticker) {
this.queue_ticker = setInterval(function () {
var data = _this.msg_queue.shift();
if (_this.ws && data) {
_this.ws.send(data);
}
}, 20);
}
// this.Try_Send( data );
return true;
};
// SocketConnect.prototype.Send = function( data ) {
// if( data == null ) {
// return false;
// }
// if( this.status != NetStatus.CONNECTED ) {
// if( this.status == NetStatus.CONNECTING ) {
// this.Send_Delay( data );
// return true;
// }
// return false;
// }
// if( this.ws == null ) {
// this.Send_Delay( data );
// this.DisConnect();
// return true;
// }
// if( this.ws.readyState === WebSocketClass.OPEN ) {
// this.Try_Send( data );
// }
// else {
// this.Send_Delay( data );
// // this.DisConnect();
// }
// return true;
// };
//丢弃处理,否则造成内存膨胀,导致内存溢出
SocketConnect.prototype.Send_Delay = function (data) {
if (this.send_msg_queue.length >= 10000) {
var p_data = this.send_msg_queue.pop();
p_data = null;
}
this.send_msg_queue.unshift(data);
console.log("[%s][send_delay] size =%d", this.send_msg_queue.length);
return true;
};
SocketConnect.prototype.Try_Send = function (data) {
if (this.send_msg_queue.length <= 0) {
if (data != null) {
this.Try_One_Send(data);
}
return true;
}
var p_data = null;
if (data != null) {
this.send_msg_queue.unshift(data);
}
for (var i = 0; i < this.send_msg_queue.length; i++) {
p_data = this.send_msg_queue.pop();
if (p_data == null) {
continue;
}
this.Try_One_Send(p_data);
}
return true;
};
SocketConnect.prototype.Try_One_Send = function (data) {
if (this.fn_on_send == null) {
if (this.ws != null) {
// console.log("[%s][send][0] is succ(data) fn_on_send 1",get_str_curr_time());
this.ws.send(data);
} else {
// console.error("[%s][send][0] is failure(data)",get_str_curr_time());
}
} else {
var self = this;
self.fn_on_send(data, function (is_success, p_data) {
if (is_success) {
if (self.ws != null) {
// console.log("[%s][send][1] is succ(data) fn_on_send 2",get_str_curr_time());
self.ws.send(p_data);
}
} else {
// console.error("[%s][send][1] is failure(data)",get_str_curr_time());
}
});
}
data = null;
return true;
};
SocketConnect.prototype.Try_Delay = function () {
// return true;
if (this.send_msg_queue.length <= 0) {
return false;
}
// if (this.status != NetStatus.CONNECTED)
// {
// return false;
// }
if (this.ws == null) {
return false;
}
if (this.ws.readyState === WebSocketClass.OPEN) {
this.Try_Send(null);
return true;
}
//延迟发送
// var self = this;
// self.Try_Finish(self);
// setTimeout(function(){
// if (self.ws.readyState === WebSocketClass.OPEN)
// {
// self.Try_Send(null);
// }
// return true;
// },30);
return true;
};
SocketConnect.prototype.Try_Finish = function (self) {
var _this2 = this;
if (self.send_msg_queue.length <= 0) return false;
if (self.ws.readyState == WebSocketClass.OPEN) {
self.Try_Send(null);
return true;
} else {
setTimeout(function () {
_this2.Try_Finish(self);
}, 50);
}
};
/*
@interface: SocketService
@desc: for Socket服务
*/
var SocketService = {};
// module.exports 适配js 和 nodejs
if (typeof module != "undefined") {
SocketService = module.exports;
}
/*
@method: InitWebSocket(websocket_class=null)
@desc: 初始化websocket,兼容chromefirefox,cocos
@param: [object]websocket_class 句柄
@return: [boolean]
*/
SocketService.InitWebSocket = function (websocket_class) {
//导入第三方websocket
if (websocket_class != null) {
WebSocketClass = websocket_class;
} else {
//自动适配浏览器websocket(chrome,firefox)
if (typeof window != "undefined") {
if (typeof window.WebSocket == "undefined") {
WebSocketClass = window.MozWebSocket;
} else {
WebSocketClass = window.WebSocket;
}
}
}
};
/*
@method: CreateConnect(is_ssl=false)
@desc: 创建连接
@param: [boolean]is_ssl 是否为ssl
@return: [boolean]
*/
SocketService.CreateConnect = function (is_ssl) {
var p_connect = new SocketConnect(!!is_ssl);
if (p_connect) {
this_connect_pool.push(p_connect);
}
return p_connect;
};
/*
@method: Release()
@desc: 系统退出,关闭所有连接
@return: [boolean]
*/
SocketService.Release = function () {
var p_connect = null;
for (var i = 0; i < this_connect_pool.length; i++) {
p_connect = this_connect_pool[i];
p_connect.Release();
}
this_connect_pool = [];
return true;
};
/*
@method: ErrCode()
@desc: 返回错误码定义
@return: [object]
*/
SocketService.ErrCode = function () {
return ErrorCode;
};
cc._RF.pop();