extends Node """ This module is responsible for making a WebSocket connection to the signaller in order to enable establishish WebRTC P2P connections. Another module is expected to fully setup the peer connections. """ signal lobby_new(lobbiesList) signal lobby_delete(id) signal lobby_joined(id) signal lobby_left(id) signal peer_joined(id) signal peer_left(id) signal websocket_connected signal websocket_disconnected onready var ws: WebSocketClient = WebSocketClient.new() onready var lobby_id = null func _ready(): var _result = ws.connect("data_received", self, "_parse_msg") _result = ws.connect("connection_established", self, "_connected") _result = ws.connect("connection_closed", self, "_closed") _result = ws.connect("connection_error", self, "_closed") _result = ws.connect("server_close_request", self, "_close_request") func close(): ws.disconnect_from_host() func connect_to_websocket_signaller(url: String): print(ws) close() print("Attempting to connect to WebSocket signalling server at ", url) var _result = ws.connect_to_url(url) func _closed(): emit_signal("websocket_disconnected") func _close_request(code: int, reason: String): print("Received WebSocket close request from signalling server ", code, reason) func _connected(protocol = ""): print("WebSocket signaller connected via protocol ", protocol) ws.get_peer(1).set_write_mode(WebSocketPeer.WRITE_MODE_TEXT) emit_signal("websocket_connected") func _process(_delta: float): var status: int = ws.get_connection_status() if status == WebSocketClient.CONNECTION_CONNECTING or status == WebSocketClient.CONNECTION_CONNECTED: ws.poll() func join_lobby(id: String): return _send("lobby_join:%s" % id) func create_lobby(): return _send("lobby_create") func request_lobby_list(): return _send("request_lobby_list") func request_peer_list(): return _send("request_peer_list") func _send(s: String): return ws.get_peer(1).put_packet(s.to_utf8()) func _parse_msg(): var msg: String = ws.get_peer(1).get_packet().get_string_from_utf8() print("Signaller sent: ", msg) if msg.begins_with("json:"): var data = JSON.parse(msg.substr(5)) if data.error == OK: handle_message(data.result) else: print("Unhandled Message: ", msg) func handle_message(data: Dictionary): match data["type"]: "lobby_new": emit_signal("lobby_new", [{"id": data["id"], "name": data["name"]}]) "lobby_delete": emit_signal("lobby_delete", data["id"]) "lobby_joined": lobby_id = data["id"] emit_signal("lobby_joined", data["id"]) "lobby_left": lobby_id = null emit_signal("lobby_left", data["id"]) "lobby_list": emit_signal("lobby_new", data["data"]) "peer_list": emit_signal("peer_joined", data["data"]) "peer_joined": emit_signal("peer_joined", [{"id": data["id"], "name": data["name"]}]) "peer_left": emit_signal("peer_left", data["id"]) _: print("Unhandled Data Message: ", JSON.print(data)) """ func _parse_msg(): var pkt_str: String = ws.get_peer(1).get_packet().get_string_from_utf8() var req: PoolStringArray = pkt_str.split("\n", true, 1) if req.size() != 2: # Invalid request size return var type: String = req[0] if type.length() < 3: # Invalid type size return if type.begins_with("J: "): print("Emitting lobby_joined") emit_signal("lobby_joined", type.substr(3, type.length() - 3)) return elif type.begins_with("S: "): emit_signal("lobby_sealed") return var src_str: String = type.substr(3, type.length() - 3) if not src_str.is_valid_integer(): # Source id is not an integer return var src_id: int = int(src_str) if type.begins_with("I: "): print("Emitting connected") emit_signal("connected", src_id) elif type.begins_with("N: "): # Client connected print("Emitting peer_connected") emit_signal("peer_connected", src_id) elif type.begins_with("D: "): # Client connected emit_signal("peer_disconnected", src_id) elif type.begins_with("O: "): # Offer received print("Emitting offer_received") emit_signal("offer_received", src_id, req[1]) elif type.begins_with("A: "): # Answer received print("Emitting answer_received") emit_signal("answer_received", src_id, req[1]) elif type.begins_with("C: "): # Candidate received var candidate: PoolStringArray = req[1].split("\n", false) if candidate.size() != 3: return if not candidate[1].is_valid_integer(): return print("Emitting candidate_received") emit_signal("candidate_received", src_id, candidate[0], int(candidate[1]), candidate[2]) func join_lobby(joined_lobby): return ws.get_peer(1).put_packet(("J: %s\n" % joined_lobby).to_utf8()) func seal_lobby(): return ws.get_peer(1).put_packet("S: \n".to_utf8()) func send_candidate(id, mid, index, sdp) -> int: return _send_msg("C", id, "\n%s\n%d\n%s" % [mid, index, sdp]) func send_offer(id, offer) -> int: return _send_msg("O", id, offer) func send_answer(id, answer) -> int: return _send_msg("A", id, answer) func _send_msg(type, id, data) -> int: return ws.get_peer(1).put_packet(("%s: %d\n%s" % [type, id, data]).to_utf8()) """