gamnit: move up UDP discovery logic from Tinks! to the lib
[nit.git] / lib / gamnit / network / client.nit
index 38db2db..8aad96f 100644 (file)
@@ -40,7 +40,7 @@
 # ~~~
 module client
 
-import common
+intrude import common
 
 # Information of the remove server
 class RemoteServerConfig
@@ -126,3 +126,55 @@ class RemoteServer
                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