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 }