1 /*
2  * Copyright (c) 2017-2020 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: 2017-2020 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/sel-client/sel/client/client.d, sel/client/client.d)
28  */
29 module sel.client.client;
30 
31 import std.conv : to;
32 import std.datetime : Duration, dur;
33 import std.socket : Address, InternetAddress;
34 
35 import sel.client.util : Server, IHandler;
36 import sel.net : Stream;
37 
38 enum isSupported(string type, uint protocol) = __traits(compiles, { mixin("import sul.attributes." ~ type ~ to!string(protocol) ~ ";"); });
39 
40 class Client {
41 
42 	/**
43 	 * Client's username used to connect to the server.
44 	 */
45 	public immutable string name;
46 
47 	public this(string name) {
48 		this.name = name;
49 	}
50 
51 	/**
52 	 * Gets the game's default port.
53 	 */
54 	public abstract pure nothrow @property @safe @nogc ushort defaultPort();
55 
56 	/**
57 	 * Pings a server to retrieve basic informations like MOTD, protocol used
58 	 * and online players.
59 	 * Returns: a Server struct with the server's informations or an empty one on failure
60 	 * Example:
61 	 * ---
62 	 * client.ping("127.0.0.1");
63 	 * client.ping("mc.hypixel.net", 25565);
64 	 * client.ping("localhost", dur!"seconds"(1));
65 	 * ---
66 	 */
67 	public final const(Server) ping(Address address, Duration timeout=dur!"seconds"(5)) {
68 		return this.pingImpl(address, address.toAddrString(), to!ushort(address.toPortString()), timeout);
69 	}
70 
71 	/// ditto
72 	public final const(Server) ping(string ip, ushort port, Duration timeout=dur!"seconds"(5)) {
73 		return this.pingImpl(new InternetAddress(ip, port), ip, port, timeout);
74 	}
75 
76 	/// ditto
77 	public final const(Server) ping(string ip, Duration timeout=dur!"seconds"(5)) {
78 		return this.ping(ip, this.defaultPort, timeout);
79 	}
80 
81 	protected abstract Server pingImpl(Address address, string ip, ushort port, Duration timeout);
82 
83 	/**
84 	 * Pings a server and returns the obtained data without parsing it.
85 	 * Example:
86 	 * ---
87 	 * assert(minecraft.rawPing("play.lbsg.net").startsWith("MCPE;"));
88 	 * assert(java.rawPing("mc.hypixel.net").startsWith("{")); // json
89 	 * ---
90 	 */
91 	public final string rawPing(Address address, Duration timeout=dur!"seconds"(5)) {
92 		return this.rawPingImpl(address, address.toAddrString(), to!ushort(address.toPortString()), timeout);
93 	}
94 	
95 	/// ditto
96 	public final string rawPing(string ip, ushort port, Duration timeout=dur!"seconds"(5)) {
97 		return this.rawPingImpl(new InternetAddress(ip, port), ip, port, timeout);
98 	}
99 	
100 	/// ditto
101 	public final string rawPing(string ip, Duration timeout=dur!"seconds"(5)) {
102 		return this.rawPing(ip, this.defaultPort, timeout);
103 	}
104 
105 	protected abstract string rawPingImpl(Address address, string ip, ushort port, Duration timeout);
106 
107 	public Stream connect(Address address, IHandler handler, Duration timeout=dur!"seconds"(5)) {
108 		return this.connectImpl(address, address.toAddrString(), to!ushort(address.toPortString()), timeout, handler);
109 	}
110 
111 	public Stream connect(string ip, ushort port, IHandler handler, Duration timeout=dur!"seconds"(5)) {
112 		return this.connectImpl(new InternetAddress(ip, port), ip, port, timeout, handler);
113 	}
114 
115 	public Stream connect(string ip, IHandler handler, Duration timeout=dur!"seconds"(5)) {
116 		return this.connect(ip, this.defaultPort, handler, timeout);
117 	}
118 
119 	protected abstract Stream connectImpl(Address address, string ip, ushort port, Duration timeout, IHandler hanlder);
120 
121 }