mirror of https://github.com/deavminet/dnetd.git
daemon now uses configuration file for network parameters, also added motd command and serverinfo command (not yet implemented)
This commit is contained in:
parent
c8a9c2bffe
commit
ef90f1ba13
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"general" : {
|
||||
"address" : "0.0.0.0",
|
||||
"addresses" : ["0.0.0.0"],
|
||||
"port" : "7777",
|
||||
"network" : "aBasedIRCNetwork",
|
||||
"name" : "MyBrandSpankingNewIRCServer"
|
||||
"name" : "MyBrandSpankingNewIRCServer",
|
||||
"motd" : "Welcome to my generic dnet chat server!"
|
||||
}
|
||||
}
|
35
protocol.md
35
protocol.md
|
@ -143,13 +143,46 @@ Request format:
|
|||
|-- 9 --|-- channel --|
|
||||
```
|
||||
|
||||
|
||||
Reply format:
|
||||
|
||||
```
|
||||
|-- status (1 byte) --|-- channel members (CSV) --|
|
||||
```
|
||||
|
||||
### `serverinfo`
|
||||
|
||||
Request format:
|
||||
|
||||
```
|
||||
|-- 10 --|
|
||||
```
|
||||
|
||||
Reply format:
|
||||
|
||||
```
|
||||
|-- status (1 byte) --|-- server info(CSV) --|
|
||||
```
|
||||
|
||||
#### Format of server info (CSV)
|
||||
|
||||
```
|
||||
<serverName>,<networkName>,<userCount>,<channelCount>
|
||||
```
|
||||
|
||||
### `motd`
|
||||
|
||||
Request format:
|
||||
|
||||
```
|
||||
|-- 11 --|
|
||||
```
|
||||
|
||||
Reply format:
|
||||
|
||||
```
|
||||
|-- status (1 byte) --|-- motd --|
|
||||
```
|
||||
|
||||
### `chanprop`
|
||||
|
||||
|
||||
|
|
77
source/app.d
77
source/app.d
|
@ -1,13 +1,82 @@
|
|||
import std.stdio;
|
||||
import std.socket : parseAddress;
|
||||
import dnetd.dserver : DServer;
|
||||
import dnetd.dconfig : DConfig;
|
||||
import std.json;
|
||||
import std.exception;
|
||||
|
||||
void main()
|
||||
void main(string[] args)
|
||||
{
|
||||
/* TODO: Args for bind */
|
||||
/* Configuration file */
|
||||
string configFilename;
|
||||
|
||||
/* If there are no arguments */
|
||||
if(!args.length)
|
||||
{
|
||||
/* Use the default file */
|
||||
configFilename = "config.json";
|
||||
}
|
||||
/* If there is one argument */
|
||||
else if(args.length == 1)
|
||||
{
|
||||
/* use the specified one */
|
||||
configFilename = args[0];
|
||||
}
|
||||
/* Illegal amount of guns in one household (no such thing) */
|
||||
else
|
||||
{
|
||||
writeln("Invalid number of arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Configuration file contents */
|
||||
byte[] data;
|
||||
|
||||
|
||||
DServer dserver = new DServer(parseAddress("0.0.0.0", 7777));
|
||||
try
|
||||
{
|
||||
/* Open the file for reading */
|
||||
File config;
|
||||
config.open(configFilename, "r");
|
||||
|
||||
/* Read the configuration file data */
|
||||
data.length = config.size();
|
||||
data = config.rawRead(data);
|
||||
config.close();
|
||||
}
|
||||
catch(ErrnoException e)
|
||||
{
|
||||
writeln("Failure to use configuration file'"~configFilename~"' with error:\n\n"~e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
/* The JSON */
|
||||
JSONValue json;
|
||||
|
||||
try
|
||||
{
|
||||
/* Parse the configuration file */
|
||||
json = parseJSON(cast(string)data);
|
||||
}
|
||||
catch(JSONException e)
|
||||
{
|
||||
writeln("Failure to parse configuration file'"~configFilename~"' with error:\n\n"~e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new configuration file and check configuration parameters */
|
||||
DConfig config = DConfig.getConfig(json);
|
||||
|
||||
/* If the configuration reading was successful (valid JSON) */
|
||||
if(config)
|
||||
{
|
||||
/* Start the server */
|
||||
DServer dserver = new DServer(config);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln("Failure to read a valid dnetd configuration file'"~configFilename~"'");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* DConfig
|
||||
*
|
||||
* Represents all configuration parameters
|
||||
*/
|
||||
module dnetd.dconfig;
|
||||
|
||||
import std.json;
|
||||
import std.conv;
|
||||
import std.socket : Address, parseAddress;
|
||||
|
||||
public final class DConfig
|
||||
{
|
||||
/* General configuration */
|
||||
private DGeneralConfig generalConfig;
|
||||
|
||||
/* Link configuration */
|
||||
private DLinkConfig linksConfig;
|
||||
|
||||
private this()
|
||||
{
|
||||
/* TODO: */
|
||||
}
|
||||
|
||||
public DGeneralConfig getGeneral()
|
||||
{
|
||||
return generalConfig;
|
||||
}
|
||||
|
||||
public DLinkConfig getLinks()
|
||||
{
|
||||
return linksConfig;
|
||||
}
|
||||
|
||||
public static DConfig getConfig(JSONValue json)
|
||||
{
|
||||
/* The newly created configuration */
|
||||
DConfig config = new DConfig();
|
||||
|
||||
try
|
||||
{
|
||||
/* TODO: Parse */
|
||||
|
||||
/* Get the `general` block */
|
||||
JSONValue generalBlock = json["general"];
|
||||
config.generalConfig = DGeneralConfig.getConfig(generalBlock);
|
||||
|
||||
/* Get the `links` block */
|
||||
JSONValue linksBlock = json["links"];
|
||||
//config.linksConfig = DLinkConfig.getConfig(linksBlock);
|
||||
}
|
||||
catch(JSONException e)
|
||||
{
|
||||
/* Set config to null (signals an error) */
|
||||
config = null;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public JSONValue saveConfig()
|
||||
{
|
||||
JSONValue config;
|
||||
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public final class DGeneralConfig
|
||||
{
|
||||
|
||||
/* Addresses to bind sockets to */
|
||||
private string[] addresses;
|
||||
private ushort port;
|
||||
|
||||
/* Server information */
|
||||
private string network;
|
||||
private string name;
|
||||
private string motd;
|
||||
|
||||
private this()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static DGeneralConfig getConfig(JSONValue generalBlock)
|
||||
{
|
||||
/* The generated general config */
|
||||
DGeneralConfig config = new DGeneralConfig();
|
||||
|
||||
try
|
||||
{
|
||||
/* Set the addresses */
|
||||
foreach(JSONValue address; generalBlock["addresses"].array())
|
||||
{
|
||||
config.addresses ~= [address.str()];
|
||||
}
|
||||
|
||||
/* Set the ports */
|
||||
config.port = to!(ushort)(generalBlock["port"].str());
|
||||
|
||||
/* Set the network name */
|
||||
config.network = generalBlock["network"].str();
|
||||
|
||||
/* Set the server name */
|
||||
config.name = generalBlock["name"].str();
|
||||
|
||||
/* Set the message of the day */
|
||||
config.motd = generalBlock["motd"].str();
|
||||
|
||||
}
|
||||
catch(JSONException e)
|
||||
{
|
||||
/* Set the config to null (signals an error) */
|
||||
config = null;
|
||||
}
|
||||
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public string getMotd()
|
||||
{
|
||||
return motd;
|
||||
}
|
||||
|
||||
public Address getAddress()
|
||||
{
|
||||
/* TODO: Add multi address support later */
|
||||
return parseAddress(addresses[0], port);
|
||||
}
|
||||
}
|
||||
|
||||
public final class DLinkConfig
|
||||
{
|
||||
|
||||
}
|
|
@ -42,6 +42,8 @@ public class DConnection : Thread
|
|||
MSG,
|
||||
MEMBER_COUNT,
|
||||
MEMBER_LIST,
|
||||
SERVER_INFO,
|
||||
MOTD,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
|
@ -244,6 +246,16 @@ public class DConnection : Thread
|
|||
{
|
||||
command = Command.MEMBER_LIST;
|
||||
}
|
||||
else if(commandByte == cast(ulong)10)
|
||||
{
|
||||
command = Command.SERVER_INFO;
|
||||
}
|
||||
else if(commandByte == cast(ulong)11)
|
||||
{
|
||||
command = Command.MOTD;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return command;
|
||||
|
@ -541,6 +553,32 @@ public class DConnection : Thread
|
|||
|
||||
|
||||
|
||||
}
|
||||
/* If `serverinfo` command (requires: authed, !unspec) */
|
||||
else if(command == Command.SERVER_INFO && hasAuthed && connType != ConnectionType.UNSPEC)
|
||||
{
|
||||
/* Status */
|
||||
bool status = true;
|
||||
|
||||
/* Get the server info */
|
||||
string serverInfo = server.getServerInfo();
|
||||
|
||||
/* Encode the reply */
|
||||
reply ~= [status];
|
||||
reply ~= serverInfo;
|
||||
}
|
||||
/* If `motd` command (requires: _nothing_) */
|
||||
else if(command == Command.MOTD)
|
||||
{
|
||||
/* Status */
|
||||
bool status = true;
|
||||
|
||||
/* Get the message of the day */
|
||||
string motd = server.getConfig().getGeneral().getMotd();
|
||||
|
||||
/* Encode the reply */
|
||||
reply ~= [status];
|
||||
reply ~= motd;
|
||||
}
|
||||
/* If no matching built-in command was found */
|
||||
else
|
||||
|
|
|
@ -18,6 +18,7 @@ import std.string : cmp;
|
|||
import core.sync.mutex : Mutex;
|
||||
import std.stdio;
|
||||
import std.conv : to;
|
||||
import dnetd.dconfig;
|
||||
|
||||
public class DServer : Thread
|
||||
{
|
||||
|
@ -28,6 +29,9 @@ public class DServer : Thread
|
|||
private Address sockAddress;
|
||||
|
||||
|
||||
/* Server configuration */
|
||||
private DConfig config;
|
||||
|
||||
/**
|
||||
* Connection queue
|
||||
*/
|
||||
|
@ -40,13 +44,17 @@ public class DServer : Thread
|
|||
private DChannel[] channels;
|
||||
private Mutex channelLock;
|
||||
|
||||
this(Address sockAddress)
|
||||
/* TODO: Implement new constructor */
|
||||
this(DConfig config)
|
||||
{
|
||||
/* Set the function to be called on thread start */
|
||||
super(&dequeueLoop);
|
||||
|
||||
/* Set the server's config */
|
||||
this.config = config;
|
||||
|
||||
/* Set the listening address */
|
||||
this.sockAddress = sockAddress;
|
||||
this.sockAddress = config.getGeneral().getAddress();
|
||||
|
||||
/* Initialize the server */
|
||||
init();
|
||||
|
@ -55,6 +63,11 @@ public class DServer : Thread
|
|||
startServer();
|
||||
}
|
||||
|
||||
public DConfig getConfig()
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
/* Setup socket */
|
||||
|
@ -309,4 +322,18 @@ public class DServer : Thread
|
|||
|
||||
return currentChannels;
|
||||
}
|
||||
|
||||
public string getServerInfo()
|
||||
{
|
||||
/* The server information */
|
||||
string serverInfo;
|
||||
|
||||
/* TODO: Fetch serverName */
|
||||
/* TODO: Fetch networkName */
|
||||
/* TODO: Fetch userCount */
|
||||
/* TODO: Fetch channelCount */
|
||||
|
||||
|
||||
return serverInfo;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue