1 module server.server;
2 
3 import utils.debugging : debugPrint;
4 import std.conv : to;
5 import std.socket : Socket, AddressFamily, SocketType, ProtocolType, parseAddress, SocketFlags, Address;
6 import core.thread : Thread;
7 import std.stdio : writeln, File;
8 import std.json : JSONValue, parseJSON, JSONException, JSONType, toJSON;
9 import std.string : cmp;
10 import handlers.handler;
11 import listeners.listener;
12 import connection.connection;
13 
14 public final class BesterServer
15 {
16 	/**
17 	* Message handlers
18 	*
19 	* Associative array of `payloadType (string)`:`MessageHandler`
20 	* TODO: Implement this
21 	*/
22 	public MessageHandler[] handlers;
23 
24 	/* The server's socket */
25 	private Socket serverSocket;
26 	/* TODO: The above to be replaced */
27 
28 	/* Socket listeners for incoming connections */
29 	private BesterListener[] listeners;
30 
31 	/* Connected clients */
32 	public BesterConnection[] clients;
33 
34 	public BesterConnection[] getClients(string[] usernames)
35 	{
36 		/* List of authenticated users matching `usernames` */
37 		BesterConnection[] matchedUsers;
38 
39 		/* Search through the provided usernames */
40 		for(ulong i = 0; i < usernames.length; i++)
41 		{
42 			for(ulong k = 0; k < clients.length; k++)
43 			{
44 				/* The potentially-matched user */
45 				BesterConnection potentialMatch = clients[k];
46 				
47 				/* Check if the user is authenticated */
48 				if(potentialMatch.getType() == BesterConnection.Scope.CLIENT && cmp(potentialMatch.getCredentials()[0], usernames[i]))
49 				{
50 					matchedUsers ~= potentialMatch;
51 				}	
52 			}
53 		}
54 
55 		return matchedUsers;
56 	}
57 
58 	public void addListener(BesterListener listener)
59 	{
60 		this.listeners ~= listener;
61 	}
62 
63 	this(JSONValue config)
64 	{
65 		/* TODO: Bounds check and JSON type check */
66 		//debugPrint("Setting up socket...");
67 		//setupServerSocket(config["network"]);
68 
69 		/* TODO: Bounds check and JSON type check */
70 		debugPrint("Setting up message handlers...");
71 		setupHandlers(config["handlers"]);
72 	}
73 
74 	private void setupHandlers(JSONValue handlerBlock)
75 	{
76 		/* TODO: Implement me */
77 		debugPrint("Constructing message handlers...");
78 		handlers = MessageHandler.constructHandlers(handlerBlock);
79 		writeln(handlers[0].getPluginName());
80 	}
81 
82 	/* Setup the server socket */
83 	private void setupServerSocket(JSONValue networkBlock)
84 	{
85 		string bindAddress;
86 		ushort listenPort;
87 		
88 		JSONValue jsonAddress, jsonPort;
89 
90 		writeln(networkBlock);
91 
92 		/* TODO: Bounds check */
93 		jsonAddress = networkBlock["address"];
94 		jsonPort = networkBlock["port"];
95 
96 		bindAddress = jsonAddress.str;
97 		listenPort = cast(ushort)jsonPort.integer;
98 
99 		debugPrint("Binding to address: " ~ bindAddress ~ " and port " ~ to!(string)(listenPort));
100 		
101 		/* Create a socket */
102 		serverSocket = new Socket(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
103 		serverSocket.bind(parseAddress(bindAddress, listenPort));
104 	}
105 
106 	/* Start listen loop */
107 	public void run()
108 	{
109 		for(ulong i = 0; i < listeners.length; i++)
110 		{
111 			debugPrint("Starting...");
112 			listeners[i].start();
113 		}
114 		
115 	}
116 
117 	/* Authenticate the user */
118 	public bool authenticate(string username, string password)
119 	{
120 		/* TODO: Implement me */
121 		debugPrint("Attempting to authenticate:\n\nUsername: " ~ username ~ "\nPassword: " ~ password);
122 
123 		/* If the authentication went through */
124 		bool authed = true;
125 
126 		/* If the authentication succeeded */
127 		if(authed)
128 		{
129 			/* Add the user to the list of authenticated clients */
130 		}
131 		
132 		return true;
133 	}
134 
135 	/* Returns the MessageHandler object of the requested type */
136 	public MessageHandler findHandler(string payloadType)
137 	{
138 		/* The found MessageHandler */
139 		MessageHandler foundHandler;
140 		
141 		for(uint i = 0; i < handlers.length; i++)
142 		{
143 			if(cmp(handlers[i].getPluginName(), payloadType) == 0)
144 			{
145 				foundHandler = handlers[i];
146 				break;
147 			}
148 		}
149 		return foundHandler;
150 	}
151 
152 	public static bool isBuiltInCommand(string command)
153 	{
154 		/* Whether or not `payloadType` is a built-in command */
155 		bool isBuiltIn = true;
156 
157 
158 		return isBuiltIn;
159 	}
160 }
161 
162