1 /*
2  * Copyright (c) 2017-2019 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-2019 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/selery/source/selery/hub/handler.d, selery/hub/handler.d)
28  */
29 module selery.hub.handler;
30 
31 import std.json : JSONValue;
32 import std.socket : SocketException;
33 import std..string : toLower, indexOf, strip, split, join;
34 
35 import sel.format : Format;
36 import sel.server.bedrock : BedrockServerImpl;
37 import sel.server.java : JavaServerImpl;
38 import sel.server.query : Query;
39 import sel.server.util : ServerInfo, GenericServer;
40 
41 import selery.about;
42 import selery.config : Config;
43 import selery.hub.hncom : HncomHandler, LiteNode;
44 import selery.hub.server : HubServer;
45 import selery.lang : Translation;
46 import selery.util.thread : SafeThread;
47 
48 /**
49  * Main handler with the purpose of starting children handlers,
50  * store constant informations and reload them when needed.
51  */
52 class Handler {
53 
54 	private shared HubServer server;
55 
56 	private shared JSONValue additionalJson;
57 	private shared string socialJson; // already encoded
58 
59 	public shared this(shared HubServer server, shared ServerInfo info, shared Query _query) {
60 
61 		this.server = server;
62 		
63 		this.regenerateSocialJson();
64 
65 		bool delegate(string ip) acceptIp; //TODO must be implemented by sel-server
66 		immutable forcedIp = server.config.hub.serverIp.toLower;
67 		if(forcedIp.length) {
68 			acceptIp = (string ip){ return ip.toLower == forcedIp; };
69 		} else {
70 			acceptIp = (string ip){ return true; };
71 		}
72 
73 		// start handlers
74 
75 		void startGenericServer(shared GenericServer gs, string name, const(Config.Hub.Address)[] addresses) {
76 			foreach(address ; addresses) {
77 				try {
78 					gs.start(address.ip, address.port, _query);
79 					debug server.logger.log(Translation("handler.listening", [Format.green ~ name ~ Format.reset, address.toString()]));
80 				} catch(SocketException e) {
81 					server.logger.logError(Translation("handler.error.bind", [name, address.toString(), (e.msg.indexOf(":")!=-1 ? e.msg.split(":")[$-1].strip : e.msg)]));
82 				} catch(Throwable t) {
83 					server.logger.logError(Translation("handler.error.address", [name, address.toString()]));
84 				}
85 			}
86 		}
87 
88 		with(server.config.hub) {
89 
90 			if(!server.lite) {
91 				auto s = new shared HncomHandler(server, &this.additionalJson);
92 				s.start(acceptedNodes, hncomPort);
93 			} else {
94 				new SafeThread(server.config.lang, { new shared LiteNode(server, &this.additionalJson); }).start();
95 			}
96 
97 			if(bedrock) {
98 				auto s = new shared BedrockServerImpl!supportedBedrockProtocols(info, server);
99 				startGenericServer(s, "bedrock", bedrock.addresses);
100 			}
101 
102 			if(java) {
103 				auto s = new shared JavaServerImpl!supportedJavaProtocols(info, server);
104 				startGenericServer(s, "java", java.addresses);
105 			}
106 
107 		}
108 
109 	}
110 
111 	/**
112 	 * Regenerates the social json adding a string field
113 	 * for each social field that is not empty in the settings.
114 	 */
115 	private shared void regenerateSocialJson() {
116 		const config = this.server.config;
117 		this.socialJson = config.hub.social.toString();
118 		JSONValue[string] additional;
119 		additional["social"] = config.hub.social;
120 		additional["minecraft"] = ["edu": config.hub.edu];
121 		additional["software"] = ["name": Software.name, "version": Software.displayVersion];
122 		this.additionalJson = cast(shared)JSONValue(additional);
123 	}
124 
125 	/**
126 	 * Closes the handlers and frees the resources.
127 	 */
128 	public shared void shutdown() {
129 		//TODO gracefully shutdown every thread
130 	}
131 
132 }
133 
134 deprecated("Server is never reloaded") interface Reloadable {
135 
136 	public shared void reload();
137 
138 }