Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can this lib be used with websockets? #62

Open
rutexd opened this issue Jan 6, 2023 · 2 comments
Open

Can this lib be used with websockets? #62

rutexd opened this issue Jan 6, 2023 · 2 comments

Comments

@rutexd
Copy link

rutexd commented Jan 6, 2023

Hey,
is it possible to use this lib with websocket?
As far as i see in your wiki examples, i have to use Socket Host class from heaps, which i guess is TCP.
But is there way to use it over hxWebSockets, for example?

@ncannasse
Copy link
Member

ncannasse commented Jan 6, 2023 via email

@jefvel
Copy link

jefvel commented Jan 18, 2025

Here's a websocket implementation using hxwebsockets :)

package elk.net;

import hx.ws.WebSocket;
import hx.ws.Types;
#if (sys || hxnodejs)
import hx.ws.WebSocketServer;
import hx.ws.WebSocketHandler;
#end
#if !hxbit
#error "Using SocketHost requires compiling with -lib hxbit"
#end
import hxbit.NetworkHost;

class WebSocketClient extends NetworkClient {
	var socket: WebSocket;

	public function new(host, s) {
		super(host);
		this.socket = s;
		if (s != null) s.onmessage = function(message) {
			switch (message) {
				case BytesMessage(content):
					var bytes = content.readAllAvailableBytes();
					processMessagesData(bytes, 0, bytes.length);
				case StrMessage(content):
			}
		}
	}

	override function error(msg: String) {
		socket.close();
		super.error(msg);
	}

	override function send(bytes: haxe.io.Bytes) {
		if (socket == null || socket.state == Closed) return;
		#if js
		var data = bytes.getData();
		if (data.byteLength != bytes.length) {
			data = data.slice(0, bytes.length);
		}
		socket.send(data);
		return;
		#end
		socket.send(bytes);
	}

	override function stop() {
		super.stop();
		if (socket != null) {
			socket.close();
			socket = null;
		}
	}
}

private class WebSocketHostCommon extends NetworkHost {
	public var connected(default, null) = false;
	public var enableSound: Bool = true;

	var web_socket: hx.ws.WebSocket;
	var on_disconnect: Void -> Void = null;

	public function new() {
		super();
		MultiplayerHandler.instance.host = this;
		isAuth = false;
	}

	function close() {
		if (connected && on_disconnect != null) {
			on_disconnect();
		}

		connected = false;

		if (web_socket != null) {
			trace('closed socket.');
			// If mid connection, socket might not close correctly.
			// in this case, close the socket as soon as it connects.
			web_socket.onopen = web_socket.close;
			var sock = web_socket;
			web_socket = null;
			sock.close();
		}

		MultiplayerHandler.instance.reset();
	}

	override public function dispose() {
		super.dispose();
		close();
	}

	public function connect(address: String, ?protocols: Array<String>, ?onConnect: Bool -> Void, ?onDisconnect: Void -> Void) {
		close();
		on_disconnect = onDisconnect;

		isAuth = false;
		web_socket = new hx.ws.WebSocket(address, false, protocols);

		self = new WebSocketClient(this, web_socket);

		web_socket.onerror = function(msg) {
			if (!connected) {
				web_socket.onerror = function(_) {};
				if (onConnect != null) onConnect(false);
			}
			else throw msg;
		};

		web_socket.onopen = function() {
			web_socket.onerror = null;
			connected = true;
			if (StringTools.contains(address, "127.0.0.1")) enableSound = false;
			clients = [self];
			if (onConnect != null) onConnect(true);
		}

		web_socket.onclose = function() {
			close();
		}

		web_socket.open();
	}

	public function offlineServer() {
		close();
		self = new WebSocketClient(this, null);
		isAuth = true;
	}
}

#if (sys || hxnodejs)
class WebSocketHandlerClient extends NetworkClient {
	var socket: WebSocketHandler;

	public function new(host, s) {
		super(host);
		this.socket = s;
		if (s != null) {
			s.onmessage = function(message) {
				try {
					switch (message) {
						case BytesMessage(content):
							var bytes = content.readAllAvailableBytes();
							processMessagesData(bytes, 0, bytes.length);

						case StrMessage(content):
					}
				}
				catch (e) {
					trace(e);
					trace(haxe.CallStack.toString(haxe.CallStack.callStack()));
					stop();
				}
			}
		}
	}

	override function error(msg: String) {
		socket.close();
		super.error(msg);
	}

	override function send(bytes: haxe.io.Bytes) {
		if (socket == null || socket.state == Closed) return;
		socket.send(bytes);
	}

	override public function stop() {
		super.stop();
		if (socket != null) {
			socket.close();
		}
	}
}

class WebSocketHost extends WebSocketHostCommon {
	var server: WebSocketServer<elk.newgrounds.NGWebSocketHandler>;

	override function close() {
		super.close();
		if (server != null) {
			server.stop();
			server = null;
		}
	}

	public function wait(host: String, port: Int, ?onConnected: NetworkClient -> Void, ?onDisconnected: NetworkClient -> Void) {
		close();
		isAuth = false;
		self = new WebSocketHandlerClient(this, null);
		
		server = new WebSocketServer(host, port, 100);

		server.onClientAdded = (client) -> {
			var c = new WebSocketHandlerClient(this, client);
			client.onopen = () -> {
				pendingClients.push(c);
				if (onConnected != null) onConnected(c);
				client.onclose = () -> {
					c.stop();
					if (onDisconnected != null) {
						onDisconnected(c);
					}
					client.onclose = null;
				}
			}
			client.onerror = function(err) {
				trace(err);
				// trace(haxe.CallStack.toString(haxe.CallStack.callStack()));
			}
		}

		server.start();
		isAuth = true;
	}
}
#else
class WebSocketHost extends WebSocketHostCommon {
	public function wait(host: String, port: Int, ?onConnected: NetworkClient -> Void) {
		throw "Can't host websocket server in browser.";
	}
}
#end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants