diff options
Diffstat (limited to 'lib/pure/asyncio.nim')
-rw-r--r-- | lib/pure/asyncio.nim | 96 |
1 files changed, 48 insertions, 48 deletions
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index 6a7cbe396..f58bb4302 100644 --- a/lib/pure/asyncio.nim +++ b/lib/pure/asyncio.nim @@ -18,8 +18,8 @@ import sockets, os ## This module implements an asynchronous event loop together with asynchronous ## sockets which use this event loop. ## It is akin to Python's asyncore module. Many modules that use sockets -## have an implementation for this module, those modules should all have a -## ``register`` function which you should use to add the desired objects to a +## have an implementation for this module, those modules should all have a +## ``register`` function which you should use to add the desired objects to a ## dispatcher which you created so ## that you can receive the events associated with that module's object. ## @@ -27,19 +27,19 @@ import sockets, os ## function in a while loop. ## ## **Note:** Most modules have tasks which need to be ran regularly, this is -## why you should not call ``poll`` with a infinite timeout, or even a +## why you should not call ``poll`` with a infinite timeout, or even a ## very long one. In most cases the default timeout is fine. ## ## **Note:** This module currently only supports select(), this is limited by ## FD_SETSIZE, which is usually 1024. So you may only be able to use 1024 ## sockets at a time. -## +## ## Most (if not all) modules that use asyncio provide a userArg which is passed ## on with the events. The type that you set userArg to must be inheriting from ## ``RootObj``! ## -## **Note:** If you want to provide async ability to your module please do not -## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible +## **Note:** If you want to provide async ability to your module please do not +## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible ## that in the future this type's fields will not be exported therefore breaking ## your code. ## @@ -59,11 +59,11 @@ import sockets, os ## socket which will give you the client which is connecting. You should then ## set any events that you want to use on that client and add it to your dispatcher ## using the ``register`` procedure. -## +## ## An example ``handleAccept`` follows: -## +## ## .. code-block:: nim -## +## ## var disp = newDispatcher() ## ... ## proc handleAccept(s: AsyncSocket) = @@ -74,7 +74,7 @@ import sockets, os ## client.handleRead = ... ## disp.register(client) ## ... -## +## ## For client sockets you should only be interested in the ``handleRead`` and ## ``handleConnect`` events. The former gets called whenever the socket has ## received messages and can be read from and the latter gets called whenever @@ -83,14 +83,14 @@ import sockets, os ## ## Getting a blocking client from an AsyncSocket ## ============================================= -## +## ## If you need a asynchronous server socket but you wish to process the clients ## synchronously then you can use the ``getSocket`` converter to get ## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined ## with ``accept`` like so: ## ## .. code-block:: nim -## +## ## proc handleAccept(s: AsyncSocket) = ## var client: Socket ## getSocket(s).accept(client) @@ -113,11 +113,11 @@ type handleWrite*: proc (h: RootRef) {.nimcall, gcsafe.} handleError*: proc (h: RootRef) {.nimcall, gcsafe.} hasDataBuffered*: proc (h: RootRef): bool {.nimcall, gcsafe.} - + open*: bool task*: proc (h: RootRef) {.nimcall, gcsafe.} mode*: FileMode - + Delegate* = ref DelegateObj Dispatcher* = ref DispatcherObj @@ -144,7 +144,7 @@ type deleg: Delegate SocketStatus* = enum - SockIdle, SockConnecting, SockConnected, SockListening, SockClosed, + SockIdle, SockConnecting, SockConnected, SockListening, SockClosed, SockUDPBound {.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate, @@ -176,8 +176,8 @@ proc newAsyncSocket(): AsyncSocket = result.lineBuffer = "".TaintedString result.sendBuffer = "" -proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, - protocol: Protocol = IPPROTO_TCP, +proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket = ## Initialises an AsyncSocket object. If a socket cannot be initialised ## EOS is raised. @@ -236,7 +236,7 @@ proc asyncSockHandleWrite(h: RootRef) = if AsyncSocket(h).socket.isSSL and not AsyncSocket(h).socket.gotHandshake: return - + if AsyncSocket(h).info == SockConnecting: AsyncSocket(h).handleConnect(AsyncSocket(h)) AsyncSocket(h).info = SockConnected @@ -256,10 +256,10 @@ proc asyncSockHandleWrite(h: RootRef) = # do nothing instead. discard elif bytesSent != sock.sendBuffer.len: - sock.sendBuffer = sock.sendBuffer[bytesSent .. -1] + sock.sendBuffer = sock.sendBuffer[bytesSent .. ^1] elif bytesSent == sock.sendBuffer.len: sock.sendBuffer = "" - + if AsyncSocket(h).handleWrite != nil: AsyncSocket(h).handleWrite(AsyncSocket(h)) except OSError: @@ -284,7 +284,7 @@ when defined(ssl): else: # handshake will set socket's ``sslNoHandshake`` field. discard AsyncSocket(h).socket.handshake() - + proc asyncSockTask(h: RootRef) = when defined(ssl): @@ -377,9 +377,9 @@ proc acceptAddr*(server: AsyncSocket, client: var AsyncSocket, if c == invalidSocket: raiseSocketError(server.socket) c.setBlocking(false) # TODO: Needs to be tested. - + # deleg.open is set in ``toDelegate``. - + client.socket = c client.lineBuffer = "".TaintedString client.sendBuffer = "" @@ -393,7 +393,7 @@ proc accept*(server: AsyncSocket, client: var AsyncSocket) = proc acceptAddr*(server: AsyncSocket): tuple[sock: AsyncSocket, address: string] {.deprecated.} = ## Equivalent to ``sockets.acceptAddr``. - ## + ## ## **Deprecated since version 0.9.0:** Please use the function above. var client = newAsyncSocket() var address: string = "" @@ -441,17 +441,17 @@ proc isConnected*(s: AsyncSocket): bool = ## Determines whether ``s`` is connected. return s.info == SockConnected proc isListening*(s: AsyncSocket): bool = - ## Determines whether ``s`` is listening for incoming connections. + ## Determines whether ``s`` is listening for incoming connections. return s.info == SockListening proc isConnecting*(s: AsyncSocket): bool = - ## Determines whether ``s`` is connecting. + ## Determines whether ``s`` is connecting. return s.info == SockConnecting proc isClosed*(s: AsyncSocket): bool = ## Determines whether ``s`` has been closed. return s.info == SockClosed proc isSendDataBuffered*(s: AsyncSocket): bool = ## Determines whether ``s`` has data waiting to be sent, i.e. whether this - ## socket's sendBuffer contains data. + ## socket's sendBuffer contains data. return s.sendBuffer.len != 0 proc setHandleWrite*(s: AsyncSocket, @@ -550,7 +550,7 @@ proc send*(sock: AsyncSocket, data: string) = sock.sendBuffer.add(data) sock.deleg.mode = fmReadWrite elif bytesSent != data.len: - sock.sendBuffer.add(data[bytesSent .. -1]) + sock.sendBuffer.add(data[bytesSent .. ^1]) sock.deleg.mode = fmReadWrite proc timeValFromMilliseconds(timeout = 500): Timeval = @@ -561,10 +561,10 @@ proc timeValFromMilliseconds(timeout = 500): Timeval = proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) = FD_ZERO(fd) - for i in items(s): + for i in items(s): m = max(m, int(i.fd)) FD_SET(i.fd, fd) - + proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) = var i = 0 var L = s.len @@ -576,16 +576,16 @@ proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) = inc(i) setLen(s, L) -proc select(readfds, writefds, exceptfds: var seq[Delegate], +proc select(readfds, writefds, exceptfds: var seq[Delegate], timeout = 500): int = var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) - + var rd, wr, ex: TFdSet var m = 0 createFdSet(rd, readfds, m) createFdSet(wr, writefds, m) createFdSet(ex, exceptfds, m) - + if timeout != -1: result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv))) else: @@ -599,7 +599,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool = ## This function checks for events on all the delegates in the `PDispatcher`. ## It then proceeds to call the correct event handler. ## - ## This function returns ``True`` if there are file descriptors that are still + ## This function returns ``True`` if there are file descriptors that are still ## open, otherwise ``False``. File descriptors that have been ## closed are immediately removed from the dispatcher automatically. ## @@ -611,7 +611,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool = var readDg, writeDg, errorDg: seq[Delegate] = @[] var len = d.delegates.len var dc = 0 - + while dc < len: let deleg = d.delegates[dc] if (deleg.mode != fmWrite or deleg.mode != fmAppend) and deleg.open: @@ -625,20 +625,20 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool = # File/socket has been closed. Remove it from dispatcher. d.delegates[dc] = d.delegates[len-1] dec len - + d.delegates.setLen(len) - + var hasDataBufferedCount = 0 for d in d.delegates: if d.hasDataBuffered(d.deleVal): hasDataBufferedCount.inc() d.handleRead(d.deleVal) if hasDataBufferedCount > 0: return true - + if readDg.len() == 0 and writeDg.len() == 0: ## TODO: Perhaps this shouldn't return if errorDg has something? return false - + if select(readDg, writeDg, errorDg, timeout) != 0: for i in 0..len(d.delegates)-1: if i > len(d.delegates)-1: break # One delegate might've been removed. @@ -651,7 +651,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool = deleg.handleWrite(deleg.deleVal) if deleg notin errorDg: deleg.handleError(deleg.deleVal) - + # Execute tasks for i in items(d.delegates): i.task(i.deleVal) @@ -664,7 +664,7 @@ when isMainModule: proc testConnect(s: AsyncSocket, no: int) = echo("Connected! " & $no) - + proc testRead(s: AsyncSocket, no: int) = echo("Reading! " & $no) var data = "" @@ -682,31 +682,31 @@ when isMainModule: var address = "" s.acceptAddr(client, address) echo("Accepted ", address) - client.handleRead = + client.handleRead = proc (s: AsyncSocket) = testRead(s, 2) disp.register(client) proc main = var d = newDispatcher() - + var s = asyncSocket() s.connect("amber.tenthbit.net", Port(6667)) - s.handleConnect = + s.handleConnect = proc (s: AsyncSocket) = testConnect(s, 1) - s.handleRead = + s.handleRead = proc (s: AsyncSocket) = testRead(s, 1) d.register(s) - + var server = asyncSocket() server.handleAccept = - proc (s: AsyncSocket) = + proc (s: AsyncSocket) = testAccept(s, d, 78) server.bindAddr(Port(5555)) server.listen() d.register(server) - + while d.poll(-1): discard main() |