1 /**
2 Copyright: Copyright (c) 2014-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module netlib.baseserver;
8 
9 import std.range;
10 
11 import voxelman.log;
12 import cbor;
13 import derelict.enet.enet;
14 import netlib;
15 
16 struct PeerStorage
17 {
18 	ENetPeer*[SessionId] peers;
19 	private SessionId _nextSessionId = 0;
20 
21 	ENetPeer* opIndex(SessionId id)
22 	{
23 		return peers.get(id, null);
24 	}
25 
26 	SessionId addClient(ENetPeer* peer)
27 	{
28 		SessionId id = nextPeerId;
29 		peers[id] = peer;
30 		return id;
31 	}
32 
33 	void removeClient(SessionId id)
34 	{
35 		peers.remove(id);
36 	}
37 
38 	size_t length()
39 	{
40 		return peers.length;
41 	}
42 
43 	private SessionId nextPeerId() @property
44 	{
45 		return _nextSessionId++;
46 	}
47 }
48 
49 struct ConnectionSettings
50 {
51 	ENetAddress* address;
52 	size_t maxPeers;
53 	size_t numChannels;
54 	uint incomingBandwidth;
55 	uint outgoingBandwidth;
56 }
57 
58 abstract class BaseServer
59 {
60 	PeerStorage peerStorage;
61 	mixin PacketManagement!(false);
62 	mixin BaseConnection!();
63 
64 	void start(ConnectionSettings settings, uint hostAddr, ushort port)
65 	{
66 		ENetAddress address;
67 		address.host = hostAddr;
68 		address.port = port;
69 		settings.address = &address;
70 
71 		if (isRunning) stop();
72 
73 		host = enet_host_create(settings.address,
74 			settings.maxPeers,
75 			settings.numChannels,
76 			settings.incomingBandwidth,
77 			settings.outgoingBandwidth);
78 
79 		if (host is null)
80 		{
81 			error("An error occured while trying to create an ENet host");
82 			return;
83 		}
84 
85 		isRunning = true;
86 	}
87 
88 	void update()
89 	{
90 		if (!isRunning) return;
91 		ENetEvent event;
92 		while (enet_host_service(host, &event, 0) > 0)
93 		{
94 			final switch (event.type)
95 			{
96 				case ENET_EVENT_TYPE_NONE:
97 					break;
98 				case ENET_EVENT_TYPE_CONNECT:
99 					onConnect(event);
100 					break;
101 				case ENET_EVENT_TYPE_RECEIVE:
102 					onPacketReceived(event);
103 					break;
104 				case ENET_EVENT_TYPE_DISCONNECT:
105 					onDisconnect(event);
106 					break;
107 			}
108 		}
109 	}
110 
111 	/// Disconnects all clients.
112 	void disconnectAll()
113 	{
114 		if (!isRunning) return;
115 		foreach(peer; peerStorage.peers.byValue)
116 		{
117 			enet_peer_disconnect(peer, 0);
118 		}
119 	}
120 
121 	/// Sends packet to specified clients.
122 	void sendTo(R)(R clients, ubyte[] data, ubyte channel = 0)
123 		if ((isInputRange!R && is(ElementType!R : SessionId)) ||
124 			is(R : SessionId))
125 	{
126 		if (!isRunning) return;
127 		ENetPacket* packet = enet_packet_create(data.ptr, data.length,
128 				ENET_PACKET_FLAG_RELIABLE);
129 		sendTo(clients, packet, channel);
130 	}
131 
132 	/// ditto
133 	void sendTo(R, P)(R clients, auto ref const(P) packet, ubyte channel = 0)
134 		if (((isInputRange!R && is(ElementType!R : SessionId)) ||
135 			is(R : SessionId)) &&
136 			is(P == struct))
137 	{
138 		sendTo(clients, createPacket(packet), channel);
139 	}
140 
141 	/// ditto
142 	void sendTo(R)(R clients, ENetPacket* packet, ubyte channel = 0)
143 		if ((isInputRange!R && is(ElementType!R : SessionId)) ||
144 			is(R : SessionId))
145 	{
146 		if (!isRunning) return;
147 		static if (isInputRange!R)
148 		{
149 			foreach(sessionId; clients)
150 			{
151 				if (auto peer = peerStorage[sessionId])
152 					enet_peer_send(peer, channel, packet);
153 			}
154 		}
155 		else // single SessionId
156 		{
157 			if (auto peer = peerStorage[clients])
158 				enet_peer_send(peer, channel, packet);
159 		}
160 	}
161 
162 	/// Sends packet to all clients.
163 	void sendToAll(P)(auto ref P packet, ubyte channel = 0)
164 		if (is(P == struct))
165 	{
166 		sendToAll(createPacket(packet), channel);
167 	}
168 
169 	/// ditto
170 	void sendToAll(ubyte[] data, ubyte channel = 0)
171 	{
172 		if (!isRunning) return;
173 		ENetPacket* packet = enet_packet_create(data.ptr, data.length,
174 					ENET_PACKET_FLAG_RELIABLE);
175 		sendToAll(packet, channel);
176 	}
177 
178 	/// ditto
179 	void sendToAll(ENetPacket* packet, ubyte channel = 0)
180 	{
181 		if (!isRunning) return;
182 		enet_host_broadcast(host, channel, packet);
183 	}
184 
185 	/// Sends packet to all clients except one.
186 	void sendToAllExcept(P)(SessionId exceptClient, auto ref const(P) packet, ubyte channel = 0)
187 		if (is(P == struct))
188 	{
189 		sendToAllExcept(exceptClient, createPacket(packet), channel);
190 	}
191 
192 	/// ditto
193 	void sendToAllExcept(SessionId exceptClient, ubyte[] data, ubyte channel = 0)
194 	{
195 		if (!isRunning) return;
196 		ENetPacket* packet = enet_packet_create(data.ptr, data.length,
197 					ENET_PACKET_FLAG_RELIABLE);
198 		sendToAllExcept(exceptClient, packet, channel);
199 	}
200 
201 	/// ditto
202 	void sendToAllExcept(SessionId exceptClient, ENetPacket* packet, ubyte channel = 0)
203 	{
204 		if (!isRunning) return;
205 		foreach(sessionId, peer; peerStorage.peers)
206 		{
207 			if (sessionId != exceptClient && peer)
208 				enet_peer_send(peer, channel, packet);
209 		}
210 	}
211 }