eventcore/source/eventcore/driver.d

314 lines
9.2 KiB
D
Raw Normal View History

module eventcore.driver;
@safe: /*@nogc:*/ nothrow:
import core.time : Duration;
import std.socket : Address;
interface EventDriver {
@safe: /*@nogc:*/ nothrow:
@property EventDriverCore core();
@property EventDriverFiles files();
@property EventDriverSockets sockets();
@property EventDriverTimers timers();
@property EventDriverEvents events();
@property EventDriverSignals signals();
@property EventDriverWatchers watchers();
}
interface EventDriverCore {
@safe: /*@nogc:*/ nothrow:
/// 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.
*/
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-06-16 08:42:38 +00:00
/** Resets the exit flag.
`processEvents` will automatically reset the exit flag before it returns
with `ExitReason.exited`. However, if `exit` is called outside of
`processEvents`, the next call to `processEvents` will return with
`ExitCode.exited` immediately. This function can be used to avoid this.
*/
void clearExitFlag();
/// 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);
}
}
interface EventDriverSockets {
@safe: /*@nogc:*/ nothrow:
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);
ConnectionState getConnectionState(StreamSocketFD sock);
void setTCPNoDelay(StreamSocketFD socket, bool enable);
void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish);
void write(StreamSocketFD socket, const(ubyte)[] buffer, IOMode mode, IOCallback on_write_finish);
void waitForData(StreamSocketFD socket, IOCallback on_data_available);
void shutdown(StreamSocketFD socket, bool shut_read = true, bool shut_write = true);
void cancelRead(StreamSocketFD socket);
void cancelWrite(StreamSocketFD socket);
/**
Increments the reference count of the given resource.
*/
void addRef(SocketFD descriptor);
/**
Decrements the reference count of the given resource.
Once the reference count reaches zero, all associated resources will be
freed and the resource descriptor gets invalidated.
*/
void releaseRef(SocketFD descriptor);
}
interface EventDriverFiles {
@safe: /*@nogc:*/ nothrow:
FileFD open(string path, FileOpenMode mode);
FileFD createTemp();
void write(FileFD file, ulong offset, ubyte[] buffer, IOCallback on_write_finish);
void read(FileFD file, ulong offset, ubyte[] buffer, IOCallback on_read_finish);
void cancelWrite(FileFD file);
void cancelRead(FileFD file);
/**
Increments the reference count of the given resource.
*/
void addRef(FileFD descriptor);
/**
Decrements the reference count of the given resource.
Once the reference count reaches zero, all associated resources will be
freed and the resource descriptor gets invalidated.
*/
void releaseRef(FileFD descriptor);
}
interface EventDriverEvents {
@safe: /*@nogc:*/ nothrow:
EventID create();
void trigger(EventID event, bool notify_all = true);
void trigger(EventID event, bool notify_all = true) shared;
void wait(EventID event, EventCallback on_event);
void cancelWait(EventID event, EventCallback on_event);
/**
Increments the reference count of the given resource.
*/
void addRef(EventID descriptor);
/**
Decrements the reference count of the given resource.
Once the reference count reaches zero, all associated resources will be
freed and the resource descriptor gets invalidated.
*/
void releaseRef(EventID descriptor);
}
interface EventDriverSignals {
@safe: /*@nogc:*/ nothrow:
void wait(int sig, SignalCallback on_signal);
void cancelWait(int sig);
}
interface EventDriverTimers {
@safe: /*@nogc:*/ nothrow:
TimerID create();
void set(TimerID timer, Duration timeout, Duration repeat = Duration.zero);
void stop(TimerID timer);
bool isPending(TimerID timer);
bool isPeriodic(TimerID timer);
void wait(TimerID timer, TimerCallback callback);
void cancelWait(TimerID timer, TimerCallback callback);
/**
Increments the reference count of the given resource.
*/
void addRef(TimerID descriptor);
/**
Decrements the reference count of the given resource.
Once the reference count reaches zero, all associated resources will be
freed and the resource descriptor gets invalidated.
*/
void releaseRef(TimerID descriptor);
}
interface EventDriverWatchers {
@safe: /*@nogc:*/ nothrow:
2016-10-05 11:40:38 +00:00
WatcherID watchDirectory(string path, bool recursive);
void wait(WatcherID watcher, FileChangesCallback callback);
void cancelWait(WatcherID watcher);
/**
Increments the reference count of the given resource.
*/
void addRef(WatcherID descriptor);
/**
Decrements the reference count of the given resource.
Once the reference count reaches zero, all associated resources will be
freed and the resource descriptor gets invalidated.
*/
void releaseRef(WatcherID descriptor);
}
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);
2016-10-05 11:40:38 +00:00
alias SignalCallback = void delegate(int);
alias TimerCallback = void delegate(TimerID);
2016-10-05 11:40:38 +00:00
alias FileChangesCallback = void delegate(WatcherID, in FileChange[] changes);
@system alias DataInitializer = void function(void*);
enum ExitReason {
timeout,
idle,
outOfWaiters,
exited
}
enum ConnectStatus {
connected,
refused,
timeout,
bindFailure,
unknownError
}
enum ConnectionState {
initialized,
connecting,
connected,
passiveClose,
activeClose,
closed
}
2016-10-05 11:40:38 +00:00
/**
Specifies how a file is manipulated on disk.
*/
enum FileOpenMode {
/// The file is opened read-only.
read,
/// The file is opened for read-write random access.
readWrite,
/// The file is truncated if it exists or created otherwise and then opened for read-write access.
createTrunc,
/// The file is opened for appending data to it and created if it does not exist.
append
}
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
}
2016-10-05 11:40:38 +00:00
/** Specifies the kind of change in a watched directory.
*/
enum FileChangeKind {
/// A file or directory was added
added,
/// A file or directory was deleted
removed,
/// A file or directory was modified
modified
}
/** Describes a single change in a watched directory.
*/
struct FileChange {
/// The type of change
FileChangeKind type;
/// Path of the file/directory that was changed
string path;
}
struct Handle(string NAME, T, T invalid_value = T.init) {
static if (is(T : Handle!(N, V, M), string N, 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!("FD", int, -1);
alias SocketFD = Handle!("Socket", FD);
alias StreamSocketFD = Handle!("Stream", SocketFD);
alias StreamListenSocketFD = Handle!("StreamListen", SocketFD);
alias FileFD = Handle!("File", FD);
alias EventID = Handle!("Event", FD);
alias TimerID = Handle!("Timer", int);
alias WatcherID = Handle!("Watcher", int);
alias EventWaitID = Handle!("EventWait", int);