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 }