|
|
|
@ -5,10 +5,34 @@
|
|
|
|
|
module libdnet.libdnet; |
|
|
|
|
|
|
|
|
|
import std.socket : Address, Socket; |
|
|
|
|
import tasky.engine : Engine; |
|
|
|
|
import tasky.engine : Engine, TaskyEvent; |
|
|
|
|
import tasky.jobs : Descriptor; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import libdnet.messages.types; |
|
|
|
|
|
|
|
|
|
import msgpack; |
|
|
|
|
|
|
|
|
|
/* TODO: Remove this when we use the newer version of tasky (which uses TaskyEvent) */ |
|
|
|
|
import eventy.event : Event; |
|
|
|
|
|
|
|
|
|
import dlog; |
|
|
|
|
|
|
|
|
|
public class Client |
|
|
|
|
{ |
|
|
|
|
/** |
|
|
|
|
* Without __gshared, this would cause us to have a `logger` per-thread |
|
|
|
|
* and statically init a new DefaultLogger() for each respective `logger` field |
|
|
|
|
* |
|
|
|
|
* This makes sure we have one `logger` field for ALL threads and therefore |
|
|
|
|
* only one static initialization. |
|
|
|
|
* |
|
|
|
|
* Funnily enough if you wanted the opposite behaviour, omitting the `__gshared` |
|
|
|
|
* will not help, DMD complains. One must make it explicit I guess with a |
|
|
|
|
* static initialization block `static this()`. |
|
|
|
|
*/ |
|
|
|
|
private __gshared static Logger logger = new DefaultLogger(); |
|
|
|
|
|
|
|
|
|
private Engine engine; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -16,7 +40,7 @@ public class Client
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Socket sock; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -33,53 +57,141 @@ public class Client
|
|
|
|
|
this.endpoint = endpoint; |
|
|
|
|
|
|
|
|
|
/* Open socket here */ |
|
|
|
|
Socket sock = new Socket(); |
|
|
|
|
sock.connect(endpoint); |
|
|
|
|
this.sock = new Socket(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialize a new Tasky engine */ |
|
|
|
|
engine = new Engine(sock); |
|
|
|
|
|
|
|
|
|
/* Register handlers */ |
|
|
|
|
registerHandlers(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public enum SpecProtocolID : byte |
|
|
|
|
{ |
|
|
|
|
NEWMESSAGE |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Connect to the server |
|
|
|
|
* Protocols |
|
|
|
|
*/ |
|
|
|
|
public void connect() |
|
|
|
|
private ulong[SpecProtocolID] ids; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Registers all of the handlers |
|
|
|
|
*/ |
|
|
|
|
private final void registerHandlers() |
|
|
|
|
{ |
|
|
|
|
/* Start the Tasky engine */ |
|
|
|
|
engine.start(); |
|
|
|
|
/* Register the message handler */ |
|
|
|
|
Descriptor messageHandlerDesc = new class Descriptor |
|
|
|
|
{ |
|
|
|
|
this() |
|
|
|
|
{ |
|
|
|
|
super(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override void handler_TaskyEvent(TaskyEvent e) |
|
|
|
|
{ |
|
|
|
|
/* Call the entry point handler */ |
|
|
|
|
messageHandler_entry(e); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
ids[SpecProtocolID.NEWMESSAGE] = messageHandlerDesc.getDescriptorClass(); |
|
|
|
|
|
|
|
|
|
/* TODO: Handler IDs must match the specifition so these should be set in sequence */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* TODO: Only output when in debug mode |
|
|
|
|
*/ |
|
|
|
|
logger.log("<<< Protocol specification breakdown >>>"); |
|
|
|
|
import std.conv : to; |
|
|
|
|
foreach(SpecProtocolID specID; ids.keys()) |
|
|
|
|
{ |
|
|
|
|
logger.log("["~to!(string)(specID)~"] = "~to!(string)(ids[specID])); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unittest |
|
|
|
|
{ |
|
|
|
|
logger.log("unittesting with null address family (no connect() call)"); |
|
|
|
|
Client c = new Client(null); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Login |
|
|
|
|
* New message handler |
|
|
|
|
* |
|
|
|
|
* This is called whenever a new message arrives |
|
|
|
|
* |
|
|
|
|
* TODO: Switch to `TaskyEvent e` |
|
|
|
|
*/ |
|
|
|
|
public void login(string[] credentials) |
|
|
|
|
private final void messageHandler_entry(TaskyEvent e) |
|
|
|
|
{ |
|
|
|
|
/* Get the payload */ |
|
|
|
|
ubyte[] eventPayload = cast(ubyte[])e.getPayload(); |
|
|
|
|
|
|
|
|
|
/* TODO: Check for msgpack errors */ |
|
|
|
|
|
|
|
|
|
/* Unpack the message */ |
|
|
|
|
EntityMessage message = unpack!(EntityMessage)(eventPayload); |
|
|
|
|
|
|
|
|
|
/* Call the handler */ |
|
|
|
|
messageHandler(message); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Override this to provide your handler for new messages |
|
|
|
|
*/ |
|
|
|
|
public void messageHandler(EntityMessage message) |
|
|
|
|
{ |
|
|
|
|
import std.stdio; |
|
|
|
|
writeln(message); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Shutsdown the client |
|
|
|
|
* Authenicate with the server |
|
|
|
|
* |
|
|
|
|
* This is a handler that will get a unique descriptor |
|
|
|
|
* for this given authentication attempt such that it |
|
|
|
|
* matches up the reply, you want to ovveride authResponseHandler |
|
|
|
|
*/ |
|
|
|
|
public void shutdown() |
|
|
|
|
public void auth(string[] credentials) |
|
|
|
|
{ |
|
|
|
|
/* TODO: Logout if not already logged out */ |
|
|
|
|
/* TODO: Do auth */ |
|
|
|
|
|
|
|
|
|
/* TODO: Set the handler to `authResponseHandler` */ |
|
|
|
|
Descriptor desc; |
|
|
|
|
|
|
|
|
|
/* TODO: Get tasky to shutdown */ |
|
|
|
|
/* TODO: Check if descriptor IDs available */ |
|
|
|
|
|
|
|
|
|
/* Get the descriptor ID */ |
|
|
|
|
desc.getDescriptorClass(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void authResponseHandler() |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* TODO: Hook ~this() onto shutdown() */ |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* When the next cycle of the garbage collector |
|
|
|
|
* runs and realises there is a zero-refcount |
|
|
|
|
* to this object then shutdown the client |
|
|
|
|
* Connect to the server |
|
|
|
|
*/ |
|
|
|
|
~this() |
|
|
|
|
public final void start() |
|
|
|
|
{ |
|
|
|
|
/* Shutdown the client */ |
|
|
|
|
shutdown(); |
|
|
|
|
/* TODO: Catch errors: Connect the socket to the endpoint host */ |
|
|
|
|
sock.connect(endpoint); |
|
|
|
|
|
|
|
|
|
/* Start the Tasky engine */ |
|
|
|
|
engine.start(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|