1 module server;
2 
3 import std.stdio;
4 import std.range;
5 
6 import derelict.enet.enet;
7 
8 import connection;
9 import packets;
10 
11 
12 struct ServerSettings
13 {
14 	ushort port;
15 	size_t maxClients;
16 	size_t numChannels;
17 	uint incomingBandwidth;
18 	uint outgoingBandwidth;
19 }
20 
21 struct User
22 {
23 	string name;
24 	ENetPeer* peer;
25 }
26 
27 struct UserStorage
28 {
29 	private User*[UserId] users;
30 
31 	UserId addUser(ENetPeer* peer)
32 	{
33 		UserId id = nextPeerId;
34 		User* user = new User;
35 		user.peer = peer;
36 		users[id] = user;
37 		return id;
38 	}
39 
40 	void removeUser(UserId id)
41 	{
42 		users.remove(id);
43 	}
44 
45 	User* findUser(UserId id)
46 	{
47 		return users.get(id, null);
48 	}
49 
50 	UserId nextPeerId() @property
51 	{
52 		return _nextPeerId++;
53 	}
54 
55 	string[UserId] userNames()
56 	{
57 		string[UserId] names;
58 		foreach(id, user; users)
59 		{
60 			names[id] = user.name;
61 		}
62 
63 		return names;
64 	}
65 
66 	string userName(UserId id)
67 	{
68 		return users[id].name;
69 	}
70 
71 	ENetPeer* userPeer(UserId id)
72 	{
73 		return users[id].peer;
74 	}
75 
76 	size_t length()
77 	{
78 		return users.length;
79 	}
80 
81 	private UserId _nextPeerId = 1;
82 }
83 
84 class Server : Connection
85 {
86 	bool isRunning;
87 
88 	ENetAddress address;
89 	ServerSettings settings;
90 
91 	UserStorage userStorage;
92 
93 	void start(ServerSettings _settings)
94 	{
95 		side = "Server";
96 
97 		registerPacket!LoginPacket(&handleLoginPacket);
98 		registerPacket!SessionInfoPacket;
99 		registerPacket!UserLoggedInPacket;
100 		registerPacket!UserLoggedOutPacket;
101 		registerPacket!MessagePacket(&handleMessagePacket);
102 
103 		printPacketMap();
104 
105 		settings = _settings;
106 
107 		address.host = ENET_HOST_ANY;
108 		address.port = settings.port;
109 
110 		host = enet_host_create(&address,
111 			settings.maxClients,
112 			settings.numChannels,
113 			settings.incomingBandwidth,
114 			settings.outgoingBandwidth);
115 
116 		if (host is null)
117 		{
118 			writeln("Server: An error occured while trying to create an ENet server host");
119 			return;
120 		}
121 
122 		isRunning = true;
123 	}
124 
125 	void sendMessageTo(UserId userId, string message)
126 	{
127 		sendTo(only(userId), createPacket(MessagePacket(0, message)));
128 	}
129 
130 	void handleCommand(string command, UserId userId)
131 	{
132 		import std.algorithm : splitter;
133 		import std.string : format;
134 		writefln("Server: %s Command> %s", userStorage.userName(userId), command);
135 		
136 		if (command.length <= 1)
137 		{
138 			sendMessageTo(userId, "Invalid command");
139 			return;
140 		}
141 
142 		// Split without leading '/'
143 		auto splitted = command[1..$].splitter;
144 		string commName = splitted.front;
145 		splitted.popFront;
146 
147 		if (commName == "stop")
148 			isRunning = false;
149 		else
150 			sendMessageTo(userId, format("Unknown command %s", commName));
151 	}
152 
153 	override void stop()
154 	{
155 		super.stop();
156 		writefln("Server: Stopped");
157 	}
158 
159 	/// Sending
160 	void sendTo(R)(R users, ubyte[] data, ubyte channel = 0)
161 		if (isInputRange!R && is(ElementType!R == UserId))
162 	{
163 		ENetPacket *packet = enet_packet_create(data.ptr, data.length,
164 				ENET_PACKET_FLAG_RELIABLE);
165 		sendTo(users, packet, channel);
166 	}
167 
168 	/// ditto
169 	void sendTo(R)(R users, ENetPacket* packet, ubyte channel = 0)
170 		if (isInputRange!R && is(ElementType!R == UserId))
171 	{
172 		foreach(userId; users)
173 		{
174 			enet_peer_send(userStorage.userPeer(userId), channel, packet);
175 		}
176 	}
177 
178 	/// ditto
179 	void sendToAll(ubyte[] data, ubyte channel = 0)
180 	{
181 		ENetPacket *packet = enet_packet_create(data.ptr, data.length,
182 					ENET_PACKET_FLAG_RELIABLE);
183 		sendToAll(packet, channel);
184 	}
185 
186 	/// ditto
187 	void sendToAll(ENetPacket* packet, ubyte channel = 0)
188 	{
189 		enet_host_broadcast(host, channel, packet);
190 	}
191 
192 	//-------------------------------------------------------------------------
193 	// Handlers
194 
195 	override void onConnect(ref ENetEvent event)
196 	{
197 		writefln("Server: A new client connected from %(%s.%):%s", 
198 			*cast(ubyte[4]*)(&event.peer.address.host),
199 			event.peer.address.port);
200 
201 		event.peer.data = cast(void*)userStorage.addUser(event.peer);
202 		enet_peer_timeout(event.peer, 0, 0, 2000);
203 	}
204 
205 	void handleLoginPacket(ubyte[] packetData, UserId userId)
206 	{
207 		LoginPacket packet = unpackPacket!LoginPacket(packetData);
208 		
209 		userStorage.findUser(userId).name = packet.userName;
210 		writefln("Server: %s logged in", packet.userName);
211 		
212 		sendTo(only(userId), createPacket(SessionInfoPacket(userId, userStorage.userNames)));
213 		sendToAll(createPacket(UserLoggedInPacket(userId, packet.userName)));
214 	}
215 
216 	void handleMessagePacket(ubyte[] packetData, UserId userId)
217 	{
218 		import std.algorithm : startsWith;
219 		import std.string : strip;
220 
221 		MessagePacket packet = unpackPacket!MessagePacket(packetData);
222 			
223 		packet.userId = userId;
224 		string strippedMsg = packet.msg.strip;
225 		
226 		if (strippedMsg.startsWith("/"))
227 		{
228 			handleCommand(strippedMsg, userId);
229 			return;
230 		}
231 
232 		writefln("Server: %s> %s", userStorage.userName(userId), packet.msg);
233 		
234 		sendToAll(createPacket(packet));
235 	}
236 
237 	override void onDisconnect(ref ENetEvent event)
238 	{
239 		UserId userId = cast(UserId)event.peer.data;
240 		
241 		writefln("Server: %s disconnected", userStorage.userName(userId));
242 		
243 		userStorage.removeUser(userId);
244 
245 		sendToAll(createPacket(UserLoggedOutPacket(userId)));
246 
247 		// Reset client's information
248 		event.peer.data = null;
249 
250 		if (userStorage.length == 0)
251 			isRunning = false;
252 	}
253 }