mirror of
https://github.com/wyb10a10/cocos_creator_framework.git
synced 2026-09-03 06:25:47 +08:00
网络接口调整
This commit is contained in:
73
.gitignore
vendored
73
.gitignore
vendored
@@ -1,6 +1,67 @@
|
||||
/local
|
||||
/temp
|
||||
/library
|
||||
/.vscode
|
||||
/packages
|
||||
.DS_Store
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# Cocos Creator Projects
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
build/
|
||||
library/
|
||||
temp/
|
||||
local/
|
||||
jsb-default/
|
||||
jsb-binary/
|
||||
jsb-link/
|
||||
web-desktop/
|
||||
# web-mobile/ 发布网页版本使用
|
||||
runtime/
|
||||
build/
|
||||
jsb/
|
||||
export/
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# Logs and databases
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# files for debugger
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
*.sln
|
||||
*.csproj
|
||||
*.pidb
|
||||
*.unityproj
|
||||
*.suo
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# OS generated files
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.DS_Store
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# exvim files
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
*UnityVS.meta
|
||||
*.err
|
||||
*.err.meta
|
||||
*.exvim
|
||||
*.exvim.meta
|
||||
*.vimentry
|
||||
*.vimentry.meta
|
||||
*.vimproject
|
||||
*.vimproject.meta
|
||||
.vimfiles.*/
|
||||
.exvim.*/
|
||||
quick_gen_project_*_autogen.bat
|
||||
quick_gen_project_*_autogen.bat.meta
|
||||
quick_gen_project_*_autogen.sh
|
||||
quick_gen_project_*_autogen.sh.meta
|
||||
.exvim.app
|
||||
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
7
assets/Script/common.meta
Normal file
7
assets/Script/common.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "b8f13390-ade4-44a3-8658-6ebf77febb27",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
||||
109
assets/Script/common/EventManager.ts
Normal file
109
assets/Script/common/EventManager.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 事件管理器,事件的监听、触发、移除
|
||||
*
|
||||
* 2018-9-20 by 宝爷
|
||||
*/
|
||||
export type EventManagerCallFunc = (eventName: string, eventData: any) => void;
|
||||
|
||||
interface CallBackTarget {
|
||||
callBack: EventManagerCallFunc,
|
||||
target: any,
|
||||
}
|
||||
|
||||
export class EventManager {
|
||||
private static instance: EventManager = null;
|
||||
public static getInstance(): EventManager {
|
||||
if (!this.instance) {
|
||||
this.instance = new EventManager();
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
public static destroy(): void {
|
||||
if (this.instance) {
|
||||
this.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
private _eventListeners: { [key: string]: CallBackTarget[] } = {};
|
||||
|
||||
private getEventListenersIndex(eventName: string, callBack: EventManagerCallFunc, target?: any): number {
|
||||
let index = -1;
|
||||
for (let i = 0; i < this._eventListeners[eventName].length; i++) {
|
||||
let iterator = this._eventListeners[eventName][i];
|
||||
if (iterator.callBack == callBack && (!target || iterator.target == target)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
addEventListener(eventName: string, callBack: EventManagerCallFunc, target?: any): boolean {
|
||||
if (!eventName) {
|
||||
cc.warn("eventName is empty" + eventName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (null == callBack) {
|
||||
cc.log('addEventListener callBack is nil');
|
||||
return false;
|
||||
}
|
||||
let callTarget: CallBackTarget = { callBack: callBack, target: target };
|
||||
if (null == this._eventListeners[eventName]) {
|
||||
this._eventListeners[eventName] = [callTarget];
|
||||
|
||||
} else {
|
||||
let index = this.getEventListenersIndex(eventName, callBack, target);
|
||||
if (-1 == index) {
|
||||
this._eventListeners[eventName].push(callTarget);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
setEventListener(eventName: string, callBack: EventManagerCallFunc, target?: any): boolean {
|
||||
if (!eventName) {
|
||||
cc.warn("eventName is empty" + eventName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (null == callBack) {
|
||||
cc.log('setEventListener callBack is nil');
|
||||
return false;
|
||||
}
|
||||
let callTarget: CallBackTarget = { callBack: callBack, target: target };
|
||||
this._eventListeners[eventName] = [callTarget];
|
||||
return true;
|
||||
}
|
||||
|
||||
removeEventListener(eventName: string, callBack: EventManagerCallFunc, target?: any) {
|
||||
if (null != this._eventListeners[eventName]) {
|
||||
let index = this.getEventListenersIndex(eventName, callBack, target);
|
||||
if (-1 != index) {
|
||||
this._eventListeners[eventName].splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raiseEvent(eventName: string, eventData?: any) {
|
||||
console.log(`==================== raiseEvent ${eventName} begin | ${JSON.stringify(eventData)}`);
|
||||
if (null != this._eventListeners[eventName]) {
|
||||
// 将所有回调提取出来,再调用,避免调用回调的时候操作了事件的删除
|
||||
let callbackList: CallBackTarget[] = [];
|
||||
for (const iterator of this._eventListeners[eventName]) {
|
||||
callbackList.push({ callBack: iterator.callBack, target: iterator.target });
|
||||
}
|
||||
for (const iterator of callbackList) {
|
||||
iterator.callBack.call(iterator.target, eventName, eventData);
|
||||
}
|
||||
}
|
||||
console.log(`==================== raiseEvent ${eventName} end`);
|
||||
}
|
||||
}
|
||||
|
||||
export let EventMgr = EventManager.getInstance();
|
||||
9
assets/Script/common/EventManager.ts.meta
Normal file
9
assets/Script/common/EventManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "d23b8dc4-fd4c-43e4-87db-4c5bc3bfa818",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
166
assets/Script/common/TaskQueue.ts
Normal file
166
assets/Script/common/TaskQueue.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 任务队列管理器
|
||||
* 1. 传入任务,进入队列顺序执行
|
||||
* 2. 支持优先级(从小到大排序,priority越小优先级越高)
|
||||
* 3. 支持队列Tag,允许多个互不影响的队列执行
|
||||
* 4. 支持清理任务队列
|
||||
* 5. 一个任务只能完成一次,避免代码的原因多次调用完成,导致后续任务提前执行
|
||||
*
|
||||
* 6. 调试模式下记录了每个Task添加时的堆栈,方便调试(可以快速查看哪个任务没有结束)
|
||||
*
|
||||
* 2018-5-7 by 宝爷
|
||||
*/
|
||||
|
||||
|
||||
// 任务结束回调
|
||||
export type TaskFinishCallback = () => void;
|
||||
// 任务执行回调
|
||||
export type TaskCallback = (TaskFinishCallback) => void;
|
||||
|
||||
class TaskInfo {
|
||||
public task: TaskCallback;
|
||||
public priority: number;
|
||||
public constructor(task: TaskCallback, priority: number) {
|
||||
this.task = task;
|
||||
this.priority = priority;
|
||||
}
|
||||
}
|
||||
|
||||
export class TaskQueue {
|
||||
private _curTask: TaskInfo = null;
|
||||
private _taskQueue: TaskInfo[] = Array<TaskInfo>();
|
||||
|
||||
// 添加一个任务,如果当前没有任务在执行,该任务会立即执行,否则进入队列等待
|
||||
public pushTask(task: TaskCallback, priority: number = 0): void {
|
||||
let taskInfo = new TaskInfo(task, priority);
|
||||
if (this._taskQueue.length > 0) {
|
||||
for (var i: number = this._taskQueue.length - 1; i >= 0; --i) {
|
||||
if (this._taskQueue[i].priority <= priority) {
|
||||
this._taskQueue.splice(i + 1, 0, taskInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 插到头部
|
||||
this._taskQueue.splice(0, 0, taskInfo);
|
||||
if (this._curTask == null) {
|
||||
this.executeNextTask();
|
||||
}
|
||||
}
|
||||
|
||||
public clearTask(): void {
|
||||
this._curTask = null;
|
||||
this._taskQueue.length = 0;
|
||||
}
|
||||
|
||||
private executeNextTask(): void {
|
||||
let taskInfo = this._taskQueue.shift() || null;
|
||||
this._curTask = taskInfo;
|
||||
if (taskInfo) {
|
||||
taskInfo.task(() => {
|
||||
if (taskInfo === this._curTask) {
|
||||
this.executeNextTask();
|
||||
} else {
|
||||
console.warn("your task finish twice!");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TaskManager {
|
||||
private static _instance: TaskManager = null;
|
||||
private _taskQueues: { [key: number]: TaskQueue } = {}
|
||||
|
||||
public static getInstance(): TaskManager {
|
||||
if (!this._instance) {
|
||||
this._instance = new TaskManager();
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
public static destory(): void {
|
||||
this._instance = null;
|
||||
}
|
||||
|
||||
private constructor() {
|
||||
|
||||
}
|
||||
|
||||
public pushTask(task: TaskCallback, priority: number = 0): void {
|
||||
return this.getTaskQueue().pushTask(task, priority);
|
||||
}
|
||||
|
||||
public pushTaskByTag(task: TaskCallback, tag: number, priority: number = 0): void {
|
||||
return this.getTaskQueue(tag).pushTask(task, priority);
|
||||
}
|
||||
|
||||
public clearTaskQueue(tag: number = 0): void {
|
||||
let taskQueue = this._taskQueues[tag];
|
||||
if (taskQueue) {
|
||||
taskQueue.clearTask();
|
||||
}
|
||||
}
|
||||
|
||||
public clearAllTaskQueue(): void {
|
||||
for (let queue in this._taskQueues) {
|
||||
this._taskQueues[queue].clearTask();
|
||||
}
|
||||
this._taskQueues = {}
|
||||
}
|
||||
|
||||
private getTaskQueue(tag: number = 0): TaskQueue {
|
||||
let taskQueue = this._taskQueues[tag];
|
||||
if (taskQueue == null) {
|
||||
taskQueue = new TaskQueue();
|
||||
this._taskQueues[tag] = taskQueue;
|
||||
}
|
||||
return taskQueue;
|
||||
}
|
||||
}
|
||||
|
||||
/* 测试用例:
|
||||
* 1. 测试多个任务的执行顺序 + 优先级
|
||||
* 2. 测试在执行任务的过程中动态添加新任务
|
||||
|
||||
export function testQueue() {
|
||||
let creatTask = (idx, pri): TaskCallback => {
|
||||
return (finish) => {
|
||||
console.log(`execute task ${idx} priority ${pri}`);
|
||||
finish();
|
||||
};
|
||||
};
|
||||
let tag = 0;
|
||||
let begin = (finish) => {
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
let priority = 0;
|
||||
if (i % 10 == 0) {
|
||||
priority = -1;
|
||||
} else if (i == 88) {
|
||||
priority = 1;
|
||||
} else if (i == 22) {
|
||||
let task = creatTask(1.1, priority);
|
||||
TaskManager.getInstance().pushTaskByTag(task, tag, priority);
|
||||
task = creatTask(1.2, priority);
|
||||
TaskManager.getInstance().pushTaskByTag(task, tag, priority);
|
||||
task = creatTask(1.3, priority);
|
||||
TaskManager.getInstance().pushTaskByTag(task, tag, priority);
|
||||
} else if (i == 51 && tag == 2) {
|
||||
// 清理之后,添加的任务会立即执行...
|
||||
TaskManager.getInstance().clearTaskQueue(tag);
|
||||
}
|
||||
let task = creatTask(i, priority);
|
||||
Object.defineProperty(task, "idx", { value: i });
|
||||
TaskManager.getInstance().pushTaskByTag(task, tag, priority);
|
||||
}
|
||||
console.log("add task finish, start test");
|
||||
finish();
|
||||
// 测试重复调用结束
|
||||
finish();
|
||||
// tag为2时的finish两次都会报警告,因为begin已经被清理了
|
||||
}
|
||||
TaskManager.getInstance().pushTaskByTag(begin, tag);
|
||||
tag = 2;
|
||||
TaskManager.getInstance().pushTaskByTag(begin, tag);
|
||||
|
||||
}*/
|
||||
9
assets/Script/common/TaskQueue.ts.meta
Normal file
9
assets/Script/common/TaskQueue.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "4ed3ba86-aa0d-4b93-864b-adc0f8d58177",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
7
assets/Script/network.meta
Normal file
7
assets/Script/network.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "7f2dddd0-7938-4352-802a-fa3d6aac09ec",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
||||
41
assets/Script/network/NetInterface.ts
Normal file
41
assets/Script/network/NetInterface.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
export type NetData = (string | ArrayBufferLike | Blob | ArrayBufferView);
|
||||
export type NetCallFunc = (mainCmd: number, subCmd: number, data: any) => void;
|
||||
|
||||
// 回调对象
|
||||
export interface CallbackObject {
|
||||
target: any, // 回调对象,不为null时调用target.callback(xxx)
|
||||
callback: NetCallFunc, // 回调函数
|
||||
}
|
||||
|
||||
// 请求对象
|
||||
export interface RequestObject {
|
||||
buffer: NetData, // 请求的Buffer
|
||||
rspCmd: number, // 等待响应指令
|
||||
rspObject: CallbackObject, // 等待响应的回调对象
|
||||
}
|
||||
|
||||
// 协议对象
|
||||
export interface IProtocolHelper {
|
||||
getHeadlen(): number; // 返回包头长度
|
||||
getHearbeat(): NetData; // 返回一个心跳包
|
||||
checkHead(msg: NetData): boolean; // 检查数据头部是否合法
|
||||
checkCmd(msg: NetData): number; // 获取协议类型或id
|
||||
}
|
||||
|
||||
// Socket对象
|
||||
export interface ISocket {
|
||||
onConnected: (event) => void;
|
||||
onMessage: (msg: NetData) => void;
|
||||
onError: (event) => void;
|
||||
onClosed: (event) => void;
|
||||
connect(options: any) : boolean;
|
||||
send(buffer: NetData) : boolean;
|
||||
close(code?: number, reason?: string);
|
||||
}
|
||||
|
||||
// 网络提示对象
|
||||
export interface INetworkTips {
|
||||
reconnectTips(isShow : boolean): void;
|
||||
requestTips(isShow : boolean): void;
|
||||
}
|
||||
9
assets/Script/network/NetInterface.ts.meta
Normal file
9
assets/Script/network/NetInterface.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "92a57531-69f5-4125-b17e-4fb69dedf652",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
9
assets/Script/network/NetManager.ts
Normal file
9
assets/Script/network/NetManager.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
/*
|
||||
* 网络节点管理类
|
||||
*
|
||||
*/
|
||||
|
||||
export class NetManager {
|
||||
|
||||
}
|
||||
9
assets/Script/network/NetManager.ts.meta
Normal file
9
assets/Script/network/NetManager.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "a83ab7c0-5761-4aac-b367-a108f45b61ad",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
347
assets/Script/network/NetNode.ts
Normal file
347
assets/Script/network/NetNode.ts
Normal file
@@ -0,0 +1,347 @@
|
||||
import { ISocket, INetworkTips, IProtocolHelper, RequestObject, CallbackObject, NetData, NetCallFunc } from "./NetInterface";
|
||||
|
||||
/*
|
||||
* CocosCreator网络节点基类,以及网络相关接口定义
|
||||
* 1. 网络连接、断开、请求发送、数据接收等基础功能
|
||||
* 2. 心跳机制
|
||||
* 3. 断线重连 + 请求重发
|
||||
* 4. 调用网络屏蔽层
|
||||
*
|
||||
* 2018-5-7 by 宝爷
|
||||
*/
|
||||
|
||||
type ExecuterFunc = (callback: CallbackObject, buffer: NetData) => void;
|
||||
type VoidFunc = () => void;
|
||||
type BoolFunc = () => boolean;
|
||||
|
||||
export enum NetNodeState {
|
||||
Closed, // 已关闭
|
||||
Connecting, // 连接中
|
||||
Checking, // 验证中
|
||||
Working, // 可传输数据
|
||||
}
|
||||
|
||||
export enum NetNodeConnectType {
|
||||
Normal,
|
||||
ReConnect,
|
||||
}
|
||||
|
||||
export class NetNode {
|
||||
protected _isAutoReconnect: boolean = false; // 是否在网络断开之后自动重连
|
||||
protected _isSocketInit: boolean = false; // Socket是否初始化过
|
||||
protected _isSocketOpen: boolean = false; // Socket是否连接成功过
|
||||
protected _connType: NetNodeConnectType = NetNodeConnectType.Normal; // 连接类型
|
||||
protected _state: NetNodeState = NetNodeState.Closed; // 节点当前状态
|
||||
protected _socket: ISocket = null; // Socket对象(可能是原生socket、websocket、wx.socket...)
|
||||
protected _host: string; // IP
|
||||
protected _port: number; // 端口
|
||||
|
||||
protected _networkTips: INetworkTips = null; // 网络提示ui对象(请求提示、断线重连提示等)
|
||||
protected _protocolHelper: IProtocolHelper = null; // 包解析对象
|
||||
protected _connectedCallback: VoidFunc = null; // 连接完成回调
|
||||
protected _disconnectCallback: BoolFunc = null; // 断线回调
|
||||
protected _callbackExecuter: ExecuterFunc = null; // 回调执行
|
||||
|
||||
protected _keepAliveTimer: any = null; // 心跳定时器
|
||||
protected _receiveMsgTimer: any = null; // 接收数据定时器
|
||||
protected _reconnectTimer: any = null; // 重连定时器
|
||||
protected _heartTime: number = 10000; // 心跳间隔
|
||||
protected _receiveTime: number = 6000000; // 多久没收到数据断开
|
||||
protected _reconnetTimeOut: number = 8000000; // 重连间隔
|
||||
protected _requests: RequestObject[] = Array<RequestObject>(); // 请求列表
|
||||
protected _listener: { [key: number]: CallbackObject[] } = {} // 监听者列表
|
||||
|
||||
/********************** 网络相关处理 *********************/
|
||||
public init(socket: ISocket, networkTips: any = null) {
|
||||
console.log(`NetNode init socket`);
|
||||
this._socket = socket;
|
||||
this._networkTips = networkTips;
|
||||
}
|
||||
|
||||
public connect(host: string, port: number, auotReconnect: boolean = true, connType: NetNodeConnectType = NetNodeConnectType.Normal) {
|
||||
if (this._socket && this._state == NetNodeState.Closed) {
|
||||
if (!this._isSocketInit) {
|
||||
this.initSocket();
|
||||
}
|
||||
this._state = NetNodeState.Connecting;
|
||||
this._isAutoReconnect = auotReconnect;
|
||||
this._socket.connect({ip : host, port});
|
||||
this._connType = connType;
|
||||
if (connType == NetNodeConnectType.Normal) {
|
||||
this._host = host;
|
||||
this._port = port;
|
||||
}
|
||||
console.log(`NetNode connect to ${host}:${port}`);
|
||||
} else {
|
||||
console.error(`NetNode connect error! should init socket! state ${this._state}`);
|
||||
}
|
||||
}
|
||||
|
||||
protected initSocket() {
|
||||
this._socket.onConnected = (event) => { this.onConnected(event) };
|
||||
this._socket.onMessage = (msg) => { this.onMessage(msg) };
|
||||
this._socket.onError = (event) => { this.onError(event) };
|
||||
this._socket.onClosed = (event) => { this.onClosed(event) };
|
||||
this._isSocketInit = true;
|
||||
}
|
||||
|
||||
// 网络连接成功
|
||||
protected onConnected(event) {
|
||||
console.log("NetNode onConnected!")
|
||||
this._isSocketOpen = true;
|
||||
// 如果设置了
|
||||
if (this._connectedCallback !== null) {
|
||||
this._state = NetNodeState.Checking;
|
||||
this._connectedCallback();
|
||||
} else {
|
||||
this.onChecked();
|
||||
}
|
||||
console.log("NetNode onConnected! state ="+this._state);
|
||||
}
|
||||
|
||||
// 连接验证成功,进入工作状态
|
||||
protected onChecked() {
|
||||
console.log("NetNode onChecked!")
|
||||
this._state = NetNodeState.Working;
|
||||
// 关闭重连中的状态显示
|
||||
if (this._networkTips !== null) {
|
||||
this._networkTips.reconnectTips(false);
|
||||
}
|
||||
// 重发待发送信息
|
||||
console.log(`NetNode flush ${this._requests.length} request`)
|
||||
if (this._requests.length > 0) {
|
||||
for (var i = 0; i < this._requests.length;) {
|
||||
let req = this._requests[i];
|
||||
this._socket.send(req.buffer);
|
||||
if (req.rspObject == null || req.rspCmd <= 0) {
|
||||
this._requests.splice(i, 1);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
// 如果还有等待返回的请求,启动网络请求层
|
||||
if (this._networkTips != null) {
|
||||
if (this._requests.length > 0) {
|
||||
console.log(`NetNode startRequestTips`)
|
||||
this._networkTips.requestTips(true);
|
||||
} else {
|
||||
this._networkTips.requestTips(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 接收到一个完整的消息包
|
||||
protected onMessage(msg): void {
|
||||
// console.log(`NetNode onMessage status = ` + this._state);
|
||||
// 进行头部的校验(实际包长与头部长度是否匹配)
|
||||
if (!this._protocolHelper.checkHead(msg)) {
|
||||
console.error(`NetNode checkHead Error`);
|
||||
return;
|
||||
}
|
||||
// 接受到数据,重新定时收数据计时器
|
||||
this.resetReceiveMsgTimer();
|
||||
// 重置心跳包发送器
|
||||
this.resetHearbeatTimer();
|
||||
// 触发消息执行
|
||||
let rspCmd = this._protocolHelper.checkCmd(msg);
|
||||
console.log(`NetNode onMessage rspCmd = ` + rspCmd);
|
||||
// 优先触发request队列
|
||||
if (this._requests.length > 0) {
|
||||
for (let reqIdx in this._requests) {
|
||||
let req = this._requests[reqIdx];
|
||||
if (req.rspCmd == rspCmd) {
|
||||
console.log(`NetNode execute request rspcmd ${rspCmd}`);
|
||||
this._callbackExecuter(req.rspObject, msg);
|
||||
this._requests.splice(parseInt(reqIdx), 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
console.log(`NetNode still has ${this._requests.length} request watting`);
|
||||
if (this._requests.length == 0 && this._networkTips) {
|
||||
this._networkTips.requestTips(false);
|
||||
}
|
||||
}
|
||||
|
||||
let listeners = this._listener[rspCmd];
|
||||
if (null != listeners) {
|
||||
for (const rsp of listeners) {
|
||||
console.log(`NetNode execute listener cmd ${rspCmd}`);
|
||||
this._callbackExecuter(rsp, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected onError(event) {
|
||||
console.error(event);
|
||||
}
|
||||
|
||||
protected onClosed(event) {
|
||||
this.clearTimer();
|
||||
|
||||
// 执行断线回调
|
||||
if (this._disconnectCallback && !this._disconnectCallback()) {
|
||||
console.log(`disconnect return!`)
|
||||
return;
|
||||
}
|
||||
|
||||
// 自动重连
|
||||
if (this._isAutoReconnect) {
|
||||
if (this._networkTips) {
|
||||
this._networkTips.reconnectTips(true);
|
||||
}
|
||||
this._reconnectTimer = setTimeout(() => {
|
||||
this._socket.close();
|
||||
this._state = NetNodeState.Closed;
|
||||
this.connect(this._host, this._port, this._isAutoReconnect, NetNodeConnectType.ReConnect);
|
||||
}, this._reconnetTimeOut);
|
||||
} else {
|
||||
this._state = NetNodeState.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
public close(code?: number, reason?: string) {
|
||||
this.clearTimer();
|
||||
this._listener = {};
|
||||
this._requests.length = 0;
|
||||
if (this._networkTips) {
|
||||
this._networkTips.reconnectTips(false);
|
||||
this._networkTips.requestTips(false);
|
||||
}
|
||||
if (this._socket) {
|
||||
this._socket.close(code, reason);
|
||||
} else {
|
||||
this._state = NetNodeState.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
// 只是关闭Socket套接字(仍然重用缓存与当前状态)
|
||||
public closeSocket(code?: number, reason?: string) {
|
||||
if (this._socket) {
|
||||
this._socket.close(code, reason);
|
||||
}
|
||||
}
|
||||
|
||||
// 发起请求,如果当前处于重连中,进入缓存列表等待重连完成后发送
|
||||
public send(buf: NetData, force: boolean = false) {
|
||||
if (this._state == NetNodeState.Working || force) {
|
||||
console.log(`socket send ...`);
|
||||
this._socket.send(buf);
|
||||
} else if (this._state == NetNodeState.Checking ||
|
||||
this._state == NetNodeState.Connecting) {
|
||||
this._requests.push({
|
||||
buffer: buf,
|
||||
rspCmd: 0,
|
||||
rspObject: null
|
||||
});
|
||||
console.log("NetNode socket is busy, push to send buffer, current state is " + this._state);
|
||||
} else {
|
||||
console.error("NetNode request error! current state is " + this._state);
|
||||
}
|
||||
}
|
||||
|
||||
// 发起请求,并进入缓存列表,
|
||||
public sendWithTimeout(buf: NetData, rspCmd: number, rspObject: CallbackObject, showTips: boolean = true, force: boolean = false) {
|
||||
if (this._state == NetNodeState.Working || force) {
|
||||
this._socket.send(buf);
|
||||
}
|
||||
console.log(`NetNode request with timeout for ${rspCmd}`);
|
||||
// 进入发送缓存列表
|
||||
this._requests.push({
|
||||
buffer: buf, rspCmd, rspObject
|
||||
});
|
||||
// 启动网络请求层
|
||||
if (this._networkTips !== null && showTips) {
|
||||
this._networkTips.requestTips(true);
|
||||
}
|
||||
}
|
||||
|
||||
/********************** 回调相关处理 *********************/
|
||||
public setResponeHandler(cmd: number, callback: NetCallFunc, target?: any): boolean {
|
||||
if (callback == null) {
|
||||
console.error(`NetNode setResponeHandler error ${cmd}`);
|
||||
return false;
|
||||
}
|
||||
this._listener[cmd] = [{ target, callback }];
|
||||
return true;
|
||||
}
|
||||
|
||||
public addResponeHandler(cmd: number, callback: NetCallFunc, target?: any): boolean {
|
||||
if (callback == null) {
|
||||
console.error(`NetNode addResponeHandler error ${cmd}`);
|
||||
return false;
|
||||
}
|
||||
let rspObject = { target, callback };
|
||||
if (null == this._listener[cmd]) {
|
||||
this._listener[cmd] = [rspObject];
|
||||
} else {
|
||||
let index = this.getNetListenersIndex(cmd, rspObject);
|
||||
if (-1 == index) {
|
||||
this._listener[cmd].push(rspObject);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public removeResponeHandler(cmd: number, callback: NetCallFunc, target?: any) {
|
||||
if (null != this._listener[cmd] && callback != null) {
|
||||
let index = this.getNetListenersIndex(cmd, { target, callback });
|
||||
if (-1 != index) {
|
||||
this._listener[cmd].splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected getNetListenersIndex(cmd: number, rspObject: CallbackObject): number {
|
||||
let index = -1;
|
||||
for (let i = 0; i < this._listener[cmd].length; i++) {
|
||||
let iterator = this._listener[cmd][i];
|
||||
if (iterator.callback == rspObject.callback
|
||||
&& iterator.target == rspObject.target) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/********************** 心跳、超时相关处理 *********************/
|
||||
protected resetReceiveMsgTimer() {
|
||||
if (this._receiveMsgTimer !== null) {
|
||||
clearTimeout(this._receiveMsgTimer);
|
||||
}
|
||||
|
||||
this._receiveMsgTimer = setTimeout(() => {
|
||||
console.warn("NetNode recvieMsgTimer close socket!");
|
||||
this._socket.close();
|
||||
}, this._receiveTime);
|
||||
}
|
||||
|
||||
protected resetHearbeatTimer() {
|
||||
if (this._keepAliveTimer !== null) {
|
||||
clearTimeout(this._keepAliveTimer);
|
||||
}
|
||||
|
||||
this._keepAliveTimer = setTimeout(() => {
|
||||
console.log("NetNode keepAliveTimer send Hearbeat")
|
||||
this.send(this._protocolHelper.getHearbeat());
|
||||
}, this._heartTime);
|
||||
}
|
||||
|
||||
protected clearTimer() {
|
||||
if (this._receiveMsgTimer !== null) {
|
||||
clearTimeout(this._receiveMsgTimer);
|
||||
}
|
||||
if (this._keepAliveTimer !== null) {
|
||||
clearTimeout(this._keepAliveTimer);
|
||||
}
|
||||
if (this._reconnectTimer !== null) {
|
||||
clearTimeout(this._reconnectTimer);
|
||||
}
|
||||
}
|
||||
|
||||
public rejectReConnect(){
|
||||
this._isAutoReconnect = false;
|
||||
this.clearTimer();
|
||||
}
|
||||
}
|
||||
9
assets/Script/network/NetNode.ts.meta
Normal file
9
assets/Script/network/NetNode.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "75b71ada-9878-434a-96fb-c03cfb4491c9",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
61
assets/Script/network/WebSock.ts
Normal file
61
assets/Script/network/WebSock.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { ISocket, NetData } from "./NetInterface";
|
||||
|
||||
/*
|
||||
* WebSocket封装
|
||||
* 1. 连接/断开相关接口
|
||||
* 2. 网络异常回调
|
||||
* 3. 数据发送与接收
|
||||
*
|
||||
* 2018-5-14 by 宝爷
|
||||
*/
|
||||
|
||||
export class WebSock implements ISocket {
|
||||
private _ws: WebSocket = null; // websocket对象
|
||||
|
||||
onConnected: (event) => void = null;
|
||||
onMessage: (msg) => void = null;
|
||||
onError: (event) => void = null;
|
||||
onClosed: (event) => void = null;
|
||||
|
||||
connect(options: any) {
|
||||
if (this._ws) {
|
||||
if (this._ws.readyState === WebSocket.CONNECTING) {
|
||||
console.log("websocket connecting, wait for a moment...")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let url = null;
|
||||
if(options.url) {
|
||||
url = options.url;
|
||||
} else {
|
||||
let ip = options.ip;
|
||||
let port = options.port;
|
||||
let protocol = options.protocol;
|
||||
url = `${protocol}://${ip}:${port}`;
|
||||
}
|
||||
|
||||
this._ws = new WebSocket(url);
|
||||
this._ws.binaryType = options.binaryType ? options.binaryType : "arraybuffer";
|
||||
this._ws.onmessage = (event) => {
|
||||
this.onMessage(event.data);
|
||||
};
|
||||
this._ws.onopen = this.onConnected;
|
||||
this._ws.onerror = this.onError;
|
||||
this._ws.onclose = this.onClosed;
|
||||
return true;
|
||||
}
|
||||
|
||||
send(buffer: NetData) {
|
||||
if (this._ws.readyState == WebSocket.OPEN)
|
||||
{
|
||||
this._ws.send(buffer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
close(code?: number, reason?: string) {
|
||||
this._ws.close();
|
||||
}
|
||||
}
|
||||
9
assets/Script/network/WebSock.ts.meta
Normal file
9
assets/Script/network/WebSock.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "7c5d5446-f565-45c1-9e5d-e9c46c91f3a3",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
||||
Reference in New Issue
Block a user