[fix]
This commit is contained in:
parent
3be734f6fc
commit
a554bb8473
@ -1,5 +1,5 @@
|
|||||||
# sudo docker build -t guesswhoiams .
|
# sudo docker build -t guesswhoiams .
|
||||||
# sudo docker exec -it 2e8e3995aa52 /bin/bash
|
# sudo docker exec -it 51bd6c84a7f2 /bin/bash
|
||||||
|
|
||||||
FROM node:19.4.0
|
FROM node:19.4.0
|
||||||
|
|
||||||
@ -31,4 +31,5 @@ EXPOSE 3003
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# 指定啟動container後執行命令
|
# 指定啟動container後執行命令
|
||||||
CMD [ "npm", "start" ]
|
CMD node index.js
|
||||||
|
# CMD [ "npm", "start" ]
|
@ -1,4 +1,5 @@
|
|||||||
import Client from "../../../../Client/Client"
|
import Client from "../../../../component/Client/Client"
|
||||||
|
|
||||||
|
|
||||||
export interface INetResponse<TResponse> {
|
export interface INetResponse<TResponse> {
|
||||||
readonly Method: string
|
readonly Method: string
|
||||||
|
@ -1,263 +0,0 @@
|
|||||||
import { BaseEnumerator } from "../CoroutineV2/Core/BaseEnumerator";
|
|
||||||
import { Action } from "../CSharp/System/Action";
|
|
||||||
import { Encoding } from "../CSharp/System/Text/Encoding";
|
|
||||||
import { INetRequest } from "./Core/INetRequest";
|
|
||||||
import { INetResponse } from "./Core/INetResponse";
|
|
||||||
import NetConfig from "./NetConfig";
|
|
||||||
|
|
||||||
export class NetConnector {
|
|
||||||
readonly OnDataReceived: Action<INetResponse<any>> = new Action<INetResponse<any>>();
|
|
||||||
readonly OnDisconnected: Action<void> = new Action<void>();
|
|
||||||
readonly OnLoadUIMask: Action<boolean> = new Action<boolean>();
|
|
||||||
|
|
||||||
get IsConnected() {
|
|
||||||
return this._ws && this._ws.readyState === WebSocket.OPEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get ws(): WebSocket {
|
|
||||||
return this._ws;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _host: string;
|
|
||||||
private _ws: WebSocket;
|
|
||||||
private _waitings: WsRequestEnumerator[] = [];
|
|
||||||
|
|
||||||
constructor(host: string, port: number) {
|
|
||||||
let checkHttp: string = "";
|
|
||||||
let index: number = host.indexOf("https://");
|
|
||||||
if (index != -1) {
|
|
||||||
checkHttp = "https";
|
|
||||||
host = host.replace("https://", "");
|
|
||||||
} else {
|
|
||||||
checkHttp = window.location.href.substring(0, 5);
|
|
||||||
host = host.replace("http://", "");
|
|
||||||
}
|
|
||||||
// if (CC_DEBUG) {
|
|
||||||
console.debug("[事件]checkHttp=", checkHttp, host, port);
|
|
||||||
// }
|
|
||||||
if (checkHttp != "https") {
|
|
||||||
this._host = `ws://${host}:${port}`;
|
|
||||||
} else {
|
|
||||||
this._host = `wss://${host}:${port}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectAsync() {
|
|
||||||
if (this._ws) {
|
|
||||||
throw new Error("請先執行CasinoNetManager.Disconnect()中斷連線");
|
|
||||||
}
|
|
||||||
this._ws = new WebSocket(this._host);
|
|
||||||
|
|
||||||
this._ws.binaryType = "arraybuffer";
|
|
||||||
this._ws.onopen = this.OnWebSocketOpen.bind(this);
|
|
||||||
this._ws.onmessage = this.OnWebSocketMessage.bind(this);
|
|
||||||
this._ws.onclose = this.OnWebSocketClose.bind(this);
|
|
||||||
this._ws.onerror = this.OnWebSocketError.bind(this);
|
|
||||||
|
|
||||||
return new WsConnectEnumerator(this._ws);
|
|
||||||
}
|
|
||||||
|
|
||||||
Send(req: INetRequest<any, any>) {
|
|
||||||
if (!this.IsConnected) return;
|
|
||||||
|
|
||||||
let json = [req.Method];
|
|
||||||
if (req.Data != null && req.Data != undefined && !Number.isNaN(req.Data)) {
|
|
||||||
json[1] = req.Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (CC_DEBUG && NetConfig.ShowServerLog) {
|
|
||||||
if (NetConfig.ShowServerLog) {
|
|
||||||
if (req.Data != null && req.Data != undefined && !Number.isNaN(req.Data)) {
|
|
||||||
console.debug(`[RPC] 傳送client資料: ${req.Method}(${JSON.stringify(req.Data)})`);
|
|
||||||
} else {
|
|
||||||
console.debug(`[RPC] 傳送client資料: ${req.Method}()`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let str = JSON.stringify(json);
|
|
||||||
if (str.length > 65535) {
|
|
||||||
throw new Error("要傳的資料太大囉");
|
|
||||||
}
|
|
||||||
|
|
||||||
let strary = Encoding.UTF8.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);
|
|
||||||
|
|
||||||
this._ws.send(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
SendAsync(req: INetRequest<any, any>, mask: boolean) {
|
|
||||||
let iterator = new WsRequestEnumerator(req);
|
|
||||||
if (!this.IsConnected) {
|
|
||||||
iterator.SetResponse(ErrorResponse);
|
|
||||||
} else {
|
|
||||||
this._waitings.push(iterator);
|
|
||||||
if (mask) {
|
|
||||||
this.OnLoadUIMask.DispatchCallback(true);
|
|
||||||
}
|
|
||||||
this.Send(req);
|
|
||||||
}
|
|
||||||
return iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
Disconnect() {
|
|
||||||
this.WebSocketEnded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private WebSocketEnded() {
|
|
||||||
if (!this._ws) return;
|
|
||||||
|
|
||||||
this._ws.close();
|
|
||||||
this._ws.onopen = null;
|
|
||||||
this._ws.onmessage = null;
|
|
||||||
this._ws.onclose = () => {
|
|
||||||
};
|
|
||||||
this._ws = null;
|
|
||||||
|
|
||||||
this.CleanWaitings();
|
|
||||||
this.OnDisconnected.DispatchCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
private CleanWaitings() {
|
|
||||||
for (let w of this._waitings) {
|
|
||||||
w.SetResponse(ErrorResponse);
|
|
||||||
this.OnLoadUIMask.DispatchCallback(false);
|
|
||||||
}
|
|
||||||
this._waitings.length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private OnWebSocketOpen(e: Event) {
|
|
||||||
// if (CC_DEBUG) {
|
|
||||||
console.debug(`[RPC] ${this._host} Connected.`);
|
|
||||||
// }
|
|
||||||
// this.event.emit(Define.Event.Socket.Connect);
|
|
||||||
}
|
|
||||||
|
|
||||||
private OnWebSocketMessage(e: MessageEvent) {
|
|
||||||
if (e.data instanceof ArrayBuffer) {
|
|
||||||
this.ParseRpcMessage(e.data, e);
|
|
||||||
} else if (e.data instanceof Blob) {
|
|
||||||
let reader = new FileReader();
|
|
||||||
reader.onload = (e) => {
|
|
||||||
this.ParseRpcMessage(<ArrayBuffer>reader.result, e);
|
|
||||||
reader.onload = null;
|
|
||||||
};
|
|
||||||
reader.readAsArrayBuffer(e.data);
|
|
||||||
} else {
|
|
||||||
throw new Error(`未知的OnWebSocketMessage(e.data)類型: ${e.data}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ParseRpcMessage(buffer: ArrayBuffer, e: any) {
|
|
||||||
let startIndex = 0, byteLength = buffer.byteLength;
|
|
||||||
while (startIndex + 4 < byteLength) {
|
|
||||||
let strlen = new DataView(buffer, startIndex, 3).getUint16(0, true);
|
|
||||||
let str = Encoding.UTF8.GetString(new Uint8Array(buffer, startIndex + 4, strlen));
|
|
||||||
startIndex += strlen + 4;
|
|
||||||
|
|
||||||
try {
|
|
||||||
let json = JSON.parse(str);
|
|
||||||
let method = <string>json[0];
|
|
||||||
let status = <number>json[1][0];
|
|
||||||
let data = json[1][1];
|
|
||||||
|
|
||||||
let resp = <INetResponse<any>>{
|
|
||||||
Method: method,
|
|
||||||
Status: status,
|
|
||||||
Data: data,
|
|
||||||
IsValid: method && status === 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// if (CC_DEBUG && NetConfig.ShowServerLog) {
|
|
||||||
if (NetConfig.ShowServerLog) {
|
|
||||||
if (data) {
|
|
||||||
console.debug(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`);
|
|
||||||
} else {
|
|
||||||
console.debug(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let dispatch = true;
|
|
||||||
let isCocos = false;
|
|
||||||
for (let i = 0, len = this._waitings.length; i < len; i++) {
|
|
||||||
let w = this._waitings[i];
|
|
||||||
if (w.MethodBack === resp.Method) {
|
|
||||||
dispatch = false;
|
|
||||||
this._waitings.splice(i, 1);
|
|
||||||
w.SetResponse(resp);
|
|
||||||
this.OnLoadUIMask.DispatchCallback(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dispatch) {
|
|
||||||
this.OnDataReceived.DispatchCallback(resp);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
throw new Error(`[RPC] 無法解析Server回應: ${str}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private OnWebSocketClose(e: CloseEvent) {
|
|
||||||
this.WebSocketEnded();
|
|
||||||
// this.event.emit(Define.Event.Socket.Disconnect);
|
|
||||||
}
|
|
||||||
|
|
||||||
private OnWebSocketError(e: CloseEvent) {
|
|
||||||
// this.event.emit(Define.Event.Socket.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ErrorResponse: INetResponse<any> = {
|
|
||||||
Status: -1,
|
|
||||||
Method: "",
|
|
||||||
Data: {},
|
|
||||||
IsValid: false,
|
|
||||||
WS: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
class WsConnectEnumerator extends BaseEnumerator {
|
|
||||||
private _ws: WebSocket;
|
|
||||||
|
|
||||||
constructor(ws: WebSocket) {
|
|
||||||
super();
|
|
||||||
this._ws = ws;
|
|
||||||
}
|
|
||||||
|
|
||||||
next(value?: any): IteratorResult<any> {
|
|
||||||
return {
|
|
||||||
done: this._ws.readyState === WebSocket.OPEN || this._ws.readyState === WebSocket.CLOSED,
|
|
||||||
value: undefined
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WsRequestEnumerator extends BaseEnumerator {
|
|
||||||
readonly MethodBack: string;
|
|
||||||
|
|
||||||
private _req: INetRequest<any, any>;
|
|
||||||
private _done: boolean = false;
|
|
||||||
|
|
||||||
constructor(req: INetRequest<any, any>) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this._req = req;
|
|
||||||
this.MethodBack = req.MethodBack;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetResponse(resp: INetResponse<any>) {
|
|
||||||
this._req.Result = resp;
|
|
||||||
this._done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
next(value?: any): IteratorResult<any> {
|
|
||||||
return {
|
|
||||||
done: this._done,
|
|
||||||
value: undefined
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
import { INetRequest } from "./Core/INetRequest";
|
|
||||||
import { NetConnector } from "./NetConnector";
|
|
||||||
|
|
||||||
export class NetManager {
|
|
||||||
static get IsConnected() {
|
|
||||||
return this._connector && this._connector.IsConnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get HasInit() {
|
|
||||||
return this._connector != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _connector: NetConnector;
|
|
||||||
|
|
||||||
static Initialize(connector: NetConnector) {
|
|
||||||
this._connector = connector;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ConnectAsync() {
|
|
||||||
this.CheckConnector();
|
|
||||||
return this._connector.ConnectAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 斷線
|
|
||||||
*/
|
|
||||||
static Disconnect() {
|
|
||||||
this.CheckConnector();
|
|
||||||
this._connector.Disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 傳送資料給Server, 不等待回應
|
|
||||||
* @param req
|
|
||||||
*/
|
|
||||||
static Send(req: INetRequest<any, any>) {
|
|
||||||
this.CheckConnector();
|
|
||||||
this._connector.Send(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 傳送資料給Server, 並等待回應
|
|
||||||
* @param req
|
|
||||||
*/
|
|
||||||
static SendAsync(req: INetRequest<any, any>, mask: boolean) {
|
|
||||||
this.CheckConnector();
|
|
||||||
return this._connector.SendAsync(req, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CheckConnector() {
|
|
||||||
if (!this._connector) throw new Error("請先呼叫CasinoNetManager.Initialize()初始化connector");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
import { INetRequest } from "./Core/INetRequest";
|
|
||||||
|
|
||||||
export abstract class NetRequest<TResquest, TResponse> implements INetRequest<TResquest, TResponse> {
|
|
||||||
abstract get Method(): string;
|
|
||||||
|
|
||||||
get MethodBack(): string {
|
|
||||||
return this.Method;
|
|
||||||
}
|
|
||||||
|
|
||||||
Data: TResquest;
|
|
||||||
Result: import("./Core/INetResponse").INetResponse<TResponse>;
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 在大廳呼叫Cocos會收到SERVER主動通知
|
|
||||||
// * 在大廳呼叫Cocos會收到SERVER主動通知
|
|
||||||
// * 在大廳呼叫Cocos會收到SERVER主動通知
|
|
||||||
// */
|
|
||||||
// SendAsync(mask: boolean = false): Iterator<any> {
|
|
||||||
// // return NetManager.SendAsync(this, mask);
|
|
||||||
// return VueNetConnector.SendAsync(this, mask);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Send() {
|
|
||||||
// // NetManager.Send(this);
|
|
||||||
// VueNetConnector.Send(this);
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import { INetResponse } from "./Core/INetResponse"
|
|
||||||
|
|
||||||
export abstract class NetResponse implements INetResponse<any> {
|
|
||||||
protected data: any = undefined
|
|
||||||
protected method: string = ""
|
|
||||||
protected status: number = undefined
|
|
||||||
|
|
||||||
get Method(): string {
|
|
||||||
return this.method
|
|
||||||
}
|
|
||||||
get Status(): number {
|
|
||||||
return this.status
|
|
||||||
}
|
|
||||||
get Data(): any {
|
|
||||||
return this.data
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(data: any = undefined, status: number = 0) {
|
|
||||||
this.data = data ?? ""
|
|
||||||
this.status = status
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user