38db2dbaaa1b76fa3018fe34de9a555817258e8a
[nit.git] / lib / gamnit / network / client.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Client-side network services for games and such
16 #
17 # The following code implements a client to connect to a local server and
18 # briefly exchange with it.
19 #
20 # ~~~
21 # redef fun handshake_app_name do return "nitwork_test"
22 # redef fun handshake_app_version do return "1.0"
23 #
24 # # Prepare connection with remote server
25 # var config = new RemoteServerConfig("localhost", 4444)
26 # var server = new RemoteServer(config)
27 #
28 # # Try to connect
29 # if not server.connect then return
30 #
31 # # Make sure the server is compatible
32 # if not server.handshake then return
33 #
34 # # Connection up! communicate
35 # server.writer.serialize "hello server"
36 # print server.reader.deserialize.as(Object)
37 #
38 # # Done, close socket
39 # server.socket.close
40 # ~~~
41 module client
42
43 import common
44
45 # Information of the remove server
46 class RemoteServerConfig
47
48 # Address of the remote server, either a domain name or an Internet address
49 var address: Text
50
51 # Listening port of the server
52 var port: Int
53 end
54
55 # Connection to a remote server
56 class RemoteServer
57
58 # `RemoteServerConfig` used to initiate connection to the server
59 var config: RemoteServerConfig
60
61 # Communication socket with the server
62 var socket: nullable TCPStream = null
63
64 # Is this connection connected?
65 fun connected: Bool do return socket != null and socket.connected == true
66
67 # `BinarySerializer` used to send data to this client through `socket`
68 var writer: BinarySerializer is noinit
69
70 # `BinaryDeserializer` used to receive data from this client through `socket`
71 var reader: BinaryDeserializer is noinit
72
73 # Attempt connection with the remote server
74 fun connect: Bool
75 do
76 print "Connecting to {config.address}:{config.port}..."
77 var socket = new TCPStream.connect(config.address.to_s, config.port)
78 self.socket = socket
79
80 if not socket.connected then
81 print "Connection failed: {socket.last_error or else "Internal error"}"
82 return false
83 end
84
85 # Setup serialization
86 writer = new BinarySerializer(socket)
87 writer.cache = new AsyncCache(false)
88 reader = new BinaryDeserializer(socket)
89 writer.link reader
90
91 return true
92 end
93
94 # Attempt handshake with server
95 #
96 # Validates compatibility between `handshake_app_name` and `handshake_app_version`.
97 #
98 # On error, close `socket`.
99 fun handshake: Bool
100 do
101 # The client goes first so that the server doesn't show its hand
102 var socket = socket
103 assert socket != null
104
105 # App name
106 var app_name = sys.handshake_app_name
107 socket.write_string app_name
108
109 var server_app = socket.read_string
110 if server_app != app_name then
111 print_error "Handshake Error: server app name is '{server_app}'"
112 socket.close
113 return false
114 end
115
116 # App version
117 socket.write_string sys.handshake_app_version
118
119 var server_version = socket.read_string
120 if server_version != sys.handshake_app_version then
121 print_error "Handshake Error: server version is different '{server_version}'"
122 socket.close
123 return false
124 end
125
126 return true
127 end
128 end