1 /*
2  * Copyright (c) 2017-2018 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: Copyright (c) 2017-2018 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/sel-hncom/sel/hncom/login.d, sel/hncom/login.d)
28  */
29 module sel.hncom.login;
30 
31 import std.json : JSONValue;
32 import std.typecons : Tuple;
33 
34 import sel.hncom.about;
35 import sel.hncom.io : IO;
36 
37 /**
38  * First packet sent by the client after the connection is established.
39  * It contains informations used by the hub to check permissions and compatibility.
40  */
41 @serverbound struct ConnectionRequest {
42 
43 	enum ubyte ID = 1;
44 	
45 	/**
46 	 * Name of the node that will be validated by the hub. It should always be
47 	 * lowercase and only contain letters, numbers, dashes and underscores.
48 	 */
49 	string name;
50 
51 	/**
52 	 * Password, if the hub requires one, or an empty string.
53 	 */
54 	string password;
55 
56 	/**
57 	 * Indicates whether the node accepts clients when they first connect to the
58 	 * hub or exclusively when they are transferred.
59 	 */
60 	bool main = true;
61 
62 	/**
63 	 * Version of the protocol used by the client that must match the hub's one.
64 	 */
65 	uint protocol = __PROTOCOL__;
66 
67 	mixin IO!(password, name, main, protocol);
68 
69 }
70 
71 /**
72  * Reply to ConnectionRequest sent only when the node's ip is accepted by the hub.
73  * It contains the connection status (accepted or an error code) and the hub's protocol.
74  */
75 @clientbound struct ConnectionResponse {
76 
77 	enum ubyte ID = 2;
78 
79 	enum : ubyte {
80 
81 		OK,
82 		OUTDATED_HUB,				/// The hub uses an old version of hncom
83 		OUTDATED_NODE,				/// The node uses an old version of hncom
84 		PASSWORD_REQUIRED,			/// A password is required to connect
85 		WRONG_PASSWORD,				/// The password doesn't match the hub's one
86 		INVALID_NAME_LENGTH,		/// The name is too short or too long
87 		INVALID_NAME_CHARACTERS,	/// The name contains invalid characters
88 		NAME_ALREADY_USED,			/// There's already a node connected with the same name
89 		NAME_RESERVED,				/// The name cannot be used because the hub has reserved it for something else
90 		BLOCKED_BY_PLUGIN,			/// A plugin has blocked the node from connecting
91 
92 	}
93 
94 	/**
95 	 * Indicates the status of connection. If not 0, it indicates an error.
96 	 */
97 	ubyte status;
98 
99 	/**
100 	 * Indicates the version of the protocol used by the hub when the status
101 	 * code indicates that the hub or the node is obsolete.
102 	 */
103 	uint protocol = __PROTOCOL__;
104 
105 	mixin IO!(status, protocol);
106 
107 }
108 
109 /**
110  * Hub's informations.
111  */
112 @clientbound struct HubInfo {
113 
114 	enum ubyte ID = 3;
115 
116 	enum int UNLIMITED = -1;
117 	
118 	alias GameInfo = Tuple!(string, "motd", uint[], "protocols", bool, "onlineMode", ushort, "port");
119 
120 	/**
121 	 * Server's id, either given by a snoop system or randomly generated at runtime.
122 	 */
123 	ulong serverId;
124 
125 	/**
126 	 * First number of the 4,294,967,296 (2^32) reserved by the hub to create the node's UUIDs.
127 	 * Every UUID generated by the node is formed by the server's id (most signicant)
128 	 * and the next reserved uuid (least significant). This way every UUID in the hub
129 	 * and in the connected nodes is always different.
130 	 */
131 	ulong reservedUUIDs;
132 
133 	/**
134 	 * Unformatted name of the server as indicated in the hub's configuration file.
135 	 */
136 	string displayName;
137 
138 	/**
139 	 * Informations about the games supported by the hub.
140 	 */
141 	GameInfo[ubyte] gamesInfo;
142 
143 	/**
144 	 * Number of players currently online and connected to other nodes.
145 	 */
146 	uint online;
147 
148 	/**
149 	 * Number of maximum players that can connect to the server (that is the sum
150 	 * of the max players of the nodes already connected).
151 	 * The number may change after the current node connects.
152 	 */
153 	int max;
154 
155 	/**
156 	 * Languages accepted by the server in format ISO 639.1 (language code) underscore
157 	 * ISO 3166 (country code), e.g. en_US.
158 	 * The list must contain at least one element.
159 	 */
160 	string[] acceptedLanguages;
161 
162 	/**
163 	 * Indicates whether the web admin protocol is active on the hub. If it is the
164 	 * node should send the port where it will listen for connections in its info packet.
165 	 */
166 	bool webAdmin;
167 
168 	/**
169 	 * Optional informations about the server's software, social accounts, system and options.
170 	 * Example:
171 	 * ---
172 	 * {
173 	 *   "software": {
174 	 *      "name": "Selery",
175 	 *      "version": "0.1.0",
176 	 *      "stable": true
177 	 *   },
178 	 *   "minecraft": {
179 	 *      "edu": false,
180 	 *      "realm": true
181 	 *   },
182 	 *   "social": {
183 	 *      "website": "example.com",
184 	 *      "facebook": "example-official",
185 	 *      "twitter": "example_tweets",
186 	 *      "youtube": "examplechannel",
187 	 *      "instagram": "example",
188 	 *      "google-plus": "example-plus"
189 	 *   },
190 	 *   "system": {
191 	 *      "os": "Ubuntu 16.04",
192 	 *      "cpu": "Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz",
193 	 *      "cores": 2,
194 	 *      "ram": 2147483648
195 	 *   }
196 	 * }
197 	 * ---
198 	 */
199 	JSONValue additionalJSON;
200 
201 	mixin IO!(serverId, reservedUUIDs, displayName, gamesInfo, online, max, acceptedLanguages, webAdmin, additionalJSON);
202 
203 }
204 
205 /**
206  * Node's informations.
207  */
208 @serverbound struct NodeInfo {
209 
210 	enum ubyte ID = 4;
211 
212 	enum uint UNLIMITED = 0;
213 
214 	alias Plugin = Tuple!(uint, "id", string, "name", string, "version_");
215 
216 	/**
217 	 * Informations about the games accepted by the node. There should be at least
218 	 * one combination of game/protocols that is also accepted by hub as indicated
219 	 * in HubInfo.gamesInfo, otherwise the node will never receive any player.
220 	 */
221 	uint[][ubyte] acceptedGames;
222 	
223 	/**
224 	 * Maximum number of players accepted by node.
225 	 */
226 	uint max;
227 
228 	/**
229 	 * List of plugins currently loaded on the node.
230 	 * This field is used only for information purposes (as displaying the
231 	 * plugins in the querying protocol).
232 	 */
233 	Plugin[] plugins;
234 
235 	/**
236 	 * Port where the node is listening for connections, if the web admin protocol
237 	 * is active on the hub.
238 	 */
239 	ushort webAdminPort;
240 
241 	/**
242 	 * Optional informations about the server's software and system,
243 	 * similar to HubInfo's additionalJson field.
244 	 * Example:
245 	 * ---
246 	 * {
247 	 *   "software": {
248 	 *      "name": "Selery",
249 	 *      "version": "0.1.0",
250 	 *      "stable": true
251 	 *   },
252 	 *   "system": {
253 	 *      "os": "Windows 10",
254 	 *      "cpu": "Intel(R) Core(TM) i7-5700U CPU @ 3.40GHz",
255 	 *      "cores": 4,
256 	 *      "ram": 8589934592
257 	 *   }
258 	 * }
259 	 * ---
260 	 */
261 	JSONValue additionalJSON;
262 
263 	mixin IO!(acceptedGames, max, plugins, webAdminPort, additionalJSON);
264 
265 }