first
This commit is contained in:
207
addons/netfox.noray/noray.gd
Normal file
207
addons/netfox.noray/noray.gd
Normal file
@@ -0,0 +1,207 @@
|
||||
extends Node
|
||||
## A noray client for Godot.
|
||||
##
|
||||
## See: https://github.com/foxssake/noray
|
||||
|
||||
var _peer: StreamPeerTCP = StreamPeerTCP.new()
|
||||
var _protocol: NorayProtocolHandler = NorayProtocolHandler.new()
|
||||
var _address: String = ""
|
||||
var _oid: String = ""
|
||||
var _pid: String = ""
|
||||
var _local_port: int = -1
|
||||
|
||||
static var _logger: _NetfoxLogger = _NetfoxLogger.for_noray("Noray")
|
||||
|
||||
## Open ID.
|
||||
##
|
||||
## [i]read-only[/i], this is set after registering as host.
|
||||
var oid: String:
|
||||
get: return _oid
|
||||
set(v): push_error("Trying to set read-only variable oid")
|
||||
|
||||
## Private ID.
|
||||
##
|
||||
## [i]read-only[/i], this is set after registering as host.
|
||||
var pid: String:
|
||||
get: return _pid
|
||||
set(v): push_error("Trying to set read-only variable pid")
|
||||
|
||||
## Registered local port.
|
||||
##
|
||||
## This is the port that servers should listen on and the port that clients
|
||||
## should bind to ( i.e. use as local port ), since this port has been
|
||||
## registered with noray as part of this machine's external address, and this
|
||||
## is the port over which any handshake happens.
|
||||
##
|
||||
## [i]read-only[/i], this is set after registering remote.
|
||||
var local_port: int:
|
||||
get: return _local_port
|
||||
set(v): push_error("Trying to set read-only variable local_port")
|
||||
|
||||
## Emitted for any command received from noray.
|
||||
signal on_command(command: String, data: String)
|
||||
|
||||
## Emitted when connected to noray.
|
||||
signal on_connect_to_host()
|
||||
|
||||
## Emitted when disconnected from noray.
|
||||
signal on_disconnect_from_host()
|
||||
|
||||
## Emitted when an OpenID is received from noray.
|
||||
signal on_oid(oid: String)
|
||||
|
||||
## Emitted when a PrivateID is received from noray.
|
||||
signal on_pid(pid: String)
|
||||
|
||||
## Emitted when a connect over NAT command is received from noray.
|
||||
signal on_connect_nat(address: String, port: int)
|
||||
|
||||
## Emitted when a connect over relay command is received from noray.
|
||||
signal on_connect_relay(address: String, port: int)
|
||||
|
||||
func _enter_tree():
|
||||
_protocol.on_command.connect(func (cmd, data): on_command.emit(cmd, data))
|
||||
on_command.connect(_handle_commands)
|
||||
|
||||
## Connect to noray at host.
|
||||
func connect_to_host(hostname: String, port: int = 8890) -> Error:
|
||||
if is_connected_to_host():
|
||||
disconnect_from_host()
|
||||
|
||||
_logger.info("Trying to connect to noray at %s:%s", [hostname, port])
|
||||
|
||||
var address = IP.resolve_hostname(hostname, IP.TYPE_IPV4)
|
||||
if address:
|
||||
_logger.debug("Resolved noray host to %s", [address])
|
||||
else:
|
||||
_logger.error("Couldn't resolve hostname %s", [hostname])
|
||||
|
||||
var err = _peer.connect_to_host(address, port)
|
||||
if err != Error.OK:
|
||||
return err
|
||||
|
||||
_peer.set_no_delay(true)
|
||||
_protocol.reset()
|
||||
|
||||
while _peer.get_status() < 2:
|
||||
_peer.poll()
|
||||
await get_tree().process_frame
|
||||
|
||||
if _peer.get_status() == _peer.STATUS_CONNECTED:
|
||||
_address = address
|
||||
_logger.info("Connected to noray at %s:%s", [address, port])
|
||||
on_connect_to_host.emit()
|
||||
return OK
|
||||
else:
|
||||
_logger.error("Connection failed to noray at %s:%s, connection status %s", [address, port, _peer.get_status()])
|
||||
disconnect_from_host()
|
||||
return ERR_CONNECTION_ERROR
|
||||
|
||||
## Check if connected to any host.
|
||||
func is_connected_to_host() -> bool:
|
||||
return _peer.get_status() == _peer.STATUS_CONNECTED
|
||||
|
||||
## Disconnect from noray.
|
||||
##
|
||||
## Does nothing if already disconnected.
|
||||
func disconnect_from_host():
|
||||
if is_connected_to_host():
|
||||
on_disconnect_from_host.emit()
|
||||
_peer.disconnect_from_host()
|
||||
|
||||
## Register as host.
|
||||
func register_host() -> Error:
|
||||
return _put_command("register-host")
|
||||
|
||||
## Register remote address.
|
||||
func register_remote(registrar_port: int = 8809, timeout: float = 8, interval: float = 0.1) -> Error:
|
||||
if not is_connected_to_host():
|
||||
return ERR_CONNECTION_ERROR
|
||||
|
||||
if not pid:
|
||||
return ERR_UNAUTHORIZED
|
||||
|
||||
var result = ERR_TIMEOUT
|
||||
var udp = PacketPeerUDP.new()
|
||||
udp.bind(0)
|
||||
udp.set_dest_address(_address, registrar_port)
|
||||
|
||||
_logger.debug("Bound UDP to port %s", [udp.get_local_port()])
|
||||
|
||||
var packet = pid.to_utf8_buffer()
|
||||
|
||||
while timeout > 0:
|
||||
udp.put_packet(packet)
|
||||
|
||||
while udp.get_available_packet_count() > 0:
|
||||
var recv = udp.get_packet().get_string_from_utf8()
|
||||
if recv == "OK":
|
||||
_local_port = udp.get_local_port()
|
||||
_logger.info("Registered local port %s to remote", [_local_port])
|
||||
result = OK
|
||||
timeout = 0 # Break outer loop
|
||||
break
|
||||
else:
|
||||
_logger.error("Failed to register local port!")
|
||||
result = FAILED
|
||||
timeout = 0 # Break outer loop
|
||||
break
|
||||
# Sleep
|
||||
await get_tree().create_timer(interval).timeout
|
||||
timeout -= interval
|
||||
|
||||
udp.close()
|
||||
return result
|
||||
|
||||
## Connect to a given host by OID over NAT.
|
||||
func connect_nat(host_oid: String) -> Error:
|
||||
return _put_command("connect", host_oid)
|
||||
|
||||
## Connect to a given host by OID over relay.
|
||||
func connect_relay(host_oid: String) -> Error:
|
||||
return _put_command("connect-relay", host_oid)
|
||||
|
||||
func _process(_delta):
|
||||
if not is_connected_to_host():
|
||||
return
|
||||
|
||||
_peer.poll()
|
||||
var available = _peer.get_available_bytes()
|
||||
if available <= 0:
|
||||
return
|
||||
|
||||
_protocol.ingest(_peer.get_utf8_string(available))
|
||||
|
||||
func _put_command(command: String, data = null) -> Error:
|
||||
if not is_connected_to_host():
|
||||
return ERR_CONNECTION_ERROR
|
||||
|
||||
if data != null:
|
||||
_peer.put_data(("%s %s\n" % [command, data]).to_utf8_buffer())
|
||||
else:
|
||||
_peer.put_data((command + "\n").to_utf8_buffer())
|
||||
|
||||
return OK
|
||||
|
||||
func _handle_commands(command: String, data: String):
|
||||
if command == "set-oid":
|
||||
_oid = data
|
||||
on_oid.emit(oid)
|
||||
_logger.debug("Saved OID: %s", [oid])
|
||||
elif command == "set-pid":
|
||||
_pid = data
|
||||
on_pid.emit(pid)
|
||||
_logger.debug("Saved PID: %s", [pid])
|
||||
elif command == "connect":
|
||||
var parts = data.split(":")
|
||||
var host = parts[0]
|
||||
var port = parts[1].to_int()
|
||||
_logger.debug("Received connect command to %s:%s", [host, port])
|
||||
on_connect_nat.emit(host, port)
|
||||
elif command == "connect-relay":
|
||||
var host = _address
|
||||
var port = data.to_int()
|
||||
_logger.debug("Received connect relay command to %s:%s", [host, port])
|
||||
on_connect_relay.emit(host, port)
|
||||
else:
|
||||
_logger.trace("Received command %s %s", [command, data])
|
||||
Reference in New Issue
Block a user