2016-01-11 20:33:49 +00:00
|
|
|
module eventcore.driver;
|
|
|
|
@safe: /*@nogc:*/ nothrow:
|
|
|
|
|
|
|
|
import core.time : Duration;
|
|
|
|
import std.socket : Address;
|
|
|
|
|
|
|
|
|
|
|
|
interface EventDriver {
|
|
|
|
@safe: /*@nogc:*/ nothrow:
|
|
|
|
//
|
|
|
|
// General functionality
|
|
|
|
//
|
|
|
|
|
|
|
|
/// Releases all resources associated with the driver
|
|
|
|
void dispose();
|
|
|
|
|
|
|
|
/**
|
|
|
|
The number of pending callbacks.
|
|
|
|
|
|
|
|
When this number drops to zero, the event loop can safely be quit. It is
|
|
|
|
guaranteed that no callbacks will be made anymore, unless new callbacks
|
|
|
|
get registered.
|
|
|
|
*/
|
|
|
|
size_t waiterCount();
|
|
|
|
|
|
|
|
/**
|
|
|
|
Runs the event loop to process a chunk of events.
|
|
|
|
|
|
|
|
This method optionally waits for an event to arrive if none are present
|
|
|
|
in the event queue. The function will return after either the specified
|
|
|
|
timeout has elapsed, or once the event queue has been fully emptied.
|
|
|
|
|
|
|
|
Params:
|
|
|
|
timeout = Maximum amount of time to wait for an event. A duration of
|
|
|
|
zero will cause the function to only process pending events. The
|
|
|
|
the default duration of `Duration.max`, if necessary, will wait
|
|
|
|
indefinitely until an event arrives.
|
|
|
|
*/
|
2016-01-27 10:02:54 +00:00
|
|
|
ExitReason processEvents(Duration timeout = Duration.max);
|
|
|
|
|
|
|
|
/**
|
|
|
|
Causes `processEvents` to return with `ExitReason.exited` as soon as
|
|
|
|
possible.
|
|
|
|
|
|
|
|
A call to `processEvents` that is currently in progress will be notfied
|
|
|
|
so that it returns immediately. If no call is in progress, the next call
|
|
|
|
to `processEvents` will immediately return with `ExitReason.exited`.
|
|
|
|
*/
|
|
|
|
void exit();
|
2016-01-11 20:33:49 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// TCP
|
|
|
|
//
|
|
|
|
StreamSocketFD connectStream(scope Address peer_address, ConnectCallback on_connect);
|
|
|
|
StreamListenSocketFD listenStream(scope Address bind_address, AcceptCallback on_accept);
|
|
|
|
void waitForConnections(StreamListenSocketFD sock, AcceptCallback on_accept);
|
2016-06-14 05:57:10 +00:00
|
|
|
ConnectionState getConnectionState(StreamSocketFD sock);
|
2016-01-11 20:33:49 +00:00
|
|
|
void setTCPNoDelay(StreamSocketFD socket, bool enable);
|
2016-01-27 10:02:54 +00:00
|
|
|
void readSocket(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish);
|
|
|
|
void writeSocket(StreamSocketFD socket, const(ubyte)[] buffer, IOMode mode, IOCallback on_write_finish);
|
2016-01-11 20:33:49 +00:00
|
|
|
void waitSocketData(StreamSocketFD socket, IOCallback on_data_available);
|
|
|
|
void shutdownSocket(StreamSocketFD socket, bool shut_read = true, bool shut_write = true);
|
2016-06-14 05:57:10 +00:00
|
|
|
void cancelRead(StreamSocketFD socket);
|
|
|
|
void cancelWrite(StreamSocketFD socket);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Files
|
|
|
|
//
|
|
|
|
//FileFD openFile(string path, FileOpenMode mode);
|
|
|
|
//FileFD createTempFile();
|
2016-01-11 20:33:49 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Manual events
|
|
|
|
//
|
|
|
|
EventID createEvent();
|
|
|
|
void triggerEvent(EventID event, bool notify_all = true);
|
2016-01-27 10:02:54 +00:00
|
|
|
void triggerEvent(EventID event, bool notify_all = true) shared;
|
2016-02-03 13:21:02 +00:00
|
|
|
void waitForEvent(EventID event, EventCallback on_event);
|
2016-06-15 16:19:22 +00:00
|
|
|
void cancelWaitForEvent(EventID event, EventCallback on_event);
|
2016-01-11 20:33:49 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Timers
|
|
|
|
//
|
2016-06-14 07:25:06 +00:00
|
|
|
TimerID createTimer();
|
2016-01-11 20:33:49 +00:00
|
|
|
void setTimer(TimerID timer, Duration timeout, Duration repeat = Duration.zero);
|
|
|
|
void stopTimer(TimerID timer);
|
|
|
|
bool isTimerPending(TimerID timer);
|
|
|
|
bool isTimerPeriodic(TimerID timer);
|
2016-02-03 13:21:02 +00:00
|
|
|
void waitTimer(TimerID timer, TimerCallback callback);
|
2016-06-14 05:57:10 +00:00
|
|
|
void cancelTimerWait(TimerID timer, TimerCallback callback);
|
2016-01-11 20:33:49 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Resource ownership
|
|
|
|
//
|
|
|
|
|
|
|
|
/**
|
|
|
|
Increments the reference count of the given resource.
|
|
|
|
*/
|
|
|
|
void addRef(SocketFD descriptor);
|
|
|
|
/// ditto
|
|
|
|
void addRef(FileFD descriptor);
|
|
|
|
/// ditto
|
|
|
|
void addRef(TimerID descriptor);
|
|
|
|
/// ditto
|
|
|
|
void addRef(EventID descriptor);
|
|
|
|
|
|
|
|
/**
|
|
|
|
Decrements the reference count of the given resource.
|
|
|
|
|
|
|
|
Once the reference count reaches zero, all associated resources will be
|
2016-02-03 13:21:02 +00:00
|
|
|
freed and the resource descriptor gets invalidated.
|
2016-01-11 20:33:49 +00:00
|
|
|
*/
|
|
|
|
void releaseRef(SocketFD descriptor);
|
|
|
|
/// ditto
|
|
|
|
void releaseRef(FileFD descriptor);
|
|
|
|
/// ditto
|
|
|
|
void releaseRef(TimerID descriptor);
|
|
|
|
/// ditto
|
|
|
|
void releaseRef(EventID descriptor);
|
2016-06-14 05:57:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
/// Low-level user data access. Use `getUserData` instead.
|
|
|
|
protected void* rawUserData(StreamSocketFD descriptor, size_t size, DataInitializer initialize, DataInitializer destroy) @system;
|
|
|
|
|
|
|
|
/** Retrieves a reference to a user-defined value associated with a descriptor.
|
|
|
|
*/
|
|
|
|
@property final ref T userData(T, FD)(FD descriptor)
|
|
|
|
@trusted {
|
|
|
|
import std.conv : emplace;
|
|
|
|
static void init(void* ptr) { emplace(cast(T*)ptr); }
|
|
|
|
static void destr(void* ptr) { destroy(*cast(T*)ptr); }
|
|
|
|
return *cast(T*)rawUserData(descriptor, T.sizeof, &init, &destr);
|
|
|
|
}
|
2016-01-11 20:33:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
alias ConnectCallback = void delegate(StreamSocketFD, ConnectStatus);
|
|
|
|
alias AcceptCallback = void delegate(StreamListenSocketFD, StreamSocketFD);
|
|
|
|
alias IOCallback = void delegate(StreamSocketFD, IOStatus, size_t);
|
|
|
|
alias EventCallback = void delegate(EventID);
|
|
|
|
alias TimerCallback = void delegate(TimerID);
|
2016-06-14 05:57:10 +00:00
|
|
|
@system alias DataInitializer = void function(void*);
|
2016-01-11 20:33:49 +00:00
|
|
|
|
2016-01-27 10:02:54 +00:00
|
|
|
enum ExitReason {
|
|
|
|
timeout,
|
|
|
|
idle,
|
|
|
|
outOfWaiters,
|
|
|
|
exited
|
|
|
|
}
|
|
|
|
|
2016-01-11 20:33:49 +00:00
|
|
|
enum ConnectStatus {
|
|
|
|
connected,
|
|
|
|
refused,
|
|
|
|
timeout,
|
|
|
|
bindFailure,
|
|
|
|
unknownError
|
|
|
|
}
|
|
|
|
|
2016-06-14 05:57:10 +00:00
|
|
|
enum ConnectionState {
|
|
|
|
initialized,
|
|
|
|
connecting,
|
|
|
|
connected,
|
|
|
|
passiveClose,
|
|
|
|
activeClose,
|
|
|
|
closed
|
|
|
|
}
|
|
|
|
|
2016-01-11 20:33:49 +00:00
|
|
|
enum IOMode {
|
|
|
|
immediate, /// Process only as much as possible without waiting
|
|
|
|
once, /// Process as much as possible with a single call
|
|
|
|
all /// Process the full buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum IOStatus {
|
|
|
|
ok, /// The data has been transferred normally
|
|
|
|
disconnected, /// The connection was closed before all data could be transterred
|
|
|
|
error, /// An error occured while transferring the data
|
|
|
|
wouldBlock /// Returned for `IOMode.immediate` when no data is readily readable/writable
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Handle(T, T invalid_value = T.init, int MAGIC = __LINE__) {
|
|
|
|
static if (is(T : Handle!(V, M), V, int M)) alias BaseType = T.BaseType;
|
|
|
|
else alias BaseType = T;
|
|
|
|
|
|
|
|
enum invalid = Handle.init;
|
|
|
|
|
|
|
|
T value = invalid_value;
|
|
|
|
|
|
|
|
this(BaseType value) { this.value = T(value); }
|
|
|
|
|
|
|
|
U opCast(U : Handle!(V, M), V, int M)() {
|
|
|
|
// TODO: verify that U derives from typeof(this)!
|
|
|
|
return U(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
U opCast(U : BaseType)()
|
|
|
|
{
|
|
|
|
return cast(U)value;
|
|
|
|
}
|
|
|
|
|
|
|
|
alias value this;
|
|
|
|
}
|
|
|
|
|
|
|
|
alias FD = Handle!(int, -1);
|
|
|
|
alias SocketFD = Handle!FD;
|
|
|
|
alias StreamSocketFD = Handle!SocketFD;
|
|
|
|
alias StreamListenSocketFD = Handle!SocketFD;
|
|
|
|
alias FileFD = Handle!FD;
|
2016-01-27 10:02:54 +00:00
|
|
|
alias EventID = Handle!FD;
|
2016-01-11 20:33:49 +00:00
|
|
|
alias TimerID = Handle!int;
|
|
|
|
alias EventWaitID = Handle!int;
|