Discover local servers responding on UDP discovery_port

Sends a message in the format gamnit::network? handshake_app_name and looks for the response gamnit::network! handshake_app_name port_number. Waits for timeout, or the default 0.1 seconds, after sending the message.

The server usually responds using the method answer_discovery_requests. When receiving responses, the client may then choose a server and connect via new RemoteServer.

var servers = discover_local_servers
if servers.not_empty then
    var server = new RemoteServer(servers.first)
    server.connect
    server.writer.serialize "hello server"
    server.socket.close
end

Property definitions

gamnit :: client $ Sys :: discover_local_servers
# Discover local servers responding on UDP `discovery_port`
#
# Sends a message in the format `gamnit::network? handshake_app_name` and
# looks for the response `gamnit::network! handshake_app_name port_number`.
# Waits for `timeout`, or the default 0.1 seconds, after sending the message.
#
# The server usually responds using the method `answer_discovery_requests`.
# When receiving responses, the client may then choose a server and
# connect via `new RemoteServer`.
#
# ~~~
# var servers = discover_local_servers
# if servers.not_empty then
#     var server = new RemoteServer(servers.first)
#     server.connect
#     server.writer.serialize "hello server"
#     server.socket.close
# end
# ~~~
fun discover_local_servers(timeout: nullable Float): Array[RemoteServerConfig]
do
	timeout = timeout or else 0.1

	var s = new UDPSocket
	s.enable_broadcast = true
	s.blocking = false
	s.broadcast(discovery_port, "{discovery_request_message} {handshake_app_name}")
	timeout.sleep

	var r = new Array[RemoteServerConfig]
	loop
		var ptr = new Ref[nullable SocketAddress](null)
		var resp = s.recv_from(1024, ptr)
		var src = ptr.item

		if resp.is_empty then
			# No response
			break
		else
			assert src != null
			var words = resp.split(" ")
			if words.length == 3 and words[0] == discovery_response_message and
			   words[1] == handshake_app_name and words[2].is_int then
				var address = src.address
				var port = words[2].to_i
				r.add new RemoteServerConfig(address, port)
			end
		end
	end
	return r
end
lib/gamnit/network/client.nit:134,1--184,3