1 module dast.usockets; 2 3 import libusockets; 4 import std.typecons; 5 6 pragma(LDC_no_moduleinfo); 7 pragma(LDC_no_typeinfo): 8 9 private alias CB = extern (C) void function(us_loop_t* loop); 10 11 alias integrate = us_loop_integrate; 12 13 @nogc struct EventLoop(T = void[0]) { 14 alias LoopCallback = extern (C) void function(typeof(this) loop); 15 16 private us_loop_t* loop; 17 // 需要保证EventLoop和us_loop_t的大小一致 18 enum uint extSize = T.sizeof; 19 20 @property handle() => loop; 21 alias handle this; 22 23 @disable this(); 24 25 this(us_loop_t* handle) { 26 loop = handle; 27 } 28 29 this(typeof(null)) { 30 this(LoopCallback.init); 31 } 32 33 this(LoopCallback onWakeUp, 34 LoopCallback onPre = null, 35 LoopCallback onPost = null) { 36 if (!onWakeUp) 37 onWakeUp = &noop; 38 if (!onPre) 39 onPre = &noop; 40 if (!onPost) 41 onPost = &noop; 42 loop = us_create_loop(null, cast(CB)onWakeUp, cast(CB)onPre, cast(CB)onPost, extSize); 43 } 44 45 void run() => us_loop_run(loop); 46 47 void wakeup() => us_wakeup_loop(loop); 48 49 @property ref data() @trusted => *cast(T*)us_loop_ext(loop); 50 @property long iteration() const => us_loop_iteration_number(loop); 51 52 void free() => us_loop_free(loop); 53 54 auto timer(int fallthrough = 0, int extSize = 0) 55 => us_create_timer(loop, fallthrough, extSize); 56 57 extern (C) static void noop(typeof(this)) { 58 } 59 } 60 61 template eventLoop(T = void[0]) { 62 alias LoopCallback = extern (C) void function(EventLoop!T loop); 63 64 auto eventLoop(LoopCallback onWakeUp = null, 65 LoopCallback onPre = null, 66 LoopCallback onPost = null) => EventLoop!T(onWakeUp, onPre, onPost); 67 } 68 69 struct SSLOptions { 70 string key; 71 string cert; 72 string passphrase; 73 string dhParams; 74 string caFile; 75 string sslCiphers; 76 bool preferLowMemoryUsage; 77 } 78 79 /// 将函数参数第一个类型替换为第二个类型参数,返回这个类型 80 private template ReplaceFirstParam(F, T) { 81 import std.traits; 82 83 static if (isFunctionPointer!F) { 84 alias ReplaceFirstParam = SetFunctionAttributes!( 85 T function(T, Parameters!F[1 .. $]), functionLinkage!F, functionAttributes!F); 86 } else static if (isDelegate!F) { 87 alias ReplaceFirstParam = SetFunctionAttributes!( 88 T delegate(T, Parameters!F[1 .. $]), functionLinkage!F, functionAttributes!F); 89 } else 90 static assert(0, "Unsupported type"); 91 } 92 93 private alias R(T) = ReplaceFirstParam!(T, us_socket_t*); 94 95 /++ 96 Socket context 97 Params: 98 T: User data type 99 S: Socket data type 100 SSL: Whether to use SSL 101 +/ 102 @nogc struct Context(CT = void[0], ST = void[0], bool SSL = false) { 103 private alias S = Socket, 104 OnSocketOpen = extern (C) S function(S socket, int isClient, char* ip, int ipLength), 105 OnSocketClose = extern (C) S function(S socket, int code, void* reason), 106 OnSocketData = extern (C) S function(S socket, char* data, int length), 107 OnSocketEnd = extern (C) S function(S socket), 108 OnSocketWritable = OnSocketEnd, 109 OnSocketTimeout = OnSocketEnd; 110 private us_socket_context_t* context; 111 enum int extSize = CT.sizeof; 112 enum ssl = SSL; 113 114 @property handle() => context; 115 alias handle this; 116 117 @property ref data() @trusted => *cast(CT*)us_socket_context_ext(ssl, context); 118 119 @property loop() const 120 => EventLoop!()(us_socket_context_loop(0, context)); 121 122 this(us_socket_context_t* handle) { 123 context = handle; 124 } 125 126 this(us_loop_t* loop, SSLOptions sslOptions = SSLOptions()) { 127 us_socket_context_options_t options = { 128 sslOptions.key.ptr, 129 sslOptions.cert.ptr, 130 sslOptions.passphrase.ptr, 131 sslOptions.dhParams.ptr, 132 sslOptions.caFile.ptr, 133 sslOptions.sslCiphers.ptr, 134 sslOptions.preferLowMemoryUsage, 135 }; 136 context = us_create_socket_context(ssl, loop, extSize, options); 137 } 138 139 void free() => us_socket_context_free(ssl, context); 140 141 void onOpen(OnSocketOpen onOpen) 142 => us_socket_context_on_open(ssl, context, cast(R!OnSocketOpen)onOpen); 143 144 void onData(OnSocketData onData) 145 => us_socket_context_on_data(ssl, context, cast(R!OnSocketData)onData); 146 147 void onWritable(OnSocketWritable onWritable) 148 => us_socket_context_on_writable(ssl, context, cast(R!OnSocketWritable)onWritable); 149 150 void onTimeout(OnSocketTimeout onTimeout) 151 => us_socket_context_on_timeout(ssl, context, cast(R!OnSocketTimeout)onTimeout); 152 153 void onClose(OnSocketClose onClose) 154 => us_socket_context_on_close(ssl, context, cast(R!OnSocketClose)onClose); 155 156 void onEnd(OnSocketEnd onEnd) 157 => us_socket_context_on_end(ssl, context, cast(R!OnSocketEnd)onEnd); 158 159 auto listen(string host, ushort port) 160 => Listener( 161 us_socket_context_listen(ssl, context, host.ptr, port, 0, ST.sizeof), ssl); 162 163 struct Socket { 164 private us_socket_t* socket; 165 166 @property handle() => socket; 167 alias handle this; 168 169 @property ref data() => *cast(ST*)us_socket_ext(ssl, socket); 170 171 @property bool isShutdown() const 172 => us_socket_is_shut_down(ssl, socket) != 0; 173 174 @property bool isEstablished() const 175 => us_socket_is_established(ssl, socket) != 0; 176 177 @property context() const 178 => Context(us_socket_context(ssl, socket)); 179 180 @property timeout(uint secs) => us_socket_timeout(ssl, socket, secs); 181 182 @disable this(); 183 184 this(us_socket_t* handle) { 185 socket = handle; 186 } 187 188 auto close(int code = 0, void* reason = null) 189 => Socket(us_socket_close(ssl, socket, code, reason)); 190 191 void shutdown() => us_socket_shutdown(ssl, socket); 192 193 void shutdownRead() => us_socket_shutdown_read(ssl, socket); 194 195 void flush() => us_socket_flush(0, socket); 196 197 int write(const(void)[] data, bool more = false) 198 => us_socket_write(ssl, socket, cast(const char*)data.ptr, cast(int)data.length, more); 199 } 200 } 201 202 struct Listener { 203 private us_listen_socket_t* socket; 204 bool ssl; 205 206 @disable this(); 207 208 @property handle() => socket; 209 alias handle this; 210 211 this(us_listen_socket_t* handle, bool ssl) { 212 socket = handle; 213 this.ssl = ssl; 214 } 215 216 T opCast(T : bool)() const => socket !is null; 217 218 void close() => us_listen_socket_close(ssl, socket); 219 }