@mercuryworkshop/wisp-js
Advanced tools
Comparing version 0.2.0 to 0.2.1
@@ -1,1 +0,1 @@ | ||
var wisp_full;(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{client:()=>i,packet:()=>s,server:()=>n});var s={};t.r(s),t.d(s,{ClosePayload:()=>b,ConnectPayload:()=>f,ContinuePayload:()=>m,DataPayload:()=>y,WispBuffer:()=>d,WispPacket:()=>w,close_reasons:()=>z,packet_classes:()=>k,packet_types:()=>g,stream_types:()=>v});var i={};t.r(i),t.d(i,{ClientConnection:()=>C,WispWebSocket:()=>P,_wisp_connections:()=>E});var n={};t.r(n),t.d(n,{ServerConnection:()=>X,ServerStream:()=>Q,options:()=>I,routeRequest:()=>tt});const a=globalThis.WebSocket,o=globalThis.crypto,r=null,c=null,h=null,l=new TextEncoder,u=l.encode.bind(l),_=new TextDecoder,p=_.decode.bind(_);class d{constructor(t){if(t instanceof Uint8Array)this.from_array(t);else if("number"==typeof t)this.from_array(new Uint8Array(t));else{if("string"!=typeof t)throw console.trace(),"invalid data type passed to wisp buffer constructor";this.from_array(u(t))}}from_array(t){this.size=t.length,this.bytes=t,this.view=new DataView(t.buffer)}concat(t){let e=new d(this.size+t.size);return e.bytes.set(this.bytes,0),e.bytes.set(t.bytes,this.size),e}slice(t,e){let s=this.bytes.slice(t,e);return new d(s)}}class w{static min_size=5;constructor({type:t,stream_id:e,payload:s,payload_bytes:i}){this.type=t,this.stream_id=e,this.payload_bytes=i,this.payload=s}static parse(t){return new w({type:t.view.getUint8(0),stream_id:t.view.getUint32(1,!0),payload_bytes:t.slice(5)})}static parse_all(t){if(t.size<w.min_size)throw"packet too small";let e=w.parse(t),s=k[e.type];if(void 0===s)throw"invalid packet type";if(e.payload_bytes.size<s.size)throw"payload too small";return e.payload=s.parse(e.payload_bytes),e}serialize(){let t=new d(5);return t.view.setUint8(0,this.type),t.view.setUint32(1,this.stream_id,!0),t=t.concat(this.payload.serialize()),t}}class f{static min_size=3;static type=1;static name="CONNECT";constructor({stream_type:t,port:e,hostname:s}){this.stream_type=t,this.port=e,this.hostname=s}static parse(t){return new f({stream_type:t.view.getUint8(0),port:t.view.getUint16(1,!0),hostname:p(t.slice(3).bytes)})}serialize(){let t=new d(3);return t.view.setUint8(0,this.stream_type),t.view.setUint16(1,this.port,!0),t=t.concat(new d(this.hostname)),t}}class y{static min_size=0;static type=2;static name="DATA";constructor({data:t}){this.data=t}static parse(t){return new y({data:t})}serialize(){return this.data}}class m{static type=3;static name="CONTINUE";constructor({buffer_remaining:t}){this.buffer_remaining=t}static parse(t){return new m({buffer_remaining:t.view.getUint32(0,!0)})}serialize(){let t=new d(4);return t.view.setUint32(0,this.buffer_remaining,!0),t}}class b{static min_size=1;static type=4;static name="CLOSE";constructor({reason:t}){this.reason=t}static parse(t){return new b({reason:t.view.getUint8(0)})}serialize(){let t=new d(1);return t.view.setUint8(0,this.buffer_remaining),t}}const k=[void 0,f,y,m,b],g={CONNECT:1,DATA:2,CONTINUE:3,CLOSE:4},v={TCP:1,UDP:2},z={Unknown:1,Voluntary:2,NetworkError:3,InvalidInfo:65,UnreachableHost:66,NoResponse:67,ConnRefused:68,TransferTimeout:71,HostBlocked:72,ConnThrottled:73,ClientError:129};class T{constructor(t,e,s,i,n,a,o){this.hostname=t,this.port=e,this.ws=s,this.buffer_size=i,this.stream_id=n,this.connection=a,this.stream_type=o,this.send_buffer=[],this.open=!0,this.onopen=()=>{},this.onclose=()=>{},this.onmessage=()=>{}}send(t){if(this.buffer_size>0||!this.open||this.stream_type===v.UDP){let e=new w({type:g.DATA,stream_id:this.stream_id,payload:new y({data:new d(t)})});this.ws.send(e.serialize().bytes),this.buffer_size--}else this.send_buffer.push(t)}continue_received(t){for(this.buffer_size=t;this.buffer_size>0&&this.send_buffer.length>0;)this.send(this.send_buffer.shift())}close(t=1){if(!this.open)return;let e=new w({type:g.CLOSE,stream_id,payload:new b({reason:t})});this.ws.send(e.serialize().bytes),this.open=!1,delete this.connection.active_streams[this.stream_id]}}class C{constructor(t){if(!t.endsWith("/"))throw"wisp endpoints must end with a trailing forward slash";this.wisp_url=t,this.max_buffer_size=null,this.active_streams={},this.connected=!1,this.connecting=!1,this.next_stream_id=1,this.onopen=()=>{},this.onclose=()=>{},this.onerror=()=>{},this.onmessage=()=>{},this.connect_ws()}connect_ws(){this.ws=new a(this.wisp_url),this.ws.binaryType="arraybuffer",this.connecting=!0,this.ws.onerror=()=>{this.on_ws_close(),this.onerror()},this.ws.onclose=()=>{this.on_ws_close(),this.onclose()},this.ws.onmessage=t=>{this.on_ws_msg(t),this.connecting&&(this.connected=!0,this.connecting=!1,this.onopen())}}close_stream(t,e){t.onclose(e),delete this.active_streams[t.stream_id]}on_ws_close(){this.connected=!1,this.connecting=!1;for(let t of Object.keys(this.active_streams))this.close_stream(this.active_streams[t],3)}create_stream(t,e,s="tcp"){let i="udp"===s?2:1,n=this.next_stream_id++,a=new T(t,e,this.ws,this.max_buffer_size,n,this,i);this.active_streams[n]=a,a.open=this.connected;let o=new w({type:g.CONNECT,stream_id:n,payload:new f({stream_type:i,port:e,hostname:t})});return this.ws.send(o.serialize().bytes),a}on_ws_msg(t){let e=new d(new Uint8Array(t.data));if(e.size<w.min_size)return void console.warn("wisp client warning: received a packet which is too short");let s=w.parse_all(e),i=this.active_streams[s.stream_id];void 0!==i||0===s.stream_id&&s.type===g.CONTINUE?s.type===g.DATA?i.onmessage(s.payload_bytes.bytes):s.type===g.CONTINUE&&0==s.stream_id?this.max_buffer_size=s.payload.buffer_remaining:s.type===g.CONTINUE?i.continue_received(s.payload.buffer_size):s.type===g.CLOSE?this.close_stream(i,s.payload.reason):console.warn(`wisp client warning: receive an invalid packet of type ${s.type}`):console.warn(`wisp client warning: received a ${k[s.type].name} packet for a stream which doesn't exist`)}}const U=globalThis.CloseEvent||Event,E={};class P extends EventTarget{constructor(t,e){super(),this.url=t,this.protocols=e,this.binaryType="blob",this.stream=null,this.connection=null,this.onopen=()=>{},this.onerror=()=>{},this.onmessage=()=>{},this.onclose=()=>{},this.CONNECTING=0,this.OPEN=1,this.CLOSING=2,this.CLOSED=3,this._ready_state=this.CONNECTING;let s=this.url.split("/"),i=s.pop().split(":");this.host=i[0],this.port=parseInt(i[1]),this.real_url=s.join("/")+"/",this.init_connection()}on_conn_close(){this._ready_state=this.CLOSED,E[this.real_url]&&(this.onerror(new Event("error")),this.dispatchEvent(new Event("error"))),delete E[this.real_url]}init_connection(){if(this.connection=E[this.real_url],this.connection)if(this.connection.connected)this.connection=E[this.real_url],this.init_stream();else{let t=this.connection.onopen;this.connection.onopen=()=>{t(),this.init_stream()}}else this.connection=new C(this.real_url),this.connection.onopen=()=>{this.init_stream()},this.connection.onclose=()=>{this.on_conn_close()},this.connection.onerror=()=>{this.on_conn_close()},E[this.real_url]=this.connection}init_stream(){this._ready_state=this.OPEN,this.stream=this.connection.create_stream(this.host,this.port),this.stream.onmessage=t=>{let e;if("blob"==this.binaryType)e=new Blob(t);else{if("arraybuffer"!=this.binaryType)throw"invalid binaryType string";e=t.buffer}let s=new MessageEvent("message",{data:e});this.onmessage(s),this.dispatchEvent(s)},this.stream.onclose=t=>{this._ready_state=this.CLOSED;let e=new U("close",{code:t});this.onclose(e),this.dispatchEvent(e)};let t=new Event("open");this.onopen(t),this.dispatchEvent(t)}send(t){let e;if(t instanceof Uint8Array)e=t;else if("string"==typeof t)e=(new TextEncoder).encode(t);else{if(t instanceof Blob)return void t.arrayBuffer().then((t=>{this.send(t)}));if(t instanceof ArrayBuffer)e=new Uint8Array(t);else{if(!ArrayBuffer.isView(t))throw"invalid data type to be sent";e=new Uint8Array(t.buffer)}}if(!this.stream)throw"websocket is not ready";this.stream.send(e)}close(){this.stream.close(2)}get bufferedAmount(){let t=0;for(let e of this.stream.send_buffer)t+=e.length;return t}get extensions(){return""}get protocol(){return"binary"}get readyState(){return this._ready_state}}const $=1,N=2,O=3;let S=$;function A(){let[t,e]=(new Date).toJSON().split("T");return t=t.replaceAll("-","/"),e=e.split(".")[0],`[${t} - ${e}]`}function q(...t){S>$||console.info(A()+" info:",...t)}function D(...t){S>N||console.warn(A()+" warn:",...t)}function x(...t){S>O||console.error(A()+" error:",...t)}const I={hostname_blacklist:null,hostname_whitelist:null,port_blacklist:null,port_whitelist:null,allow_direct_ip:!0,allow_private_ips:!1,allow_loopback_ips:!1,client_ip_blacklist:null,client_ip_whitelist:null,stream_limit_per_host:-1,stream_limit_total:-1,allow_udp_streams:!0,allow_tcp_streams:!0};class B extends Error{}function j(t,e){return t===e||t[0]<=e&&t[1]>=e}function H(t,e){let s=!1;for(let i of t)if(e(i)){s=!0;break}return!s}function L(t,e){for(let s of t)if(e(s))return!0;return!1}function W(t,e,s,i){if(!I.allow_tcp_streams&&e===stream_types.TCP)return z.HostBlocked;if(!I.allow_udp_streams&&e===stream_types.UDP)return z.HostBlocked;if(I.hostname_whitelist){if(H(I.hostname_whitelist,(t=>t.test(s))))return z.HostBlocked}else if(I.hostname_blacklist&&L(I.hostname_blacklist,(t=>t.test(s))))return z.HostBlocked;if(I.port_whitelist){if(H(I.port_whitelist,(t=>j(t,i))))return z.HostBlocked}else if(I.port_blacklist&&L(I.port_blacklist,(t=>j(t,i))))return z.HostBlocked;if(!t)return 0;if(-1!==I.stream_limit_total&&Object.keys(t.streams).length>=I.stream_limit_total)return z.ConnThrottled;if(-1!==I.stream_limit_per_host){let e=0;for(let i of t.streams)i.socket.hostname===s&&e++;if(e>=I.stream_limit_per_host)return z.ConnThrottled}return 0}class M{send_buffer_size=33554432;constructor(t){this.ws=t,this.connected=!1,this.data_queue=new R(1)}async connect(){await new Promise(((t,e)=>{this.ws.onopen=()=>{this.connected=!0,t()},this.ws.onmessage=t=>{this.data_queue.put(t.data)},this.ws.onclose=()=>{this.connected?this.data_queue.close():e()},this.ws.readyState===this.ws.OPEN&&(this.connected=!0,t())}))}async recv(){return await this.data_queue.get()}async send(t){if(this.ws.send(t),!(this.ws.bufferedAmount<=this.send_buffer_size))for(;!(this.ws.bufferedAmount<=this.send_buffer_size/2);)await new Promise((t=>{setTimeout(t,10)}))}close(t,e){this.ws.close(t,e),this.data_queue.close()}get buffered_amount(){return this.ws.bufferedAmount}}class R{constructor(t){this.max_size=t,this.queue=[],this.put_callbacks=[],this.get_callbacks=[]}put_now(t){this.queue.push(t),this.get_callbacks.shift()?.()}async put(t){this.size<=this.max_size||await new Promise((t=>{this.put_callbacks.push(t)})),this.put_now(t)}get_now(){return this.put_callbacks.shift()?.(),this.queue.shift()}async get(){return this.size>0||await new Promise((t=>{this.get_callbacks.push(t)})),this.get_now()}close(){let t;for(this.queue=[];t=this.get_callbacks.shift();)t();for(;t=this.put_callbacks.shift();)t()}get size(){return this.queue.length}}const V="undefined"!=typeof process;function G(){if(!V)throw"not running on node.js"}async function J(t){let e=r.isIP(t);return 4===e||6===e?t:(await c.lookup(t)).address}class F{constructor(t,e){G(),this.hostname=t,this.port=e,this.recv_buffer_size=128,this.socket=null,this.paused=!1,this.connected=!1,this.data_queue=new R(this.recv_buffer_size)}async connect(){let t=await J(this.hostname);await new Promise(((e,s)=>{this.socket=new r.Socket,this.socket.setNoDelay(!0),this.socket.on("connect",(()=>{this.connected=!0,e()})),this.socket.on("data",(t=>{this.data_queue.put(t)})),this.socket.on("close",(t=>{t&&!this.connected?s():this.data_queue.close(),this.socket=null})),this.socket.on("error",(t=>{D(`tcp stream to ${this.hostname} ended with error - ${t}`)})),this.socket.on("end",(()=>{this.socket&&(this.socket.destroy(),this.socket=null)})),this.socket.connect({host:t,port:this.port})}))}async recv(){return await this.data_queue.get()}async send(t){await new Promise((e=>{this.socket.write(t,e)}))}async close(){this.socket&&(this.socket.end(),this.socket=null)}pause(){this.data_queue.size>=this.data_queue.max_size&&(this.socket.pause(),this.paused=!0)}resume(){this.socket&&this.paused&&(this.socket.resume(),this.paused=!1)}}class K{constructor(t,e){G(),this.hostname=t,this.port=e,this.connected=!1,this.recv_buffer_size=128,this.data_queue=new R(this.recv_buffer_size)}async connect(){let t=await J(this.hostname),e=r.isIP(t);await new Promise(((s,i)=>{this.socket=null.createSocket(6===e?"udp6":"udp4"),this.socket.on("connect",(()=>{s()})),this.socket.on("message",(t=>{this.data_queue.put(t)})),this.socket.on("error",(()=>{this.connected||i(),this.data_queue.close(),this.socket=null})),this.socket.connect(this.port,t)}))}async recv(){return await this.data_queue.get()}async send(t){this.socket.send(t)}async close(){this.socket&&(this.socket.close(),this.socket=null)}pause(){}resume(){}}class Q{static buffer_size=128;constructor(t,e,s){this.stream_id=t,this.conn=e,this.socket=s,this.send_buffer=new R(Q.buffer_size),this.packets_sent=0}async setup(){await this.socket.connect(),this.tcp_to_ws().catch((t=>{x(`(${this.conn.conn_id}) a tcp/udp to ws task encountered an error - ${t}`),this.close()})),this.ws_to_tcp().catch((t=>{x(`(${this.conn.conn_id}) a ws to tcp/udp task encountered an error - ${t}`),this.close()}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause();let e=new w({type:y.type,stream_id:this.stream_id,payload:new y({data:new d(new Uint8Array(t))})});await this.conn.ws.send(e.serialize().bytes),this.socket.resume()}await this.conn.close_stream(this.stream_id,z.Voluntary)}async ws_to_tcp(){for(;;){let t=await this.send_buffer.get();if(null==t)break;if(await this.socket.send(t),this.packets_sent++,this.packets_sent%(Q.buffer_size/2)!=0)continue;let e=new w({type:m.type,stream_id:this.stream_id,payload:new m({buffer_remaining:Q.buffer_size-this.send_buffer.size})});this.conn.ws.send(e.serialize().bytes)}await this.close()}async close(t=null){if(this.send_buffer.close(),this.socket.close(),null==t)return;let e=new w({type:b.type,stream_id:this.stream_id,payload:new b({reason:t})});await this.conn.ws.send(e.serialize().bytes)}async put_data(t){await this.send_buffer.put(t)}}class X{constructor(t,e,{TCPSocket:s,UDPSocket:i,ping_interval:n}={}){this.ws=new M(t),this.path=e,this.TCPSocket=s||F,this.UDPSocket=i||K,this.ping_interval=n||30,this.ping_task=null,this.streams={},this.conn_id=o.randomUUID().split("-")[0]}async setup(){q(`setting up new wisp connection with id ${this.conn_id}`),await this.ws.connect();let t=new w({type:m.type,stream_id:0,payload:new m({buffer_remaining:Q.buffer_size})});await this.ws.send(t.serialize().bytes),"function"==typeof this.ws.ws.ping&&(this.ping_task=setInterval((()=>{!function(...t){S>0||console.debug(A()+" debug:",...t)}(`(${this.conn_id}) sending websocket ping`),this.ws.ws.ping()}),1e3*this.ping_interval))}async create_stream(t,e,s,i){let n=W(this,e,s,i);if(n){D(`(${this.conn_id}) refusing to create a stream to ${s}:${i}`);let e=new w({type:b.type,stream_id:t,payload:new b({reason:n})});return void await this.ws.send(e.serialize().bytes)}let a=new(e===v.TCP?this.TCPSocket:this.UDPSocket)(s,i),o=new Q(t,this,a);this.streams[t]=o,o.setup().catch((e=>{D(`(${this.conn_id}) creating a stream to ${s}:${i} failed - ${e}`),this.close_stream(t,z.NetworkError)}))}async close_stream(t,e=null){let s=this.streams[t];null!=s&&(e&&q(`(${this.conn_id}) closing stream to ${s.socket.hostname} for reason ${e}`),await s.close(e),delete this.streams[t])}async route_packet(t){let e=w.parse_all(t),s=this.streams[e.stream_id];if(null!=s||e.type!=y.type)if(e.type===f.type){let t=e.payload.stream_type===v.TCP?"TCP":"UDP";q(`(${this.conn_id}) opening new ${t} stream to ${e.payload.hostname}:${e.payload.port}`),await this.create_stream(e.stream_id,e.payload.stream_type,e.payload.hostname,e.payload.port)}else e.type===y.type?s.put_data(e.payload.data.bytes):e.type==m.type?D(`(${this.conn_id}) client sent a CONTINUE packet, this should never be possible`):e.type==b.type&&await this.close_stream(e.stream_id,e.reason);else D(`(${this.conn_id}) received a DATA packet for a stream which doesn't exist`)}async run(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;try{this.route_packet(new d(new Uint8Array(t)))}catch(t){D(`(${this.conn_id}) routing a packet failed - ${t}`)}}for(let t of Object.keys(this.streams))await this.close_stream(t);clearInterval(this.ping_task),q(`(${this.conn_id}) wisp connection closed`)}}class Y{constructor(t,e){let[s,i]=e.split("/").pop().split(":");if(this.hostname=s,this.port=parseInt(i),0!==W(null,v.TCP,this.hostname,this.port))throw q(`Refusing to create a wsproxy connection to ${this.hostname}:${this.port}`),new B;this.socket=new F(s,i),this.ws=new M(t)}async setup(){await this.ws.connect(),await this.socket.connect(),this.tcp_to_ws().catch((t=>{x(`a tcp to ws task (wsproxy) encountered an error - ${t}`)})),this.ws_to_tcp().catch((t=>{x(`a ws to tcp task (wsproxy) encountered an error - ${t}`)}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause(),await this.ws.send(t),this.socket.resume()}await this.ws.close()}async ws_to_tcp(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;await this.socket.send(t)}await this.socket.close()}}let Z=null;function tt(t,e,s,i={}){G(),t instanceof h.IncomingMessage?Z.handleUpgrade(t,e,s,(e=>{et(e,t.url,t,i)})):t instanceof a&&et(ws,"/",{})}async function et(t,e,s,i){q(`new connection on ${e} from ${s.socket.address().address}`);try{if(e.endsWith("/")){let s=new X(t,e,i);await s.setup(),await s.run()}else{let s=new Y(t,e,i);await s.setup()}}catch(e){if(t.close(),e instanceof B)return;x("Uncaught server error:\n"+e.stack)}}V&&(Z=new null({noServer:!0})),wisp_full=e})(); | ||
var wisp_full;(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{client:()=>i,packet:()=>s,server:()=>n});var s={};t.r(s),t.d(s,{ClosePayload:()=>b,ConnectPayload:()=>f,ContinuePayload:()=>m,DataPayload:()=>y,WispBuffer:()=>d,WispPacket:()=>w,close_reasons:()=>z,packet_classes:()=>k,packet_types:()=>g,stream_types:()=>v});var i={};t.r(i),t.d(i,{ClientConnection:()=>C,WispWebSocket:()=>P,_wisp_connections:()=>E});var n={};t.r(n),t.d(n,{ServerConnection:()=>X,ServerStream:()=>Q,options:()=>I,routeRequest:()=>tt});const a=globalThis.WebSocket,o=globalThis.crypto,r=null,c=null,h=null,l=new TextEncoder,u=l.encode.bind(l),_=new TextDecoder,p=_.decode.bind(_);class d{constructor(t){if(t instanceof Uint8Array)this.from_array(t);else if("number"==typeof t)this.from_array(new Uint8Array(t));else{if("string"!=typeof t)throw console.trace(),"invalid data type passed to wisp buffer constructor";this.from_array(u(t))}}from_array(t){this.size=t.length,this.bytes=t,this.view=new DataView(t.buffer)}concat(t){let e=new d(this.size+t.size);return e.bytes.set(this.bytes,0),e.bytes.set(t.bytes,this.size),e}slice(t,e){let s=this.bytes.slice(t,e);return new d(s)}}class w{static min_size=5;constructor({type:t,stream_id:e,payload:s,payload_bytes:i}){this.type=t,this.stream_id=e,this.payload_bytes=i,this.payload=s}static parse(t){return new w({type:t.view.getUint8(0),stream_id:t.view.getUint32(1,!0),payload_bytes:t.slice(5)})}static parse_all(t){if(t.size<w.min_size)throw"packet too small";let e=w.parse(t),s=k[e.type];if(void 0===s)throw"invalid packet type";if(e.payload_bytes.size<s.size)throw"payload too small";return e.payload=s.parse(e.payload_bytes),e}serialize(){let t=new d(5);return t.view.setUint8(0,this.type),t.view.setUint32(1,this.stream_id,!0),t=t.concat(this.payload.serialize()),t}}class f{static min_size=3;static type=1;static name="CONNECT";constructor({stream_type:t,port:e,hostname:s}){this.stream_type=t,this.port=e,this.hostname=s}static parse(t){return new f({stream_type:t.view.getUint8(0),port:t.view.getUint16(1,!0),hostname:p(t.slice(3).bytes)})}serialize(){let t=new d(3);return t.view.setUint8(0,this.stream_type),t.view.setUint16(1,this.port,!0),t=t.concat(new d(this.hostname)),t}}class y{static min_size=0;static type=2;static name="DATA";constructor({data:t}){this.data=t}static parse(t){return new y({data:t})}serialize(){return this.data}}class m{static type=3;static name="CONTINUE";constructor({buffer_remaining:t}){this.buffer_remaining=t}static parse(t){return new m({buffer_remaining:t.view.getUint32(0,!0)})}serialize(){let t=new d(4);return t.view.setUint32(0,this.buffer_remaining,!0),t}}class b{static min_size=1;static type=4;static name="CLOSE";constructor({reason:t}){this.reason=t}static parse(t){return new b({reason:t.view.getUint8(0)})}serialize(){let t=new d(1);return t.view.setUint8(0,this.buffer_remaining),t}}const k=[void 0,f,y,m,b],g={CONNECT:1,DATA:2,CONTINUE:3,CLOSE:4},v={TCP:1,UDP:2},z={Unknown:1,Voluntary:2,NetworkError:3,InvalidInfo:65,UnreachableHost:66,NoResponse:67,ConnRefused:68,TransferTimeout:71,HostBlocked:72,ConnThrottled:73,ClientError:129};class T{constructor(t,e,s,i,n,a,o){this.hostname=t,this.port=e,this.ws=s,this.buffer_size=i,this.stream_id=n,this.connection=a,this.stream_type=o,this.send_buffer=[],this.open=!0,this.onopen=()=>{},this.onclose=()=>{},this.onmessage=()=>{}}send(t){if(this.buffer_size>0||!this.open||this.stream_type===v.UDP){let e=new w({type:g.DATA,stream_id:this.stream_id,payload:new y({data:new d(t)})});this.ws.send(e.serialize().bytes),this.buffer_size--}else this.send_buffer.push(t)}continue_received(t){for(this.buffer_size=t;this.buffer_size>0&&this.send_buffer.length>0;)this.send(this.send_buffer.shift())}close(t=1){if(!this.open)return;let e=new w({type:g.CLOSE,stream_id,payload:new b({reason:t})});this.ws.send(e.serialize().bytes),this.open=!1,delete this.connection.active_streams[this.stream_id]}}class C{constructor(t){if(!t.endsWith("/"))throw"wisp endpoints must end with a trailing forward slash";this.wisp_url=t,this.max_buffer_size=null,this.active_streams={},this.connected=!1,this.connecting=!1,this.next_stream_id=1,this.onopen=()=>{},this.onclose=()=>{},this.onerror=()=>{},this.onmessage=()=>{},this.connect_ws()}connect_ws(){this.ws=new a(this.wisp_url),this.ws.binaryType="arraybuffer",this.connecting=!0,this.ws.onerror=()=>{this.on_ws_close(),this.onerror()},this.ws.onclose=()=>{this.on_ws_close(),this.onclose()},this.ws.onmessage=t=>{this.on_ws_msg(t),this.connecting&&(this.connected=!0,this.connecting=!1,this.onopen())}}close_stream(t,e){t.onclose(e),delete this.active_streams[t.stream_id]}on_ws_close(){this.connected=!1,this.connecting=!1;for(let t of Object.keys(this.active_streams))this.close_stream(this.active_streams[t],3)}create_stream(t,e,s="tcp"){let i="udp"===s?2:1,n=this.next_stream_id++,a=new T(t,e,this.ws,this.max_buffer_size,n,this,i);this.active_streams[n]=a,a.open=this.connected;let o=new w({type:g.CONNECT,stream_id:n,payload:new f({stream_type:i,port:e,hostname:t})});return this.ws.send(o.serialize().bytes),a}on_ws_msg(t){let e=new d(new Uint8Array(t.data));if(e.size<w.min_size)return void console.warn("wisp client warning: received a packet which is too short");let s=w.parse_all(e),i=this.active_streams[s.stream_id];void 0!==i||0===s.stream_id&&s.type===g.CONTINUE?s.type===g.DATA?i.onmessage(s.payload_bytes.bytes):s.type===g.CONTINUE&&0==s.stream_id?this.max_buffer_size=s.payload.buffer_remaining:s.type===g.CONTINUE?i.continue_received(s.payload.buffer_size):s.type===g.CLOSE?this.close_stream(i,s.payload.reason):console.warn(`wisp client warning: receive an invalid packet of type ${s.type}`):console.warn(`wisp client warning: received a ${k[s.type].name} packet for a stream which doesn't exist`)}}const U=globalThis.CloseEvent||Event,E={};class P extends EventTarget{constructor(t,e){super(),this.url=t,this.protocols=e,this.binaryType="blob",this.stream=null,this.connection=null,this.onopen=()=>{},this.onerror=()=>{},this.onmessage=()=>{},this.onclose=()=>{},this.CONNECTING=0,this.OPEN=1,this.CLOSING=2,this.CLOSED=3,this._ready_state=this.CONNECTING;let s=this.url.split("/"),i=s.pop().split(":");this.host=i[0],this.port=parseInt(i[1]),this.real_url=s.join("/")+"/",this.init_connection()}on_conn_close(){this._ready_state=this.CLOSED,E[this.real_url]&&(this.onerror(new Event("error")),this.dispatchEvent(new Event("error"))),delete E[this.real_url]}init_connection(){if(this.connection=E[this.real_url],this.connection)if(this.connection.connected)this.connection=E[this.real_url],this.init_stream();else{let t=this.connection.onopen;this.connection.onopen=()=>{t(),this.init_stream()}}else this.connection=new C(this.real_url),this.connection.onopen=()=>{this.init_stream()},this.connection.onclose=()=>{this.on_conn_close()},this.connection.onerror=()=>{this.on_conn_close()},E[this.real_url]=this.connection}init_stream(){this._ready_state=this.OPEN,this.stream=this.connection.create_stream(this.host,this.port),this.stream.onmessage=t=>{let e;if("blob"==this.binaryType)e=new Blob(t);else{if("arraybuffer"!=this.binaryType)throw"invalid binaryType string";e=t.buffer}let s=new MessageEvent("message",{data:e});this.onmessage(s),this.dispatchEvent(s)},this.stream.onclose=t=>{this._ready_state=this.CLOSED;let e=new U("close",{code:t});this.onclose(e),this.dispatchEvent(e)};let t=new Event("open");this.onopen(t),this.dispatchEvent(t)}send(t){let e;if(t instanceof Uint8Array)e=t;else if("string"==typeof t)e=(new TextEncoder).encode(t);else{if(t instanceof Blob)return void t.arrayBuffer().then((t=>{this.send(t)}));if(t instanceof ArrayBuffer)e=new Uint8Array(t);else{if(!ArrayBuffer.isView(t))throw"invalid data type to be sent";e=new Uint8Array(t.buffer)}}if(!this.stream)throw"websocket is not ready";this.stream.send(e)}close(){this.stream.close(2)}get bufferedAmount(){let t=0;for(let e of this.stream.send_buffer)t+=e.length;return t}get extensions(){return""}get protocol(){return"binary"}get readyState(){return this._ready_state}}const $=1,N=2,O=3;let S=$;function A(){let[t,e]=(new Date).toJSON().split("T");return t=t.replaceAll("-","/"),e=e.split(".")[0],`[${t} - ${e}]`}function q(...t){S>$||console.info(A()+" info:",...t)}function D(...t){S>N||console.warn(A()+" warn:",...t)}function x(...t){S>O||console.error(A()+" error:",...t)}const I={hostname_blacklist:null,hostname_whitelist:null,port_blacklist:null,port_whitelist:null,allow_direct_ip:!0,allow_private_ips:!1,allow_loopback_ips:!1,client_ip_blacklist:null,client_ip_whitelist:null,stream_limit_per_host:-1,stream_limit_total:-1,allow_udp_streams:!0,allow_tcp_streams:!0};class B extends Error{}function j(t,e){return t===e||t[0]<=e&&t[1]>=e}function H(t,e){let s=!1;for(let i of t)if(e(i)){s=!0;break}return!s}function L(t,e){for(let s of t)if(e(s))return!0;return!1}function W(t,e,s,i){if(!I.allow_tcp_streams&&e===v.TCP)return z.HostBlocked;if(!I.allow_udp_streams&&e===v.UDP)return z.HostBlocked;if(I.hostname_whitelist){if(H(I.hostname_whitelist,(t=>t.test(s))))return z.HostBlocked}else if(I.hostname_blacklist&&L(I.hostname_blacklist,(t=>t.test(s))))return z.HostBlocked;if(I.port_whitelist){if(H(I.port_whitelist,(t=>j(t,i))))return z.HostBlocked}else if(I.port_blacklist&&L(I.port_blacklist,(t=>j(t,i))))return z.HostBlocked;if(!t)return 0;if(-1!==I.stream_limit_total&&Object.keys(t.streams).length>=I.stream_limit_total)return z.ConnThrottled;if(-1!==I.stream_limit_per_host){let e=0;for(let i of t.streams)i.socket.hostname===s&&e++;if(e>=I.stream_limit_per_host)return z.ConnThrottled}return 0}class M{send_buffer_size=33554432;constructor(t){this.ws=t,this.connected=!1,this.data_queue=new R(1)}async connect(){await new Promise(((t,e)=>{this.ws.onopen=()=>{this.connected=!0,t()},this.ws.onmessage=t=>{this.data_queue.put(t.data)},this.ws.onclose=()=>{this.connected?this.data_queue.close():e()},this.ws.readyState===this.ws.OPEN&&(this.connected=!0,t())}))}async recv(){return await this.data_queue.get()}async send(t){if(this.ws.send(t),!(this.ws.bufferedAmount<=this.send_buffer_size))for(;!(this.ws.bufferedAmount<=this.send_buffer_size/2);)await new Promise((t=>{setTimeout(t,10)}))}close(t,e){this.ws.close(t,e),this.data_queue.close()}get buffered_amount(){return this.ws.bufferedAmount}}class R{constructor(t){this.max_size=t,this.queue=[],this.put_callbacks=[],this.get_callbacks=[]}put_now(t){this.queue.push(t),this.get_callbacks.shift()?.()}async put(t){this.size<=this.max_size||await new Promise((t=>{this.put_callbacks.push(t)})),this.put_now(t)}get_now(){return this.put_callbacks.shift()?.(),this.queue.shift()}async get(){return this.size>0||await new Promise((t=>{this.get_callbacks.push(t)})),this.get_now()}close(){let t;for(this.queue=[];t=this.get_callbacks.shift();)t();for(;t=this.put_callbacks.shift();)t()}get size(){return this.queue.length}}const V="undefined"!=typeof process;function G(){if(!V)throw"not running on node.js"}async function J(t){let e=r.isIP(t);return 4===e||6===e?t:(await c.lookup(t)).address}class F{constructor(t,e){G(),this.hostname=t,this.port=e,this.recv_buffer_size=128,this.socket=null,this.paused=!1,this.connected=!1,this.data_queue=new R(this.recv_buffer_size)}async connect(){let t=await J(this.hostname);await new Promise(((e,s)=>{this.socket=new r.Socket,this.socket.setNoDelay(!0),this.socket.on("connect",(()=>{this.connected=!0,e()})),this.socket.on("data",(t=>{this.data_queue.put(t)})),this.socket.on("close",(t=>{t&&!this.connected?s():this.data_queue.close(),this.socket=null})),this.socket.on("error",(t=>{D(`tcp stream to ${this.hostname} ended with error - ${t}`)})),this.socket.on("end",(()=>{this.socket&&(this.socket.destroy(),this.socket=null)})),this.socket.connect({host:t,port:this.port})}))}async recv(){return await this.data_queue.get()}async send(t){await new Promise((e=>{this.socket.write(t,e)}))}async close(){this.socket&&(this.socket.end(),this.socket=null)}pause(){this.data_queue.size>=this.data_queue.max_size&&(this.socket.pause(),this.paused=!0)}resume(){this.socket&&this.paused&&(this.socket.resume(),this.paused=!1)}}class K{constructor(t,e){G(),this.hostname=t,this.port=e,this.connected=!1,this.recv_buffer_size=128,this.data_queue=new R(this.recv_buffer_size)}async connect(){let t=await J(this.hostname),e=r.isIP(t);await new Promise(((s,i)=>{this.socket=null.createSocket(6===e?"udp6":"udp4"),this.socket.on("connect",(()=>{s()})),this.socket.on("message",(t=>{this.data_queue.put(t)})),this.socket.on("error",(()=>{this.connected||i(),this.data_queue.close(),this.socket=null})),this.socket.connect(this.port,t)}))}async recv(){return await this.data_queue.get()}async send(t){this.socket.send(t)}async close(){this.socket&&(this.socket.close(),this.socket=null)}pause(){}resume(){}}class Q{static buffer_size=128;constructor(t,e,s){this.stream_id=t,this.conn=e,this.socket=s,this.send_buffer=new R(Q.buffer_size),this.packets_sent=0}async setup(){await this.socket.connect(),this.tcp_to_ws().catch((t=>{x(`(${this.conn.conn_id}) a tcp/udp to ws task encountered an error - ${t}`),this.close()})),this.ws_to_tcp().catch((t=>{x(`(${this.conn.conn_id}) a ws to tcp/udp task encountered an error - ${t}`),this.close()}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause();let e=new w({type:y.type,stream_id:this.stream_id,payload:new y({data:new d(new Uint8Array(t))})});await this.conn.ws.send(e.serialize().bytes),this.socket.resume()}await this.conn.close_stream(this.stream_id,z.Voluntary)}async ws_to_tcp(){for(;;){let t=await this.send_buffer.get();if(null==t)break;if(await this.socket.send(t),this.packets_sent++,this.packets_sent%(Q.buffer_size/2)!=0)continue;let e=new w({type:m.type,stream_id:this.stream_id,payload:new m({buffer_remaining:Q.buffer_size-this.send_buffer.size})});this.conn.ws.send(e.serialize().bytes)}await this.close()}async close(t=null){if(this.send_buffer.close(),this.socket.close(),null==t)return;let e=new w({type:b.type,stream_id:this.stream_id,payload:new b({reason:t})});await this.conn.ws.send(e.serialize().bytes)}async put_data(t){await this.send_buffer.put(t)}}class X{constructor(t,e,{TCPSocket:s,UDPSocket:i,ping_interval:n}={}){this.ws=new M(t),this.path=e,this.TCPSocket=s||F,this.UDPSocket=i||K,this.ping_interval=n||30,this.ping_task=null,this.streams={},this.conn_id=o.randomUUID().split("-")[0]}async setup(){q(`setting up new wisp connection with id ${this.conn_id}`),await this.ws.connect();let t=new w({type:m.type,stream_id:0,payload:new m({buffer_remaining:Q.buffer_size})});await this.ws.send(t.serialize().bytes),"function"==typeof this.ws.ws.ping&&(this.ping_task=setInterval((()=>{!function(...t){S>0||console.debug(A()+" debug:",...t)}(`(${this.conn_id}) sending websocket ping`),this.ws.ws.ping()}),1e3*this.ping_interval))}async create_stream(t,e,s,i){let n=W(this,e,s,i);if(n){D(`(${this.conn_id}) refusing to create a stream to ${s}:${i}`);let e=new w({type:b.type,stream_id:t,payload:new b({reason:n})});return void await this.ws.send(e.serialize().bytes)}let a=new(e===v.TCP?this.TCPSocket:this.UDPSocket)(s,i),o=new Q(t,this,a);this.streams[t]=o,o.setup().catch((e=>{D(`(${this.conn_id}) creating a stream to ${s}:${i} failed - ${e}`),this.close_stream(t,z.NetworkError)}))}async close_stream(t,e=null){let s=this.streams[t];null!=s&&(e&&q(`(${this.conn_id}) closing stream to ${s.socket.hostname} for reason ${e}`),await s.close(e),delete this.streams[t])}async route_packet(t){let e=w.parse_all(t),s=this.streams[e.stream_id];if(null!=s||e.type!=y.type)if(e.type===f.type){let t=e.payload.stream_type===v.TCP?"TCP":"UDP";q(`(${this.conn_id}) opening new ${t} stream to ${e.payload.hostname}:${e.payload.port}`),await this.create_stream(e.stream_id,e.payload.stream_type,e.payload.hostname,e.payload.port)}else e.type===y.type?s.put_data(e.payload.data.bytes):e.type==m.type?D(`(${this.conn_id}) client sent a CONTINUE packet, this should never be possible`):e.type==b.type&&await this.close_stream(e.stream_id,e.reason);else D(`(${this.conn_id}) received a DATA packet for a stream which doesn't exist`)}async run(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;try{this.route_packet(new d(new Uint8Array(t)))}catch(t){D(`(${this.conn_id}) routing a packet failed - ${t}`)}}for(let t of Object.keys(this.streams))await this.close_stream(t);clearInterval(this.ping_task),q(`(${this.conn_id}) wisp connection closed`)}}class Y{constructor(t,e){let[s,i]=e.split("/").pop().split(":");if(this.hostname=s,this.port=parseInt(i),0!==W(null,v.TCP,this.hostname,this.port))throw q(`Refusing to create a wsproxy connection to ${this.hostname}:${this.port}`),new B;this.socket=new F(s,i),this.ws=new M(t)}async setup(){await this.ws.connect(),await this.socket.connect(),this.tcp_to_ws().catch((t=>{x(`a tcp to ws task (wsproxy) encountered an error - ${t}`)})),this.ws_to_tcp().catch((t=>{x(`a ws to tcp task (wsproxy) encountered an error - ${t}`)}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause(),await this.ws.send(t),this.socket.resume()}await this.ws.close()}async ws_to_tcp(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;await this.socket.send(t)}await this.socket.close()}}let Z=null;function tt(t,e,s,i={}){G(),t instanceof h.IncomingMessage?Z.handleUpgrade(t,e,s,(e=>{et(e,t.url,t,i)})):t instanceof a&&et(ws,"/",{})}async function et(t,e,s,i){q(`new connection on ${e} from ${s.socket.address().address}`);try{if(e.endsWith("/")){let s=new X(t,e,i);await s.setup(),await s.run()}else{let s=new Y(t,e,i);await s.setup()}}catch(e){if(t.close(),e instanceof B)return;x("Uncaught server error:\n"+e.stack)}}V&&(Z=new null({noServer:!0})),wisp_full=e})(); |
@@ -1,1 +0,1 @@ | ||
var wisp_server;(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{logging:()=>s,packet:()=>i,server:()=>a});var s={};t.r(s),t.d(s,{DEBUG:()=>n,ERROR:()=>c,INFO:()=>o,NONE:()=>l,WARN:()=>r,debug:()=>_,error:()=>y,get_timestamp:()=>u,info:()=>d,log:()=>w,log_level:()=>h,set_level:()=>p,warn:()=>f});var i={};t.r(i),t.d(i,{ClosePayload:()=>T,ConnectPayload:()=>$,ContinuePayload:()=>U,DataPayload:()=>P,WispBuffer:()=>v,WispPacket:()=>z,close_reasons:()=>N,packet_classes:()=>C,packet_types:()=>S,stream_types:()=>q});var a={};t.r(a),t.d(a,{ServerConnection:()=>X,ServerStream:()=>Q,options:()=>O,routeRequest:()=>tt});const n=0,o=1,r=2,c=3,l=4;let h=o;function u(){let[t,e]=(new Date).toJSON().split("T");return t=t.replaceAll("-","/"),e=e.split(".")[0],`[${t} - ${e}]`}function p(t){h=t}function _(...t){h>n||console.debug(u()+" debug:",...t)}function d(...t){h>o||console.info(u()+" info:",...t)}function w(...t){h>o||console.log(u()+" log:",...t)}function f(...t){h>r||console.warn(u()+" warn:",...t)}function y(...t){h>c||console.error(u()+" error:",...t)}const m=new TextEncoder,k=m.encode.bind(m),b=new TextDecoder,g=b.decode.bind(b);class v{constructor(t){if(t instanceof Uint8Array)this.from_array(t);else if("number"==typeof t)this.from_array(new Uint8Array(t));else{if("string"!=typeof t)throw console.trace(),"invalid data type passed to wisp buffer constructor";this.from_array(k(t))}}from_array(t){this.size=t.length,this.bytes=t,this.view=new DataView(t.buffer)}concat(t){let e=new v(this.size+t.size);return e.bytes.set(this.bytes,0),e.bytes.set(t.bytes,this.size),e}slice(t,e){let s=this.bytes.slice(t,e);return new v(s)}}class z{static min_size=5;constructor({type:t,stream_id:e,payload:s,payload_bytes:i}){this.type=t,this.stream_id=e,this.payload_bytes=i,this.payload=s}static parse(t){return new z({type:t.view.getUint8(0),stream_id:t.view.getUint32(1,!0),payload_bytes:t.slice(5)})}static parse_all(t){if(t.size<z.min_size)throw"packet too small";let e=z.parse(t),s=C[e.type];if(void 0===s)throw"invalid packet type";if(e.payload_bytes.size<s.size)throw"payload too small";return e.payload=s.parse(e.payload_bytes),e}serialize(){let t=new v(5);return t.view.setUint8(0,this.type),t.view.setUint32(1,this.stream_id,!0),t=t.concat(this.payload.serialize()),t}}class ${static min_size=3;static type=1;static name="CONNECT";constructor({stream_type:t,port:e,hostname:s}){this.stream_type=t,this.port=e,this.hostname=s}static parse(t){return new $({stream_type:t.view.getUint8(0),port:t.view.getUint16(1,!0),hostname:g(t.slice(3).bytes)})}serialize(){let t=new v(3);return t.view.setUint8(0,this.stream_type),t.view.setUint16(1,this.port,!0),t=t.concat(new v(this.hostname)),t}}class P{static min_size=0;static type=2;static name="DATA";constructor({data:t}){this.data=t}static parse(t){return new P({data:t})}serialize(){return this.data}}class U{static type=3;static name="CONTINUE";constructor({buffer_remaining:t}){this.buffer_remaining=t}static parse(t){return new U({buffer_remaining:t.view.getUint32(0,!0)})}serialize(){let t=new v(4);return t.view.setUint32(0,this.buffer_remaining,!0),t}}class T{static min_size=1;static type=4;static name="CLOSE";constructor({reason:t}){this.reason=t}static parse(t){return new T({reason:t.view.getUint8(0)})}serialize(){let t=new v(1);return t.view.setUint8(0,this.buffer_remaining),t}}const C=[void 0,$,P,U,T],S={CONNECT:1,DATA:2,CONTINUE:3,CLOSE:4},q={TCP:1,UDP:2},N={Unknown:1,Voluntary:2,NetworkError:3,InvalidInfo:65,UnreachableHost:66,NoResponse:67,ConnRefused:68,TransferTimeout:71,HostBlocked:72,ConnThrottled:73,ClientError:129},O={hostname_blacklist:null,hostname_whitelist:null,port_blacklist:null,port_whitelist:null,allow_direct_ip:!0,allow_private_ips:!1,allow_loopback_ips:!1,client_ip_blacklist:null,client_ip_whitelist:null,stream_limit_per_host:-1,stream_limit_total:-1,allow_udp_streams:!0,allow_tcp_streams:!0};class D extends Error{}function E(t,e){return t===e||t[0]<=e&&t[1]>=e}function A(t,e){let s=!1;for(let i of t)if(e(i)){s=!0;break}return!s}function I(t,e){for(let s of t)if(e(s))return!0;return!1}function x(t,e,s,i){if(!O.allow_tcp_streams&&e===stream_types.TCP)return N.HostBlocked;if(!O.allow_udp_streams&&e===stream_types.UDP)return N.HostBlocked;if(O.hostname_whitelist){if(A(O.hostname_whitelist,(t=>t.test(s))))return N.HostBlocked}else if(O.hostname_blacklist&&I(O.hostname_blacklist,(t=>t.test(s))))return N.HostBlocked;if(O.port_whitelist){if(A(O.port_whitelist,(t=>E(t,i))))return N.HostBlocked}else if(O.port_blacklist&&I(O.port_blacklist,(t=>E(t,i))))return N.HostBlocked;if(!t)return 0;if(-1!==O.stream_limit_total&&Object.keys(t.streams).length>=O.stream_limit_total)return N.ConnThrottled;if(-1!==O.stream_limit_per_host){let e=0;for(let i of t.streams)i.socket.hostname===s&&e++;if(e>=O.stream_limit_per_host)return N.ConnThrottled}return 0}const B=globalThis.WebSocket,H=globalThis.crypto,R=null,j=null,W=null;class M{send_buffer_size=33554432;constructor(t){this.ws=t,this.connected=!1,this.data_queue=new V(1)}async connect(){await new Promise(((t,e)=>{this.ws.onopen=()=>{this.connected=!0,t()},this.ws.onmessage=t=>{this.data_queue.put(t.data)},this.ws.onclose=()=>{this.connected?this.data_queue.close():e()},this.ws.readyState===this.ws.OPEN&&(this.connected=!0,t())}))}async recv(){return await this.data_queue.get()}async send(t){if(this.ws.send(t),!(this.ws.bufferedAmount<=this.send_buffer_size))for(;!(this.ws.bufferedAmount<=this.send_buffer_size/2);)await new Promise((t=>{setTimeout(t,10)}))}close(t,e){this.ws.close(t,e),this.data_queue.close()}get buffered_amount(){return this.ws.bufferedAmount}}class V{constructor(t){this.max_size=t,this.queue=[],this.put_callbacks=[],this.get_callbacks=[]}put_now(t){this.queue.push(t),this.get_callbacks.shift()?.()}async put(t){this.size<=this.max_size||await new Promise((t=>{this.put_callbacks.push(t)})),this.put_now(t)}get_now(){return this.put_callbacks.shift()?.(),this.queue.shift()}async get(){return this.size>0||await new Promise((t=>{this.get_callbacks.push(t)})),this.get_now()}close(){let t;for(this.queue=[];t=this.get_callbacks.shift();)t();for(;t=this.put_callbacks.shift();)t()}get size(){return this.queue.length}}const L="undefined"!=typeof process;function F(){if(!L)throw"not running on node.js"}async function G(t){let e=R.isIP(t);return 4===e||6===e?t:(await j.lookup(t)).address}class J{constructor(t,e){F(),this.hostname=t,this.port=e,this.recv_buffer_size=128,this.socket=null,this.paused=!1,this.connected=!1,this.data_queue=new V(this.recv_buffer_size)}async connect(){let t=await G(this.hostname);await new Promise(((e,s)=>{this.socket=new R.Socket,this.socket.setNoDelay(!0),this.socket.on("connect",(()=>{this.connected=!0,e()})),this.socket.on("data",(t=>{this.data_queue.put(t)})),this.socket.on("close",(t=>{t&&!this.connected?s():this.data_queue.close(),this.socket=null})),this.socket.on("error",(t=>{f(`tcp stream to ${this.hostname} ended with error - ${t}`)})),this.socket.on("end",(()=>{this.socket&&(this.socket.destroy(),this.socket=null)})),this.socket.connect({host:t,port:this.port})}))}async recv(){return await this.data_queue.get()}async send(t){await new Promise((e=>{this.socket.write(t,e)}))}async close(){this.socket&&(this.socket.end(),this.socket=null)}pause(){this.data_queue.size>=this.data_queue.max_size&&(this.socket.pause(),this.paused=!0)}resume(){this.socket&&this.paused&&(this.socket.resume(),this.paused=!1)}}class K{constructor(t,e){F(),this.hostname=t,this.port=e,this.connected=!1,this.recv_buffer_size=128,this.data_queue=new V(this.recv_buffer_size)}async connect(){let t=await G(this.hostname),e=R.isIP(t);await new Promise(((s,i)=>{this.socket=null.createSocket(6===e?"udp6":"udp4"),this.socket.on("connect",(()=>{s()})),this.socket.on("message",(t=>{this.data_queue.put(t)})),this.socket.on("error",(()=>{this.connected||i(),this.data_queue.close(),this.socket=null})),this.socket.connect(this.port,t)}))}async recv(){return await this.data_queue.get()}async send(t){this.socket.send(t)}async close(){this.socket&&(this.socket.close(),this.socket=null)}pause(){}resume(){}}class Q{static buffer_size=128;constructor(t,e,s){this.stream_id=t,this.conn=e,this.socket=s,this.send_buffer=new V(Q.buffer_size),this.packets_sent=0}async setup(){await this.socket.connect(),this.tcp_to_ws().catch((t=>{y(`(${this.conn.conn_id}) a tcp/udp to ws task encountered an error - ${t}`),this.close()})),this.ws_to_tcp().catch((t=>{y(`(${this.conn.conn_id}) a ws to tcp/udp task encountered an error - ${t}`),this.close()}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause();let e=new z({type:P.type,stream_id:this.stream_id,payload:new P({data:new v(new Uint8Array(t))})});await this.conn.ws.send(e.serialize().bytes),this.socket.resume()}await this.conn.close_stream(this.stream_id,N.Voluntary)}async ws_to_tcp(){for(;;){let t=await this.send_buffer.get();if(null==t)break;if(await this.socket.send(t),this.packets_sent++,this.packets_sent%(Q.buffer_size/2)!=0)continue;let e=new z({type:U.type,stream_id:this.stream_id,payload:new U({buffer_remaining:Q.buffer_size-this.send_buffer.size})});this.conn.ws.send(e.serialize().bytes)}await this.close()}async close(t=null){if(this.send_buffer.close(),this.socket.close(),null==t)return;let e=new z({type:T.type,stream_id:this.stream_id,payload:new T({reason:t})});await this.conn.ws.send(e.serialize().bytes)}async put_data(t){await this.send_buffer.put(t)}}class X{constructor(t,e,{TCPSocket:s,UDPSocket:i,ping_interval:a}={}){this.ws=new M(t),this.path=e,this.TCPSocket=s||J,this.UDPSocket=i||K,this.ping_interval=a||30,this.ping_task=null,this.streams={},this.conn_id=H.randomUUID().split("-")[0]}async setup(){d(`setting up new wisp connection with id ${this.conn_id}`),await this.ws.connect();let t=new z({type:U.type,stream_id:0,payload:new U({buffer_remaining:Q.buffer_size})});await this.ws.send(t.serialize().bytes),"function"==typeof this.ws.ws.ping&&(this.ping_task=setInterval((()=>{_(`(${this.conn_id}) sending websocket ping`),this.ws.ws.ping()}),1e3*this.ping_interval))}async create_stream(t,e,s,i){let a=x(this,e,s,i);if(a){f(`(${this.conn_id}) refusing to create a stream to ${s}:${i}`);let e=new z({type:T.type,stream_id:t,payload:new T({reason:a})});return void await this.ws.send(e.serialize().bytes)}let n=new(e===q.TCP?this.TCPSocket:this.UDPSocket)(s,i),o=new Q(t,this,n);this.streams[t]=o,o.setup().catch((e=>{f(`(${this.conn_id}) creating a stream to ${s}:${i} failed - ${e}`),this.close_stream(t,N.NetworkError)}))}async close_stream(t,e=null){let s=this.streams[t];null!=s&&(e&&d(`(${this.conn_id}) closing stream to ${s.socket.hostname} for reason ${e}`),await s.close(e),delete this.streams[t])}async route_packet(t){let e=z.parse_all(t),s=this.streams[e.stream_id];if(null!=s||e.type!=P.type)if(e.type===$.type){let t=e.payload.stream_type===q.TCP?"TCP":"UDP";d(`(${this.conn_id}) opening new ${t} stream to ${e.payload.hostname}:${e.payload.port}`),await this.create_stream(e.stream_id,e.payload.stream_type,e.payload.hostname,e.payload.port)}else e.type===P.type?s.put_data(e.payload.data.bytes):e.type==U.type?f(`(${this.conn_id}) client sent a CONTINUE packet, this should never be possible`):e.type==T.type&&await this.close_stream(e.stream_id,e.reason);else f(`(${this.conn_id}) received a DATA packet for a stream which doesn't exist`)}async run(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;try{this.route_packet(new v(new Uint8Array(t)))}catch(t){f(`(${this.conn_id}) routing a packet failed - ${t}`)}}for(let t of Object.keys(this.streams))await this.close_stream(t);clearInterval(this.ping_task),d(`(${this.conn_id}) wisp connection closed`)}}class Y{constructor(t,e){let[s,i]=e.split("/").pop().split(":");if(this.hostname=s,this.port=parseInt(i),0!==x(null,q.TCP,this.hostname,this.port))throw d(`Refusing to create a wsproxy connection to ${this.hostname}:${this.port}`),new D;this.socket=new J(s,i),this.ws=new M(t)}async setup(){await this.ws.connect(),await this.socket.connect(),this.tcp_to_ws().catch((t=>{y(`a tcp to ws task (wsproxy) encountered an error - ${t}`)})),this.ws_to_tcp().catch((t=>{y(`a ws to tcp task (wsproxy) encountered an error - ${t}`)}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause(),await this.ws.send(t),this.socket.resume()}await this.ws.close()}async ws_to_tcp(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;await this.socket.send(t)}await this.socket.close()}}let Z=null;function tt(t,e,s,i={}){F(),t instanceof W.IncomingMessage?Z.handleUpgrade(t,e,s,(e=>{et(e,t.url,t,i)})):t instanceof B&&et(ws,"/",{})}async function et(t,e,s,i){d(`new connection on ${e} from ${s.socket.address().address}`);try{if(e.endsWith("/")){let s=new X(t,e,i);await s.setup(),await s.run()}else{let s=new Y(t,e,i);await s.setup()}}catch(e){if(t.close(),e instanceof D)return;y("Uncaught server error:\n"+e.stack)}}L&&(Z=new null({noServer:!0})),wisp_server=e})(); | ||
var wisp_server;(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{logging:()=>s,packet:()=>i,server:()=>a});var s={};t.r(s),t.d(s,{DEBUG:()=>n,ERROR:()=>c,INFO:()=>o,NONE:()=>l,WARN:()=>r,debug:()=>_,error:()=>y,get_timestamp:()=>u,info:()=>d,log:()=>w,log_level:()=>h,set_level:()=>p,warn:()=>f});var i={};t.r(i),t.d(i,{ClosePayload:()=>T,ConnectPayload:()=>$,ContinuePayload:()=>U,DataPayload:()=>P,WispBuffer:()=>v,WispPacket:()=>z,close_reasons:()=>N,packet_classes:()=>C,packet_types:()=>S,stream_types:()=>q});var a={};t.r(a),t.d(a,{ServerConnection:()=>X,ServerStream:()=>Q,options:()=>O,routeRequest:()=>tt});const n=0,o=1,r=2,c=3,l=4;let h=o;function u(){let[t,e]=(new Date).toJSON().split("T");return t=t.replaceAll("-","/"),e=e.split(".")[0],`[${t} - ${e}]`}function p(t){h=t}function _(...t){h>n||console.debug(u()+" debug:",...t)}function d(...t){h>o||console.info(u()+" info:",...t)}function w(...t){h>o||console.log(u()+" log:",...t)}function f(...t){h>r||console.warn(u()+" warn:",...t)}function y(...t){h>c||console.error(u()+" error:",...t)}const m=new TextEncoder,k=m.encode.bind(m),b=new TextDecoder,g=b.decode.bind(b);class v{constructor(t){if(t instanceof Uint8Array)this.from_array(t);else if("number"==typeof t)this.from_array(new Uint8Array(t));else{if("string"!=typeof t)throw console.trace(),"invalid data type passed to wisp buffer constructor";this.from_array(k(t))}}from_array(t){this.size=t.length,this.bytes=t,this.view=new DataView(t.buffer)}concat(t){let e=new v(this.size+t.size);return e.bytes.set(this.bytes,0),e.bytes.set(t.bytes,this.size),e}slice(t,e){let s=this.bytes.slice(t,e);return new v(s)}}class z{static min_size=5;constructor({type:t,stream_id:e,payload:s,payload_bytes:i}){this.type=t,this.stream_id=e,this.payload_bytes=i,this.payload=s}static parse(t){return new z({type:t.view.getUint8(0),stream_id:t.view.getUint32(1,!0),payload_bytes:t.slice(5)})}static parse_all(t){if(t.size<z.min_size)throw"packet too small";let e=z.parse(t),s=C[e.type];if(void 0===s)throw"invalid packet type";if(e.payload_bytes.size<s.size)throw"payload too small";return e.payload=s.parse(e.payload_bytes),e}serialize(){let t=new v(5);return t.view.setUint8(0,this.type),t.view.setUint32(1,this.stream_id,!0),t=t.concat(this.payload.serialize()),t}}class ${static min_size=3;static type=1;static name="CONNECT";constructor({stream_type:t,port:e,hostname:s}){this.stream_type=t,this.port=e,this.hostname=s}static parse(t){return new $({stream_type:t.view.getUint8(0),port:t.view.getUint16(1,!0),hostname:g(t.slice(3).bytes)})}serialize(){let t=new v(3);return t.view.setUint8(0,this.stream_type),t.view.setUint16(1,this.port,!0),t=t.concat(new v(this.hostname)),t}}class P{static min_size=0;static type=2;static name="DATA";constructor({data:t}){this.data=t}static parse(t){return new P({data:t})}serialize(){return this.data}}class U{static type=3;static name="CONTINUE";constructor({buffer_remaining:t}){this.buffer_remaining=t}static parse(t){return new U({buffer_remaining:t.view.getUint32(0,!0)})}serialize(){let t=new v(4);return t.view.setUint32(0,this.buffer_remaining,!0),t}}class T{static min_size=1;static type=4;static name="CLOSE";constructor({reason:t}){this.reason=t}static parse(t){return new T({reason:t.view.getUint8(0)})}serialize(){let t=new v(1);return t.view.setUint8(0,this.buffer_remaining),t}}const C=[void 0,$,P,U,T],S={CONNECT:1,DATA:2,CONTINUE:3,CLOSE:4},q={TCP:1,UDP:2},N={Unknown:1,Voluntary:2,NetworkError:3,InvalidInfo:65,UnreachableHost:66,NoResponse:67,ConnRefused:68,TransferTimeout:71,HostBlocked:72,ConnThrottled:73,ClientError:129},O={hostname_blacklist:null,hostname_whitelist:null,port_blacklist:null,port_whitelist:null,allow_direct_ip:!0,allow_private_ips:!1,allow_loopback_ips:!1,client_ip_blacklist:null,client_ip_whitelist:null,stream_limit_per_host:-1,stream_limit_total:-1,allow_udp_streams:!0,allow_tcp_streams:!0};class D extends Error{}function E(t,e){return t===e||t[0]<=e&&t[1]>=e}function A(t,e){let s=!1;for(let i of t)if(e(i)){s=!0;break}return!s}function I(t,e){for(let s of t)if(e(s))return!0;return!1}function x(t,e,s,i){if(!O.allow_tcp_streams&&e===q.TCP)return N.HostBlocked;if(!O.allow_udp_streams&&e===q.UDP)return N.HostBlocked;if(O.hostname_whitelist){if(A(O.hostname_whitelist,(t=>t.test(s))))return N.HostBlocked}else if(O.hostname_blacklist&&I(O.hostname_blacklist,(t=>t.test(s))))return N.HostBlocked;if(O.port_whitelist){if(A(O.port_whitelist,(t=>E(t,i))))return N.HostBlocked}else if(O.port_blacklist&&I(O.port_blacklist,(t=>E(t,i))))return N.HostBlocked;if(!t)return 0;if(-1!==O.stream_limit_total&&Object.keys(t.streams).length>=O.stream_limit_total)return N.ConnThrottled;if(-1!==O.stream_limit_per_host){let e=0;for(let i of t.streams)i.socket.hostname===s&&e++;if(e>=O.stream_limit_per_host)return N.ConnThrottled}return 0}const B=globalThis.WebSocket,H=globalThis.crypto,R=null,j=null,W=null;class M{send_buffer_size=33554432;constructor(t){this.ws=t,this.connected=!1,this.data_queue=new V(1)}async connect(){await new Promise(((t,e)=>{this.ws.onopen=()=>{this.connected=!0,t()},this.ws.onmessage=t=>{this.data_queue.put(t.data)},this.ws.onclose=()=>{this.connected?this.data_queue.close():e()},this.ws.readyState===this.ws.OPEN&&(this.connected=!0,t())}))}async recv(){return await this.data_queue.get()}async send(t){if(this.ws.send(t),!(this.ws.bufferedAmount<=this.send_buffer_size))for(;!(this.ws.bufferedAmount<=this.send_buffer_size/2);)await new Promise((t=>{setTimeout(t,10)}))}close(t,e){this.ws.close(t,e),this.data_queue.close()}get buffered_amount(){return this.ws.bufferedAmount}}class V{constructor(t){this.max_size=t,this.queue=[],this.put_callbacks=[],this.get_callbacks=[]}put_now(t){this.queue.push(t),this.get_callbacks.shift()?.()}async put(t){this.size<=this.max_size||await new Promise((t=>{this.put_callbacks.push(t)})),this.put_now(t)}get_now(){return this.put_callbacks.shift()?.(),this.queue.shift()}async get(){return this.size>0||await new Promise((t=>{this.get_callbacks.push(t)})),this.get_now()}close(){let t;for(this.queue=[];t=this.get_callbacks.shift();)t();for(;t=this.put_callbacks.shift();)t()}get size(){return this.queue.length}}const L="undefined"!=typeof process;function F(){if(!L)throw"not running on node.js"}async function G(t){let e=R.isIP(t);return 4===e||6===e?t:(await j.lookup(t)).address}class J{constructor(t,e){F(),this.hostname=t,this.port=e,this.recv_buffer_size=128,this.socket=null,this.paused=!1,this.connected=!1,this.data_queue=new V(this.recv_buffer_size)}async connect(){let t=await G(this.hostname);await new Promise(((e,s)=>{this.socket=new R.Socket,this.socket.setNoDelay(!0),this.socket.on("connect",(()=>{this.connected=!0,e()})),this.socket.on("data",(t=>{this.data_queue.put(t)})),this.socket.on("close",(t=>{t&&!this.connected?s():this.data_queue.close(),this.socket=null})),this.socket.on("error",(t=>{f(`tcp stream to ${this.hostname} ended with error - ${t}`)})),this.socket.on("end",(()=>{this.socket&&(this.socket.destroy(),this.socket=null)})),this.socket.connect({host:t,port:this.port})}))}async recv(){return await this.data_queue.get()}async send(t){await new Promise((e=>{this.socket.write(t,e)}))}async close(){this.socket&&(this.socket.end(),this.socket=null)}pause(){this.data_queue.size>=this.data_queue.max_size&&(this.socket.pause(),this.paused=!0)}resume(){this.socket&&this.paused&&(this.socket.resume(),this.paused=!1)}}class K{constructor(t,e){F(),this.hostname=t,this.port=e,this.connected=!1,this.recv_buffer_size=128,this.data_queue=new V(this.recv_buffer_size)}async connect(){let t=await G(this.hostname),e=R.isIP(t);await new Promise(((s,i)=>{this.socket=null.createSocket(6===e?"udp6":"udp4"),this.socket.on("connect",(()=>{s()})),this.socket.on("message",(t=>{this.data_queue.put(t)})),this.socket.on("error",(()=>{this.connected||i(),this.data_queue.close(),this.socket=null})),this.socket.connect(this.port,t)}))}async recv(){return await this.data_queue.get()}async send(t){this.socket.send(t)}async close(){this.socket&&(this.socket.close(),this.socket=null)}pause(){}resume(){}}class Q{static buffer_size=128;constructor(t,e,s){this.stream_id=t,this.conn=e,this.socket=s,this.send_buffer=new V(Q.buffer_size),this.packets_sent=0}async setup(){await this.socket.connect(),this.tcp_to_ws().catch((t=>{y(`(${this.conn.conn_id}) a tcp/udp to ws task encountered an error - ${t}`),this.close()})),this.ws_to_tcp().catch((t=>{y(`(${this.conn.conn_id}) a ws to tcp/udp task encountered an error - ${t}`),this.close()}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause();let e=new z({type:P.type,stream_id:this.stream_id,payload:new P({data:new v(new Uint8Array(t))})});await this.conn.ws.send(e.serialize().bytes),this.socket.resume()}await this.conn.close_stream(this.stream_id,N.Voluntary)}async ws_to_tcp(){for(;;){let t=await this.send_buffer.get();if(null==t)break;if(await this.socket.send(t),this.packets_sent++,this.packets_sent%(Q.buffer_size/2)!=0)continue;let e=new z({type:U.type,stream_id:this.stream_id,payload:new U({buffer_remaining:Q.buffer_size-this.send_buffer.size})});this.conn.ws.send(e.serialize().bytes)}await this.close()}async close(t=null){if(this.send_buffer.close(),this.socket.close(),null==t)return;let e=new z({type:T.type,stream_id:this.stream_id,payload:new T({reason:t})});await this.conn.ws.send(e.serialize().bytes)}async put_data(t){await this.send_buffer.put(t)}}class X{constructor(t,e,{TCPSocket:s,UDPSocket:i,ping_interval:a}={}){this.ws=new M(t),this.path=e,this.TCPSocket=s||J,this.UDPSocket=i||K,this.ping_interval=a||30,this.ping_task=null,this.streams={},this.conn_id=H.randomUUID().split("-")[0]}async setup(){d(`setting up new wisp connection with id ${this.conn_id}`),await this.ws.connect();let t=new z({type:U.type,stream_id:0,payload:new U({buffer_remaining:Q.buffer_size})});await this.ws.send(t.serialize().bytes),"function"==typeof this.ws.ws.ping&&(this.ping_task=setInterval((()=>{_(`(${this.conn_id}) sending websocket ping`),this.ws.ws.ping()}),1e3*this.ping_interval))}async create_stream(t,e,s,i){let a=x(this,e,s,i);if(a){f(`(${this.conn_id}) refusing to create a stream to ${s}:${i}`);let e=new z({type:T.type,stream_id:t,payload:new T({reason:a})});return void await this.ws.send(e.serialize().bytes)}let n=new(e===q.TCP?this.TCPSocket:this.UDPSocket)(s,i),o=new Q(t,this,n);this.streams[t]=o,o.setup().catch((e=>{f(`(${this.conn_id}) creating a stream to ${s}:${i} failed - ${e}`),this.close_stream(t,N.NetworkError)}))}async close_stream(t,e=null){let s=this.streams[t];null!=s&&(e&&d(`(${this.conn_id}) closing stream to ${s.socket.hostname} for reason ${e}`),await s.close(e),delete this.streams[t])}async route_packet(t){let e=z.parse_all(t),s=this.streams[e.stream_id];if(null!=s||e.type!=P.type)if(e.type===$.type){let t=e.payload.stream_type===q.TCP?"TCP":"UDP";d(`(${this.conn_id}) opening new ${t} stream to ${e.payload.hostname}:${e.payload.port}`),await this.create_stream(e.stream_id,e.payload.stream_type,e.payload.hostname,e.payload.port)}else e.type===P.type?s.put_data(e.payload.data.bytes):e.type==U.type?f(`(${this.conn_id}) client sent a CONTINUE packet, this should never be possible`):e.type==T.type&&await this.close_stream(e.stream_id,e.reason);else f(`(${this.conn_id}) received a DATA packet for a stream which doesn't exist`)}async run(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;try{this.route_packet(new v(new Uint8Array(t)))}catch(t){f(`(${this.conn_id}) routing a packet failed - ${t}`)}}for(let t of Object.keys(this.streams))await this.close_stream(t);clearInterval(this.ping_task),d(`(${this.conn_id}) wisp connection closed`)}}class Y{constructor(t,e){let[s,i]=e.split("/").pop().split(":");if(this.hostname=s,this.port=parseInt(i),0!==x(null,q.TCP,this.hostname,this.port))throw d(`Refusing to create a wsproxy connection to ${this.hostname}:${this.port}`),new D;this.socket=new J(s,i),this.ws=new M(t)}async setup(){await this.ws.connect(),await this.socket.connect(),this.tcp_to_ws().catch((t=>{y(`a tcp to ws task (wsproxy) encountered an error - ${t}`)})),this.ws_to_tcp().catch((t=>{y(`a ws to tcp task (wsproxy) encountered an error - ${t}`)}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause(),await this.ws.send(t),this.socket.resume()}await this.ws.close()}async ws_to_tcp(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;await this.socket.send(t)}await this.socket.close()}}let Z=null;function tt(t,e,s,i={}){F(),t instanceof W.IncomingMessage?Z.handleUpgrade(t,e,s,(e=>{et(e,t.url,t,i)})):t instanceof B&&et(ws,"/",{})}async function et(t,e,s,i){d(`new connection on ${e} from ${s.socket.address().address}`);try{if(e.endsWith("/")){let s=new X(t,e,i);await s.setup(),await s.run()}else{let s=new Y(t,e,i);await s.setup()}}catch(e){if(t.close(),e instanceof D)return;y("Uncaught server error:\n"+e.stack)}}L&&(Z=new null({noServer:!0})),wisp_server=e})(); |
{ | ||
"name": "@mercuryworkshop/wisp-js", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "A client and server for the Wisp protocol, written in Javascript", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -12,2 +12,23 @@ # JavaScript Wisp Implementation | ||
## Server CLI: | ||
THere is a CLI interface available for the Wisp server, and it can be used by installing the package with npm, then running: | ||
``` | ||
$ npx wisp-js-server --help | ||
Usage: wisp-js-server [options] | ||
A Wisp server implementation written in Javascript. (v0.2.1) | ||
Options: | ||
-V, --version output the version number | ||
-H, --host <host> The hostname the server will listen on. (default: "127.0.0.1") | ||
-P, --port <port> The port number to run the server on. (default: 5001) | ||
-L, --logging <log_level> The log level to use. This is either DEBUG, INFO, WARN, ERROR, or NONE. (default: "INFO") | ||
-S, --static <static_dir> The directory to serve static files from. (optional) (default: null) | ||
-C, --config <config_path> The path to your server config file. (optional) (default: null) | ||
-h, --help display help for command | ||
``` | ||
You may also clone this repository and run `npn run server_cli -- --help`. | ||
The config file is a JSON file with the same entries as the [global server config](https://github.com/MercuryWorkshop/wisp-client-js/?tab=readme-ov-file#changing-server-settings) in the API. | ||
## Client API: | ||
@@ -14,0 +35,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
204072
1261
221