mirror of
https://github.com/deavminet/dnetd
synced 2024-09-21 01:33:24 +02:00
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" : {
|
"general" : {
|
||||||
"address" : "0.0.0.0",
|
"addresses" : ["0.0.0.0"],
|
||||||
"port" : "7777",
|
"port" : "7777",
|
||||||
"network" : "aBasedIRCNetwork",
|
"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 --|
|
|-- 9 --|-- channel --|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Reply format:
|
Reply format:
|
||||||
|
|
||||||
```
|
```
|
||||||
|-- status (1 byte) --|-- channel members (CSV) --|
|
|-- 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`
|
### `chanprop`
|
||||||
|
|
||||||
|
|
||||||
|
77
source/app.d
77
source/app.d
@ -1,13 +1,82 @@
|
|||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.socket : parseAddress;
|
import std.socket : parseAddress;
|
||||||
import dnetd.dserver : DServer;
|
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;
|
||||||
|
|
||||||
|
try
|
||||||
DServer dserver = new DServer(parseAddress("0.0.0.0", 7777));
|
{
|
||||||
|
/* 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,
|
MSG,
|
||||||
MEMBER_COUNT,
|
MEMBER_COUNT,
|
||||||
MEMBER_LIST,
|
MEMBER_LIST,
|
||||||
|
SERVER_INFO,
|
||||||
|
MOTD,
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,6 +246,16 @@ public class DConnection : Thread
|
|||||||
{
|
{
|
||||||
command = Command.MEMBER_LIST;
|
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;
|
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 */
|
/* If no matching built-in command was found */
|
||||||
else
|
else
|
||||||
|
@ -18,6 +18,7 @@ import std.string : cmp;
|
|||||||
import core.sync.mutex : Mutex;
|
import core.sync.mutex : Mutex;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.conv : to;
|
import std.conv : to;
|
||||||
|
import dnetd.dconfig;
|
||||||
|
|
||||||
public class DServer : Thread
|
public class DServer : Thread
|
||||||
{
|
{
|
||||||
@ -28,6 +29,9 @@ public class DServer : Thread
|
|||||||
private Address sockAddress;
|
private Address sockAddress;
|
||||||
|
|
||||||
|
|
||||||
|
/* Server configuration */
|
||||||
|
private DConfig config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection queue
|
* Connection queue
|
||||||
*/
|
*/
|
||||||
@ -40,13 +44,17 @@ public class DServer : Thread
|
|||||||
private DChannel[] channels;
|
private DChannel[] channels;
|
||||||
private Mutex channelLock;
|
private Mutex channelLock;
|
||||||
|
|
||||||
this(Address sockAddress)
|
/* TODO: Implement new constructor */
|
||||||
|
this(DConfig config)
|
||||||
{
|
{
|
||||||
/* Set the function to be called on thread start */
|
/* Set the function to be called on thread start */
|
||||||
super(&dequeueLoop);
|
super(&dequeueLoop);
|
||||||
|
|
||||||
|
/* Set the server's config */
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
/* Set the listening address */
|
/* Set the listening address */
|
||||||
this.sockAddress = sockAddress;
|
this.sockAddress = config.getGeneral().getAddress();
|
||||||
|
|
||||||
/* Initialize the server */
|
/* Initialize the server */
|
||||||
init();
|
init();
|
||||||
@ -55,6 +63,11 @@ public class DServer : Thread
|
|||||||
startServer();
|
startServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DConfig getConfig()
|
||||||
|
{
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
private void init()
|
private void init()
|
||||||
{
|
{
|
||||||
/* Setup socket */
|
/* Setup socket */
|
||||||
@ -309,4 +322,18 @@ public class DServer : Thread
|
|||||||
|
|
||||||
return currentChannels;
|
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
Block a user