202 lines
7.1 KiB
TypeScript
202 lines
7.1 KiB
TypeScript
const { ccclass, property } = cc._decorator;
|
||
|
||
@ccclass
|
||
export default class WebSocketSeverClass extends cc.Component {
|
||
//#region 外調參數
|
||
|
||
@property({ type: cc.Label })
|
||
public Label: cc.Label = null;
|
||
|
||
//#endregion
|
||
|
||
//#region Lifecycle
|
||
|
||
protected onLoad(): void {
|
||
let self: this = this;
|
||
// 在原生平台的 Release 模式下或者在 Web/微信小游戏等平台中,WebSocketServer 可能没有定义
|
||
if (typeof WebSocketServer === "undefined") {
|
||
self._addLog("WebSocketServer is not enabled!");
|
||
return;
|
||
}
|
||
switch (cc.sys.getNetworkType()) {
|
||
case cc.sys.NetworkType.LAN: {
|
||
self._addLog("已連接Wifi");
|
||
break;
|
||
}
|
||
|
||
case cc.sys.NetworkType.WWAN: {
|
||
self._addLog("未連接Wifi");
|
||
break;
|
||
}
|
||
|
||
case cc.sys.NetworkType.NONE: {
|
||
self._addLog("未連接Network");
|
||
return;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
let ws: any = new WebSocketServer();
|
||
ws.onconnection = function (conn: any): any {
|
||
self._addLog(`${conn.headers["origin:"]} connect!`);
|
||
conn.ondata = function (data: any): any {
|
||
self._addLog(`${conn.headers["origin:"]} ondata!`);
|
||
self.ParseRpcMessage.bind(self)(data);
|
||
self.SendData.bind(self)(ws, "acc", "666");
|
||
};
|
||
|
||
conn.onclose = function (): any {
|
||
self._addLog(`${conn.headers["origin:"]} connection gone!`);
|
||
};
|
||
};
|
||
|
||
ws.onclose = function (): any {
|
||
self._addLog("server is closed!");
|
||
};
|
||
|
||
ws.listen(9005, (err: any): any => {
|
||
if (err) {
|
||
return;
|
||
}
|
||
self._addLog("server booted!");
|
||
});
|
||
}
|
||
|
||
private _addLog(msg: string): void {
|
||
console.log(msg);
|
||
this.Label.string += `\n\n${msg}`;
|
||
}
|
||
|
||
public SendData(ws, Method, Data) {
|
||
let json = [Method];
|
||
if (Data != null && Data != undefined && Data != NaN) {
|
||
json[1] = Data;
|
||
}
|
||
|
||
let str = JSON.stringify(json);
|
||
if (str.length > 65535) {
|
||
this._addLog("要傳的資料太大囉");
|
||
throw new Error('要傳的資料太大囉');
|
||
}
|
||
|
||
if (Data != null && Data != undefined && Data != NaN) {
|
||
this._addLog(`[RPC] 傳送server資料: ${Method}(${JSON.stringify(Data).replace(/\\/g, "")})`);
|
||
} else {
|
||
this._addLog(`[RPC] 傳送server資料: ${Method}()`);
|
||
}
|
||
|
||
let strary = this.GetBytes(str);
|
||
let buffer = new Uint8Array(4 + strary.byteLength);
|
||
let u16ary = new Uint16Array(buffer.buffer, 0, 3);
|
||
u16ary[0] = strary.byteLength;
|
||
buffer[3] = 0x01;
|
||
buffer.set(strary, 4);
|
||
ws.send(buffer, (err: any) => {
|
||
this._addLog(`${ws.headers["origin:"]} send!`);
|
||
//
|
||
});
|
||
}
|
||
|
||
public ParseRpcMessage(buffer) {
|
||
let startIndex = 0, byteLength = buffer.byteLength;
|
||
while (startIndex + 4 < byteLength) {
|
||
let strlen = new DataView(buffer, startIndex, 3).getUint16(0, true);
|
||
let str = this.GetString(new Uint8Array(buffer, startIndex + 4, strlen));
|
||
startIndex += strlen + 4;
|
||
|
||
try {
|
||
let json = JSON.parse(str);
|
||
let method = json[0];
|
||
let status = json[1][0];
|
||
let data = json[1][1];
|
||
|
||
let resp = {
|
||
Method: method,
|
||
Status: status,
|
||
Data: data,
|
||
IsValid: method && status === 0
|
||
};
|
||
|
||
if (data) {
|
||
this._addLog(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`);
|
||
// ResData(resp.Status, resp.Method, resp.Data);
|
||
} else {
|
||
this._addLog(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`);
|
||
// ResData(resp.Status, resp.Method);
|
||
}
|
||
} catch {
|
||
this._addLog(`[RPC] 無法解析Server回應: ${str}`);
|
||
throw new Error(`[RPC] 無法解析Server回應: ${str}`);
|
||
}
|
||
}
|
||
}
|
||
|
||
public GetString(array) {
|
||
let str = "";
|
||
let i = 0, len = array.length;
|
||
while (i < len) {
|
||
let c = array[i++];
|
||
switch (c >> 4) {
|
||
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
|
||
str += String.fromCharCode(c);
|
||
break;
|
||
case 12: case 13:
|
||
str += String.fromCharCode(((c & 0x1F) << 6) | (array[i++] & 0x3F));
|
||
break;
|
||
case 14:
|
||
str += String.fromCharCode(((c & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | ((array[i++] & 0x3F) << 0));
|
||
break;
|
||
}
|
||
}
|
||
return str;
|
||
}
|
||
|
||
public GetBytes(str) {
|
||
let len = str.length, resPos = -1;
|
||
let resArr = new Uint8Array(len * 3);
|
||
for (let point = 0, nextcode = 0, i = 0; i !== len;) {
|
||
point = str.charCodeAt(i), i += 1;
|
||
if (point >= 0xD800 && point <= 0xDBFF) {
|
||
if (i === len) {
|
||
resArr[resPos += 1] = 0xef;
|
||
resArr[resPos += 1] = 0xbf;
|
||
resArr[resPos += 1] = 0xbd;
|
||
break;
|
||
}
|
||
|
||
nextcode = str.charCodeAt(i);
|
||
if (nextcode >= 0xDC00 && nextcode <= 0xDFFF) {
|
||
point = (point - 0xD800) * 0x400 + nextcode - 0xDC00 + 0x10000;
|
||
i += 1;
|
||
if (point > 0xffff) {
|
||
resArr[resPos += 1] = (0x1e << 3) | (point >>> 18);
|
||
resArr[resPos += 1] = (0x2 << 6) | ((point >>> 12) & 0x3f);
|
||
resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f);
|
||
resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f);
|
||
continue;
|
||
}
|
||
} else {
|
||
resArr[resPos += 1] = 0xef;
|
||
resArr[resPos += 1] = 0xbf;
|
||
resArr[resPos += 1] = 0xbd;
|
||
continue;
|
||
}
|
||
}
|
||
if (point <= 0x007f) {
|
||
resArr[resPos += 1] = (0x0 << 7) | point;
|
||
} else if (point <= 0x07ff) {
|
||
resArr[resPos += 1] = (0x6 << 5) | (point >>> 6);
|
||
resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f);
|
||
} else {
|
||
resArr[resPos += 1] = (0xe << 4) | (point >>> 12);
|
||
resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f);
|
||
resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f);
|
||
}
|
||
}
|
||
return resArr.subarray(0, resPos + 1);
|
||
}
|
||
|
||
//#endregion
|
||
}
|