1 module besterd;
2 
3 import server.server : BesterServer;
4 import std.conv : to;
5 import std.socket : SocketOSException, parseAddress, UnixAddress;
6 import utils.debugging : dprint;
7 import std.stdio : File, writeln;
8 import std.json : parseJSON, JSONValue;
9 import listeners.listener : BesterListener, BesterListenerException;
10 import listeners.types : TCP4Listener, TCP6Listener, UNIXListener;
11 import std.file : exists;
12 
13 void main(string[] args)
14 {
15 	/* Make sure we have atleast two arguments */
16 	if(args.length >= 2)
17 	{
18 		/* Get the second argument for configuration file path */
19 		string configFilePath = args[1];
20 
21 		/* Start thhe server if the file exists, else show an error */
22 		if(exists(configFilePath))
23 		{
24 			startServer(args[1]);
25 		}
26 		else
27 		{
28 			writeln("Provided server configuration file \"" ~ configFilePath ~ "\" does not exist");
29 		}
30 	}
31 
32 	/* TODO: Add usage check and arguments before this */
33 
34 	dprint("Main finished, remaining threads are keeping this open if it hangs");
35 
36 	/* TODO: Install signal handler so a shutdown can trigger shutdown */
37 }
38 
39 private JSONValue getConfig(string configurationFilePath)
40 {
41 	/* TODO: Open the file here */
42 	File configFile;
43 	configFile.open(configurationFilePath);
44 
45 	/* The file buffer */
46 	byte[] fileBuffer;
47 
48 	/* Allocate the buffer to be the size of the file */
49 	fileBuffer.length = configFile.size();
50 
51 	/* Read the content of the file */
52 	/* TODO: Error handling ErrnoException */
53 	fileBuffer = configFile.rawRead(fileBuffer);
54 	configFile.close();
55 
56 	JSONValue config;
57 
58 	/* TODO: JSON error checking */
59 	config = parseJSON(cast(string)fileBuffer);
60 
61 	return config;	
62 }
63 
64 private BesterListener[] getListeners(BesterServer server, JSONValue networkBlock)
65 {
66 	BesterListener[] listeners;
67 
68 	/* TODO: Error handling and get keys and clean up for formality */
69 
70 	try
71 	{
72 		/* Look for IPv4 TCP block */
73 		JSONValue inet4TCPBlock = networkBlock["tcp4"];
74 		dprint("<<< IPv4 TCP Block >>>\n" ~ inet4TCPBlock.toPrettyString());
75 		string inet4Address = inet4TCPBlock["address"].str();
76 		ushort inet4Port = to!(ushort)(inet4TCPBlock["port"].str());
77 		TCP4Listener tcp4Listener = new TCP4Listener(server, parseAddress(inet4Address, inet4Port));
78 		listeners ~= tcp4Listener;
79 
80 		/* Look for IPv6 TCP block */
81 		JSONValue inet6TCPBlock = networkBlock["tcp6"];
82 		dprint("<<< IPv6 TCP Block >>>\n" ~ inet6TCPBlock.toPrettyString());
83 		string inet6Address = inet6TCPBlock["address"].str();
84 		ushort inet6Port = to!(ushort)(inet6TCPBlock["port"].str());
85 		TCP6Listener tcp6Listener = new TCP6Listener(server, parseAddress(inet6Address, inet6Port));
86 		listeners ~= tcp6Listener;
87 
88 		/* Look for UNIX Domain block */
89 		JSONValue unixDomainBlock = networkBlock["unix"];
90 		dprint("<<< UNIX Domain Block >>>\n" ~ unixDomainBlock.toPrettyString());
91 		string unixAddress = unixDomainBlock["address"].str();
92 		// UNIXListener unixListener = new UNIXListener(server, new UnixAddress(unixAddress));
93 		// listeners ~= unixListener;
94 	}
95 	catch(BesterListenerException e)
96 	{
97 
98 	}
99 	
100 
101 	return listeners;
102 }
103 
104 private void startServer(string configurationFilePath)
105 {
106 	/* The server configuration */
107 	JSONValue serverConfiguration = getConfig(configurationFilePath);
108 	dprint("<<< Bester.d configuration >>>\n" ~ serverConfiguration.toPrettyString());
109 
110 	try
111 	{
112 		/* The server */
113 		BesterServer server = null;
114 
115 		/* TODO: Bounds anc type checking */
116 
117 		/* Get the network block */
118 		JSONValue networkBlock = serverConfiguration["network"];
119 
120 		/* Create the Bester server */
121 		server = new BesterServer(serverConfiguration);
122 
123 		/* TODO: Get keys */
124 		BesterListener[] listeners = getListeners(server, networkBlock);
125 
126 		for(ulong i = 0; i < listeners.length; i++)
127 		{
128 			/* Add listener */
129 			server.addListener(listeners[i]);
130 		}
131 		
132 		/* Start running the server (starts the listeners) */
133 		server.run();
134 	}
135 	catch(SocketOSException exception)
136 	{
137 		dprint("Error binding: " ~ exception.toString());
138 	}
139 	
140 }