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: 2017-2018 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/selery/source/selery/node/node.d, selery/node/node.d)
28  */
29 module selery.node.node;
30 
31 import std.algorithm : canFind;
32 
33 import selery.node.server : NodeServer;
34 import selery.player.player : Player;
35 
36 /**
37  * A node connected to the hub where players can be transferred to.
38  */
39 class Node {
40 
41 	public shared NodeServer server;
42 	
43 	/**
44 	 * Id of the node, given by the hub.
45 	 */
46 	public immutable uint hubId;
47 	
48 	/**
49 	 * Name of the node. It can only be one node with the same name
50 	 * online at the same time.
51 	 */
52 	public const string name;
53 	
54 	/**
55 	 * Indicates whether the can receive player when they first
56 	 * connect or only when they are transferred.
57 	 */
58 	public immutable bool main;
59 	
60 	/**
61 	 * Indicates which games and which protocols the node does accept.
62 	 * Example:
63 	 * ---
64 	 * auto pocket = PE in node.acceptedGames;
65 	 * if(pocket && (*pocket).canFind(100)) {
66 	 *    log(node.name, " supports MCPE 1.0");
67 	 * }
68 	 * ---
69 	 */
70 	uint[][ubyte] acceptedGames;
71 
72 	public this(shared NodeServer server, uint hubId, string name, bool main, uint[][ubyte] acceptedGames) {
73 		this.server = server;
74 		this.hubId = hubId;
75 		this.name = name;
76 		this.main = main;
77 		this.acceptedGames = acceptedGames;
78 	}
79 	
80 	/**
81 	 * Indicates whether or not the node is still connected to
82 	 * the hub.
83 	 * Example:
84 	 * ---
85 	 * auto node = server.nodeWithName("node");
86 	 * assert(node.online);
87 	 * ---
88 	 */
89 	public inout @property @safe bool online() {
90 		return this.server.nodeWithHubId(this.hubId) !is null;
91 	}
92 	
93 	/**
94 	 * Indicates whether the node can accept the given player.
95 	 * If a player is transferred to a node that cannot accept it
96 	 * it is kicked with the "End of Stream" message by the hub.
97 	 */
98 	public inout @safe bool accepts(Player player) {
99 		auto a = player.gameId in this.acceptedGames;
100 		return a && (*a).canFind(player.protocol);
101 	}
102 
103 	/**
104 	 * Sends a message to the node.
105 	 * Example:
106 	 * ---
107 	 * // if the other node uses the same JSON protocol
108 	 * node.sendMessage(`{"reply_with":12}`);
109 	 * server += (NodeMessageEvent event) {
110 	 *    if(node == event.node) {
111 	 *       assert(parseJSON(cast(string)event.payload)["reply"].integer == 12);
112 	 *    }
113 	 * }
114 	 * ---
115 	 */
116 	public void sendMessage(ubyte[] payload) {
117 		this.server.sendMessage(this, payload);
118 	}
119 
120 	/// ditto
121 	public void sendMessage(string message) {
122 		this.sendMessage(cast(ubyte[])message);
123 	}
124 
125 	public override bool opEquals(Object o) {
126 		auto node = cast(Node)o;
127 		return node !is null && node.hubId == this.hubId;
128 	}
129 	
130 }