@use itertools::Itertools; @use crate::data::RPC; @use crate::generators::ts_c::*; @(rpc: &RPC) @for e in &rpc.enums { export enum @e.name @{ @for (k,v) in &e.values { @k = @v, } @} } @for s in &rpc.structs { export interface @s.name @{ @for f in &s.fields { @f.name: @ty_to_str(&f.ty); } @} } interface _WSResponse @{ id: number; data: any; @} interface _WSWaitingEntry @{ ok: (v: any) => void; err: (reason?: any) => void; @} export class MRPCConnector @{ url: string; socket: WebSocket; nmi: number; waiting: @{ [id: number]: _WSWaitingEntry @}; streams: @{ [id: number]: (v: any) => void @}; private open() @{ this.socket = new WebSocket(this.url); this.socket.onmessage = ev => @{ const data = JSON.parse(ev.data) as _WSResponse; if (data.id in this.streams) @{ this.streams[data.id](data.data); if (data.data == null) delete this.streams[data.id]; @} else if (data.id in this.waiting) @{ this.waiting[data.id].ok(data.data); delete this.waiting[data.id]; @} else @{ console.log(`Got unexpected message: $@{data@}`); @} @} this.socket.onerror = () => setTimeout(() => @{this.open();@}, 2500); this.socket.onclose = () => setTimeout(() => @{this.open();@}, 2500); @} private get_prom(id: number): Promise @{ return new Promise((ok, err) => @{ this.waiting[id] = @{ok, err@}; @}); @} public constructor(url: string) @{ this.url = url; this.nmi = 0; this.waiting = @{@}; this.streams = @{@}; this.open(); @} @for s in &rpc.services { @for m in &s.methods { public @(s.name)_@(m.name)(@method_args(m))@method_ret(m) @{ const __msg = @{ id: this.nmi++, service: '@s.name', method: '@m.name', data: @{@m.args.iter().map(|a| &a.name).join(",")@} @}; @if m.ret.is_some() && !m.ret_stream {const __p = this.get_prom<@ty_to_str(m.ret.as_ref().unwrap())>(__msg.id);} else if m.ret_stream {this.streams[__msg.id] = __cbk;} this.socket.send(JSON.stringify(__msg)); @if m.ret.is_some() && !m.ret_stream {return __p;} @} }} @}