mirror of
https://github.com/JuLi0n21/goTsClient.git
synced 2026-04-19 16:00:07 +00:00
git ignore
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
flake-profile-1-link
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/nix/store/yir3akbqrs37krrd4v7kgb5qpjzws30d-nix-shell-env
|
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.direnv/
|
||||||
|
.envrc
|
||||||
|
client.ts
|
||||||
189
client.ts
189
client.ts
@@ -1,189 +0,0 @@
|
|||||||
// --- AUTO-GENERATED ---
|
|
||||||
// Generated by generator. Do not edit by hand (unless you know what you do).
|
|
||||||
// Types
|
|
||||||
|
|
||||||
export interface ReceiveValue {
|
|
||||||
Field: string[];
|
|
||||||
Second: number;
|
|
||||||
Uhhhh?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReturnValue {
|
|
||||||
Field: string[];
|
|
||||||
Second: number;
|
|
||||||
Uhhhh?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic RPC method result
|
|
||||||
export type RPCResult<T> = { data: T; error?: any };
|
|
||||||
|
|
||||||
export interface RPCClient {
|
|
||||||
ComplexThings(arg0: string[]): Promise<RPCResult<{ [key: string]: number }>>;
|
|
||||||
EmptyParams(): Promise<RPCResult<string>>;
|
|
||||||
ManyParams(arg0: number, arg1: number, arg2: number, arg3: number, arg4: number, arg5: number, arg6: number, arg7: number, arg8: number): Promise<RPCResult<string>>;
|
|
||||||
Structs(receiveValue: ReceiveValue): Promise<RPCResult<ReturnValue>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WSBackend {
|
|
||||||
private ws: WebSocket | null = null;
|
|
||||||
private tokenProvider?: () => string;
|
|
||||||
private url: string;
|
|
||||||
private callbacks: Record<string, {
|
|
||||||
callback: (err: any, res: any) => void;
|
|
||||||
timeout: ReturnType<typeof setTimeout>;
|
|
||||||
}> = {};
|
|
||||||
private counter = 0;
|
|
||||||
private _api: any = null;
|
|
||||||
private queue: Array<{ id: string; method: string; params: any[]; resolve: Function; reject: Function }> = [];
|
|
||||||
private reconnectDelay = 1000;
|
|
||||||
private _connected = false;
|
|
||||||
private connectedListeners: Array<() => void> = [];
|
|
||||||
private disconnectedListeners: Array<() => void> = [];
|
|
||||||
private callTimeout = 10000; // 10 second timeout for calls
|
|
||||||
|
|
||||||
constructor(url: string) {
|
|
||||||
this.url = url;
|
|
||||||
this._api = new Proxy({}, {
|
|
||||||
get: (_t, method: string) => (...args: any[]) => this.call(method, args)
|
|
||||||
});
|
|
||||||
this.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
public setTokenProvider(fn: () => string) {
|
|
||||||
this.tokenProvider = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get api() {
|
|
||||||
return this._api;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get connected() {
|
|
||||||
return this._connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
public onConnected(cb: () => void) {
|
|
||||||
this.connectedListeners.push(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
public onDisconnected(cb: () => void) {
|
|
||||||
this.disconnectedListeners.push(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setCallTimeout(ms: number) {
|
|
||||||
this.callTimeout = ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
private connect() {
|
|
||||||
this.ws = new WebSocket(this.url);
|
|
||||||
|
|
||||||
this.ws.onopen = () => {
|
|
||||||
console.log("[WS] Connected to", this.url);
|
|
||||||
this._connected = true;
|
|
||||||
this.connectedListeners.forEach(cb => cb());
|
|
||||||
|
|
||||||
this.queue.forEach(item => {
|
|
||||||
this._send(item.id, item.method, item.params);
|
|
||||||
});
|
|
||||||
this.queue = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
this.ws.onmessage = (evt) => {
|
|
||||||
let msg: any;
|
|
||||||
try {
|
|
||||||
msg = JSON.parse(evt.data);
|
|
||||||
} catch {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const callbackData = this.callbacks[msg.id];
|
|
||||||
if (!callbackData) return;
|
|
||||||
|
|
||||||
clearTimeout(callbackData.timeout);
|
|
||||||
|
|
||||||
if (msg.result && typeof msg.result === "object" && ("data" in msg.result || "error" in msg.result)) {
|
|
||||||
const r = msg.result;
|
|
||||||
callbackData.callback(r.error, r.data);
|
|
||||||
} else {
|
|
||||||
callbackData.callback(msg.error, msg.result);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete this.callbacks[msg.id];
|
|
||||||
};
|
|
||||||
|
|
||||||
this.ws.onclose = () => {
|
|
||||||
const wasConnected = this._connected;
|
|
||||||
this._connected = false;
|
|
||||||
|
|
||||||
Object.keys(this.callbacks).forEach(id => {
|
|
||||||
const callbackData = this.callbacks[id];
|
|
||||||
clearTimeout(callbackData.timeout);
|
|
||||||
callbackData.callback({ message: 'WebSocket disconnected' }, null);
|
|
||||||
delete this.callbacks[id];
|
|
||||||
});
|
|
||||||
|
|
||||||
if (wasConnected) {
|
|
||||||
this.disconnectedListeners.forEach(cb => cb());
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("[WS] Disconnected. Reconnecting...");
|
|
||||||
setTimeout(() => this.connect(), this.reconnectDelay);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.ws.onerror = (e) => {
|
|
||||||
console.warn("[WS] Error:", e);
|
|
||||||
this.ws?.close();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private call(method: string, params: any[]): Promise<any> {
|
|
||||||
const id = (++this.counter).toString();
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
if (this.callbacks[id]) {
|
|
||||||
console.warn(`[WS] Call timeout for \${method} (id: \${id})`);
|
|
||||||
this.callbacks[id].callback({ message: 'Request timeout' }, null);
|
|
||||||
delete this.callbacks[id];
|
|
||||||
}
|
|
||||||
}, this.callTimeout);
|
|
||||||
|
|
||||||
this.callbacks[id] = {
|
|
||||||
callback: (err, res) => {
|
|
||||||
resolve({ data: res, error: err });
|
|
||||||
},
|
|
||||||
timeout
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this._connected && this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
||||||
this._send(id, method, params);
|
|
||||||
} else {
|
|
||||||
console.log("[WS] Queueing call", method, id, params);
|
|
||||||
this.queue.push({ id, method, params, resolve, reject: () => { } });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _send(id: string, method: string, params: any[]) {
|
|
||||||
if (!this.ws) throw new Error("WebSocket not initialized");
|
|
||||||
const msg: any = { id, method, params };
|
|
||||||
if (this.tokenProvider) msg.token = this.tokenProvider();
|
|
||||||
this.ws.send(JSON.stringify(msg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let backendWrapper: WSBackend | null = null;
|
|
||||||
let backendInstance: RPCClient | null = null;
|
|
||||||
|
|
||||||
export function useBackend(url: string = '/ws'): { api: RPCClient, backend: WSBackend } {
|
|
||||||
if (url.startsWith('/')) {
|
|
||||||
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
|
||||||
const host = window.location.host;
|
|
||||||
url = `${protocol}://${host}${url}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!backendWrapper) {
|
|
||||||
backendWrapper = new WSBackend(url);
|
|
||||||
backendInstance = backendWrapper.api as unknown as RPCClient;
|
|
||||||
}
|
|
||||||
return { api: backendInstance!, backend: backendWrapper! };
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
devShells.x86_64-linux.default = pkgs.mkShell {
|
devShells.x86_64-linux.default = pkgs.mkShell {
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
go_1_26
|
go_1_26
|
||||||
|
|
||||||
nodejs_24
|
nodejs_24
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
func wsHandler(api any) func(*websocket.Conn) {
|
func WsHandler(api any) func(*websocket.Conn) {
|
||||||
return func(ws *websocket.Conn) {
|
return func(ws *websocket.Conn) {
|
||||||
apiVal := reflect.ValueOf(api)
|
apiVal := reflect.ValueOf(api)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user