Files
fc/dev/project/library/imports/2a/2ae25839-db90-4a5e-8a78-4e887033bd3b.js
T

644 lines
15 KiB
JavaScript
Raw Normal View History

2026-05-24 10:21:26 +08:00
"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();