1 /*
2  * Copyright (c) 2017 SEL
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU Lesser General Public License for more details.
13  * 
14  */
15 module sel.hncom.login;
16 
17 import std.json : JSONValue;
18 import std.typecons : Tuple;
19 
20 import sel.hncom.about;
21 import sel.hncom.io : IO;
22 
23 /**
24  * First packet sent by the client after the connection is established.
25  * It contains informations used by the hub to check permissions and compatibility.
26  */
27 @serverbound struct ConnectionRequest {
28 
29 	enum ubyte ID = 1;
30 
31 	/**
32 	 * Password, if the hub requires one, or an empty string.
33 	 */
34 	string password;
35 
36 	/**
37 	 * Name of the node that will be validated by the hub. It should always be
38 	 * lowercase and only contain letters, numbers, dashes and underscores.
39 	 */
40 	string name;
41 
42 	/**
43 	 * Indicates whether the node accepts clients when they first connect to the
44 	 * hub or exclusively when they are transferred.
45 	 */
46 	bool main = true;
47 
48 	/**
49 	 * Version of the protocol used by the client that must match the hub's one.
50 	 */
51 	uint protocol = __PROTOCOL__;
52 
53 	mixin IO!(password, name, main, protocol);
54 
55 }
56 
57 /**
58  * Reply to ConnectionRequest sent only when the node's ip is accepted by the hub.
59  * It contains the connection status (accepted or an error code) and the hub's protocol.
60  */
61 @clientbound struct ConnectionResponse {
62 
63 	enum ubyte ID = 2;
64 
65 	enum : ubyte {
66 
67 		OK,
68 		OUTDATED_HUB,				/// The hub uses an old version of hncom
69 		OUTDATED_NODE,				/// The node uses an old version of hncom
70 		PASSWORD_REQUIRED,			/// A password is required to connect
71 		WRONG_PASSWORD,				/// The password doesn't match the hub's one
72 		INVALID_NAME_LENGTH,		/// The name is too short or too long
73 		INVALID_NAME_CHARACTERS,	/// The name contains invalid characters
74 		NAME_ALREADY_USED,			/// There's already a node connected with the same name
75 		NAME_RESERVED,				/// The name cannot be used because the hub has reserved it for something else
76 		BLOCKED_BY_PLUGIN,			/// A plugin has blocked the node from connecting
77 
78 	}
79 
80 	/**
81 	 * Indicates the status of connection. If not 0, it indicates an error.
82 	 */
83 	ubyte status;
84 
85 	/**
86 	 * Indicates the version of the protocol used by the hub when the status
87 	 * code indicates that the hub or the node is obsolete.
88 	 */
89 	uint protocol = __PROTOCOL__;
90 
91 	mixin IO!(status, protocol);
92 
93 }
94 
95 /**
96  * Hub's informations.
97  */
98 @clientbound struct HubInfo {
99 
100 	enum ubyte ID = 3;
101 
102 	enum int UNLIMITED = -1;
103 	
104 	alias GameInfo = Tuple!(string, "motd", uint[], "protocols", bool, "onlineMode", ushort, "port");
105 
106 	/**
107 	 * Server's id, either given by a snoop system or randomly generated at runtime.
108 	 */
109 	ulong serverId;
110 
111 	/**
112 	 * First number of the 4,294,967,296 (2^32) reserved by the hub to create the node's UUIDs.
113 	 * Every UUID generated by the node is formed by the server's id (most signicant)
114 	 * and the next reserved uuid (least significant). This way every UUID in the hub
115 	 * and in the connected nodes is always different.
116 	 */
117 	ulong reservedUUIDs;
118 
119 	/**
120 	 * Unformatted name of the server as indicated in the hub's configuration file.
121 	 */
122 	string displayName;
123 
124 	/**
125 	 * Informations about the games supported by the hub.
126 	 */
127 	GameInfo[ubyte] gamesInfo;
128 
129 	/**
130 	 * Number of players currently online and connected to other nodes.
131 	 */
132 	uint online;
133 
134 	/**
135 	 * Number of maximum players that can connect to the server (that is the sum
136 	 * of the max players of the nodes already connected).
137 	 * The number may change after the current node connects.
138 	 */
139 	int max;
140 
141 	/**
142 	 * Default server's language in format (language_COUNTRY, e.g. en_GB) and also the
143 	 * default language for players that don't specify their language or for the ones
144 	 * which language is not supported by the server.
145 	 */
146 	string language;
147 
148 	/**
149 	 * Languages accepted by the server in the same format as language.
150 	 * The list should always contain at least one element (the default language).
151 	 */
152 	string[] acceptedLanguages;
153 
154 	/**
155 	 * Optional informations about the server's software, social accounts, system and options.
156 	 * Example:
157 	 * ---
158 	 * {
159 	 *   "software": {
160 	 *      "name": "selery",
161 	 *      "version": "0.0.1",
162 	 *      "stable": true
163 	 *   },
164 	 *   "minecraft": {
165 	 *      "edu": false,
166 	 *      "realm": true
167 	 *   },
168 	 *   "social": {
169 	 *      "website": "example.com",
170 	 *      "facebook": "example-official",
171 	 *      "twitter": "example_tweets",
172 	 *      "youtube": "examplechannel",
173 	 *      "instagram": "example",
174 	 *      "google-plus": "example-plus"
175 	 *   },
176 	 *   "system": {
177 	 *      "os": "Ubuntu 16.04",
178 	 *      "cpu": "Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz",
179 	 *      "cores": 2,
180 	 *      "ram": 2147483648
181 	 *   }
182 	 * }
183 	 * ---
184 	 */
185 	JSONValue additionalJSON;
186 
187 	mixin IO!(serverId, reservedUUIDs, displayName, gamesInfo, online, max, language, acceptedLanguages, additionalJSON);
188 
189 }
190 
191 /**
192  * Node's informations.
193  */
194 @serverbound struct NodeInfo {
195 
196 	enum ubyte ID = 4;
197 
198 	enum uint UNLIMITED = 0;
199 
200 	alias Plugin = Tuple!(string, "name", string, "version_");
201 
202 	/**
203 	 * Informations about the games accepted by the node. There should be at least
204 	 * one combination of game/protocols that is also accepted by hub as indicated
205 	 * in HubInfo.gamesInfo, otherwise the node will never receive any player.
206 	 */
207 	uint[][ubyte] acceptedGames;
208 	
209 	/**
210 	 * Maximum number of players accepted by node.
211 	 */
212 	uint max;
213 
214 	/**
215 	 * List of plugins loaded on the node for creating queries on the hub.
216 	 */
217 	Plugin[] plugins;
218 
219 	/**
220 	 * Optional informations about the server's software and system,
221 	 * similar to HubInfo's additionalJson field.
222 	 * Example:
223 	 * ---
224 	 * {
225 	 *   "software": {
226 	 *      "name": "selery",
227 	 *      "version": "0.0.1",
228 	 *      "stable": true
229 	 *   },
230 	 *   "system": {
231 	 *      "os": "Windows 10",
232 	 *      "cpu": "Intel(R) Core(TM) i7-5700U CPU @ 3.40GHz",
233 	 *      "cores": 4,
234 	 *      "ram": 8589934592
235 	 *   }
236 	 * }
237 	 * ---
238 	 */
239 	JSONValue additionalJSON;
240 
241 	mixin IO!(acceptedGames, max, plugins, additionalJSON);
242 
243 }