diff --git a/dub.json b/dub.json index 9105438..d374adc 100644 --- a/dub.json +++ b/dub.json @@ -4,9 +4,8 @@ ], "copyright": "Copyright © 2021, Tristan B. Kildaire", "dependencies": { - "dlog": "~>0.0.5", - "gogga": "~>0.1.3", - "jcli": "~>0.24.0" + "dlog": "~>0.0.6", + "tasky": "~>1.2.0" }, "description": "Official implementation of the DNET protocol for the server-side", "license": "AGPLv3", diff --git a/dub.selections.json b/dub.selections.json new file mode 100644 index 0000000..3eacbae --- /dev/null +++ b/dub.selections.json @@ -0,0 +1,10 @@ +{ + "fileVersion": 1, + "versions": { + "bformat": "3.1.3", + "dlog": "0.0.6", + "eventy": "0.2.4", + "tasky": "1.2.0", + "tristanable": "2.6.12" + } +} diff --git a/source/app.d b/source/app.d new file mode 100644 index 0000000..5e34900 --- /dev/null +++ b/source/app.d @@ -0,0 +1,6 @@ +import std.stdio; + +void main() +{ + writeln("Hello world"); +} \ No newline at end of file diff --git a/source/dnetd/app.d b/source/dnetd/app.d deleted file mode 100644 index ccadedb..0000000 --- a/source/dnetd/app.d +++ /dev/null @@ -1,37 +0,0 @@ -/** -* Main module -*/ -module dnetd.app; - -import dlog; -import dnetd.exceptions : GeneralException; -import std.json : JSONValue; -import dnetd.config : Configuration; -import dnetd.server : Server; - -public Logger logger; -string VERSION = "0.0.1"; - -void main() -{ - /* Setup the logger */ - logger = new DefaultLogger(); - - logger.log("Welcome to dnetd v"~VERSION); - - /* TODO: Add jcli handling here */ - - try - { - - Configuration config = Configuration.getConfig("config.json"); - - /* TODO: Server init with config here */ - Server server = new Server(config); - - } - catch(GeneralException e) - { - logger.log(e.toString()); - } -} diff --git a/source/dnetd/config.d b/source/dnetd/config.d deleted file mode 100644 index 0c7c034..0000000 --- a/source/dnetd/config.d +++ /dev/null @@ -1,225 +0,0 @@ -/** -* Configuration sub-system -*/ -module dnetd.config; - -import dnetd.app : logger; -import std.json : JSONValue, JSONException, parseJSON; -import dnetd.exceptions; -import std.stdio : File; -import std.string : cmp, strip; - -/** -* In its instance-form this represents a read-in and parsed configuration -* of the configuration file in an OOP format, with the ability to write back -* any modifications made to it (TODO: Add this). -* -* In static use it provides the ability to translate between the JSON configuration -* file and the instance (OOP) form. -*/ -public final class Configuration -{ - string configPath; - NetworkInformation netInfo; - - public static Configuration getConfig(string configPath) - { - JSONValue jsonConfig = readConfig("config.json"); - Configuration config = Configuration.fromJSON(jsonConfig); - - /* Save the path so we can rehash later on */ - config.configPath = configPath; - - return config; - } - - /** - * Reads in the JSON from the given path to the configuration - * file - * - * On error throws TODO - */ - private static JSONValue readConfig(string path) - { - File file; - file.open(path); /* TODO:Check this for errors */ - /* TODO: Only open with read rights */ - - /* Allocate a buffer for the file */ - byte[] contents; - contents.length = file.size(); /* TODO: Check size here */ - - /* TODO: Check this */ - /* TODO: Technically the below is fine */ - file.rawRead(contents); - - JSONValue config; - - try - { - config = parseJSON(cast(string)contents); - } - catch(JSONException e) - { - /* TODO: Get specific error here to show where config syntax is wrong */ - - - throw new ConfigurationError(e); - } - - - return config; - } - - /** - * Load the configuration from a JSON source, returning the - * configuration as a Configuration object, on error, null (TODO: Throw exception rather) - * - * @param jsonConfig the JSONValue configuration - */ - private static Configuration fromJSON(JSONValue jsonConfig) - { - Configuration config = new Configuration(); - - try - { - /* TODO: Parse config here */ - - /* Retrieve the `network` block */ - JSONValue networkBlock = jsonConfig["network"]; - - config.netInfo = confNetInfo(networkBlock["info"]); - // TODO: Log the above logger.log() - - - /* Retrieve the `accounting` block */ - JSONValue accountingBlock = jsonConfig["accounting"]; - - /* Retrieve the `links` block */ - JSONValue linksBlock = jsonConfig["links"]; - - - } - catch(JSONException e) - { - /* TODO: Throw proper error here saying which key is missing */ - throw new ConfigurationError(e); - } - - return config; - } - - private static NetworkInformation confNetInfo(JSONValue infoBlock) - { - NetworkInformation netInfo; - - /** - * TODO (keycheck): Make sure that `serverName` is present - * and `networkName` - * - * `motd` is optional - */ - bool foundNetworkName; - bool foundServerName; - - string[] keys = infoBlock.object.keys(); - foreach(string key; keys) - { - if(cmp(key, "serverName") == 0) - { - foundServerName = true; - netInfo.serverName = infoBlock[key].str(); - } - else if(cmp(key, "networkName") == 0) - { - foundNetworkName = true; - netInfo.networkName = infoBlock[key].str(); - } - - } - - - /** - * Make sure we found the required fields - * - * These are: serverName, networkName, sid (TODO: Finish these) - */ - if(!foundServerName) - { - throw new ConfigurationError("Missing server name"); - } - else if(!foundNetworkName) - { - throw new ConfigurationError("Missing network name"); - } - - /** - * Strip whitespace from the beginnings and endings of - * `serverName`, `networkName`, (TODO: Complete list) - */ - netInfo.serverName = strip(netInfo.serverName); - netInfo.networkName = strip(netInfo.networkName); - - /** - * Make sure the required fields were set to a valid - * value - */ - if(cmp(netInfo.networkName, "") == 0) - { - throw new ConfigurationError("Network name cannot be empty"); - } - else if(cmp(netInfo.serverName, "") == 0) - { - throw new ConfigurationError("Server name cannot be empty"); - } - - /* TODO: Add handling for motd and motdFile */ - - - return netInfo; - } - - private this() - { - } -} - - - - -/** -* Configuration error -*/ -public final class ConfigurationError : GeneralException -{ - this(string message) - { - super(message); - } - - this(JSONException e) - { - super("JSON configuration has a syntax error ("~e.msg~")"); - } -} - - -/** -* Network information -* -* This holds information that pertains to network-wide -* information (such as the network's name) and server-specific -* information such as the message-of-the-day or the server's -* name -*/ -struct NetworkInformation -{ - string serverName; - string motd; - ushort sid; - - string networkName; - -} - - diff --git a/source/dnetd/connection/connection.d b/source/dnetd/connection/connection.d deleted file mode 100644 index a4e5df7..0000000 --- a/source/dnetd/connection/connection.d +++ /dev/null @@ -1,36 +0,0 @@ -/** -* Connection handling sub-system -*/ -module dnetd.connection.connection; - -import core.thread : Thread; -import dnetd.server : Server; - -/** -* Represents a client's/server's connection to -* this server -* -* These are normally spawned by the `serviceLoop` -* of Listener sub-classes -*/ -public abstract class Connection : Thread -{ - /** - * The server instance this Connection - * is associated with - */ - private Server server; - - this(Server server) - { - super(&handler); - this.server = server; - } - - /** - * Connection handler - * - * This is to be implemented by sub-classes - */ - public abstract void handler(); -} diff --git a/source/dnetd/connection/socket.d b/source/dnetd/connection/socket.d deleted file mode 100644 index 309b066..0000000 --- a/source/dnetd/connection/socket.d +++ /dev/null @@ -1,30 +0,0 @@ -/** -* Socket-based connection handler sub-system -*/ - -import dnetd.connection.connection : Connection; -import std.socket; -import dnetd.server : Server; - -/** -* FIXME: When we do anything so far, I am assuming -* a streaming socket so we shouldn't let the -* SocketListener use any SocketType that isn't STREAM -*/ -public final class SocketConnection : Connection -{ - private Socket socket; - - this(Server server, Socket socket) - { - super(server); - this.socket = socket; - } - - public override void handler() - { - while(true) - { - } - } -} diff --git a/source/dnetd/exceptions.d b/source/dnetd/exceptions.d deleted file mode 100644 index 5b45006..0000000 --- a/source/dnetd/exceptions.d +++ /dev/null @@ -1,33 +0,0 @@ -/** -* Exceptions sub-system -*/ -module dnetd.exceptions; - -import std.exception; - -/** -* Base class for all DNETD exceptions -*/ -public class GeneralException : Exception -{ - /* Name of exception type and description */ - private string errorTypeName; - private string message; - - /** - * TODO: Make this take in a `string message` - */ - this(string message) - { - import std.string : split; - string[] fragments = split(this.classinfo.name, "."); - errorTypeName = fragments[fragments.length-1]; - this.message = message; - super(null); - } - - public override string toString() - { - return errorTypeName~": "~message; - } -} diff --git a/source/dnetd/listeners/listeners.d b/source/dnetd/listeners/listeners.d deleted file mode 100644 index 49a0367..0000000 --- a/source/dnetd/listeners/listeners.d +++ /dev/null @@ -1,42 +0,0 @@ -/** -* Module for listeners -* -* These include the base listener class responsible -* for managing a connection with peers and some -* concrete classes implementing this for various -* network protocols -*/ -module dnetd.listeners.listeners; - -import dnetd.server : Server; -import dnetd.exceptions : GeneralException; -import std.exception; -import core.thread : Thread; - -public abstract class Listener : Thread -{ - private Server server; - - this(Server server) - { - super(&serviceLoop); - this.server = server; - } - - /** - * The connection accepting loop of which - * is provided as the "worker" function to - * the thread - */ - public abstract void serviceLoop(); -} - -public abstract class ListenerException : GeneralException -{ - /* TODO: Potentially remove `listener` */ - this(Listener listener, string msg) - { - /* TODO: Set message here */ - super(msg); - } -} diff --git a/source/dnetd/listeners/socket.d b/source/dnetd/listeners/socket.d deleted file mode 100644 index de8403a..0000000 --- a/source/dnetd/listeners/socket.d +++ /dev/null @@ -1,65 +0,0 @@ -/** -* Socket-based listener for supporting any -* network protocol that Linux supports, such as -* TCP (STREAM-based) on IPv4 and IPv6 and UNIX -* domain sockets... to name a few. -*/ -module dnetd.listeners.socket; - -import dnetd.listeners.listeners; -import dnetd.server : Server; -import std.socket; -import std.conv : to; - -public final class SocketListenerException : ListenerException -{ - this(SocketListener e) - { - string msg = to!(string)(e.getAddress().addressFamily) - ~ - "-type socket listener error"; - - super(e, msg); - } -} - -public final class SocketListener : Listener -{ - private Socket socket; - private Address address; - - this(Server server, Address address, SocketType type, ProtocolType proto) - { - super(server); - this.address = address; - - try - { - socket = new Socket(address.addressFamily, type, proto); - socket.bind(address); - } - catch(SocketOSException e) - { - throw new SocketListenerException(this); - } - } - - /** - * Socket accept-and-connection spawner - * loop - */ - public override void serviceLoop() - { - while(true) - { - Socket clientSock = socket.accept(); - - //TODO - } - } - - public Address getAddress() - { - return address; - } -} diff --git a/source/dnetd/server.d b/source/dnetd/server.d deleted file mode 100644 index 336d336..0000000 --- a/source/dnetd/server.d +++ /dev/null @@ -1,69 +0,0 @@ -/** -* Server sub-system -* -* This module pertains to the code required to stand-up a -* singular instance of a server and all the state that -* relates to it, such as users, server links and processing/handling -* of messages and commands. -*/ -module dnetd.server; - -import dnetd.app : logger; -import dnetd.config : ConfigurationError, Configuration; -import std.container.slist : SList; -import dnetd.listeners.listeners : Listener; -import dnetd.connection.connection : Connection; -import core.sync.mutex : Mutex; - -/** -* Represents an instance of a dnet server -*/ -public final class Server -{ - /* Server Configuration */ - private Configuration config; - - /** - * Listeners - */ - private SList!(Listener) listeners; - private Mutex listenersMutex; - - /** - * Connected clients and servers - * - * Inbound and outbound - */ - private SList!(Connection) conns; - private Mutex connsMutex; - - - - - this(Configuration config) - { - logger.log("Server instance '"~"PUT ID HERE"~"' starting up..."); - this.config = config; - - /** - * Initialize all locks for data - * structures - */ - connsMutex = new Mutex(); - listeners = new Mutex(); - } - - /* Rehash server configuration */ - public void rehash() - { - try - { - config = Configuration.getConfig(config.configPath); - } - catch(ConfigurationError e) - { - /* TODO: Handle the error here by sending a server message */ - logger.log("Error whilst rehashing the configuration"); - } - } -}