# ~~~
module client
-import common
+intrude import common
# Information of the remove server
class RemoteServerConfig
return true
end
end
+
+# 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