summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/asyncdispatch.nim140
-rw-r--r--lib/pure/asyncftpclient.nim18
-rw-r--r--lib/pure/asynchttpserver.nim16
-rw-r--r--lib/pure/asyncnet.nim18
-rw-r--r--lib/pure/ftpclient.nim2
-rw-r--r--lib/pure/httpclient.nim13
-rw-r--r--lib/pure/os.nim2
7 files changed, 183 insertions, 26 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 5363d8862..cac98e160 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -18,42 +18,137 @@ export Port, SocketFlag
 #{.injectStmt: newGcInvariant().}
 
 ## AsyncDispatch
-## -------------
+## *************
 ##
-## This module implements a brand new dispatcher based on Futures.
-## On Windows IOCP is used and on other operating systems the ``selectors``
-## module is used instead.
+## This module implements asynchronous IO. This includes a dispatcher,
+## a ``Future`` type implementation, and an ``async`` macro which allows
+## asynchronous code to be written in a synchronous style with the ``await``
+## keyword.
 ##
-## **Note:** This module is still largely experimental.
+## The dispatcher acts as a kind of event loop. You must call ``poll`` on it
+## (or a function which does so for you such as ``waitFor`` or ``runForever``)
+## in order to poll for any outstanding events. The underlying implementation
+## is based on epoll on Linux, IO Completion Ports on Windows and select on
+## other operating systems.
+##
+## The ``poll`` function will not, on its own, return any events. Instead
+## an appropriate ``Future`` object will be completed. A ``Future`` is a
+## type which holds a value which is not yet available, but which *may* be
+## available in the future. You can check whether a future is finished
+## by using the ``finished`` function. When a future is finished it means that
+## either the value that it holds is now available or it holds an error instead.
+## The latter situation occurs when the operation to complete a future fails
+## with an exception. You can distinguish between the two situations with the
+## ``failed`` function.
+##
+## Future objects can also store a callback procedure which will be called
+## automatically once the future completes.
+##
+## Futures therefore can be thought of as an implementation of the proactor
+## pattern. In this
+## pattern you make a request for an action, and once that action is fulfilled
+## a future is completed with the result of that action. Requests can be
+## made by calling the appropriate functions. For example: calling the ``recv``
+## function will create a request for some data to be read from a socket. The
+## future which the ``recv`` function returns will then complete once the
+## requested amount of data is read **or** an exception occurs.
+##
+## Code to read some data from a socket may look something like this:
+##
+##   .. code-block::nim
+##      var future = socket.recv(100)
+##      future.callback =
+##        proc () =
+##          echo(future.read)
+##
+## All asynchronous functions returning a ``Future`` will not block. They
+## will not however return immediately. An asynchronous function will have
+## code which will be executed before an asynchronous request is made, in most
+## cases this code sets up the request.
+##
+## In the above example, the ``recv`` function will return a brand new
+## ``Future`` instance once the request for data to be read from the socket
+## is made. This ``Future`` instance will complete once the requested amount
+## of data is read, in this case it is 100 bytes. The second line sets a
+## callback on this future which will be called once the future completes.
+## All the callback does is write the data stored in the future to ``stdout``.
+## The ``read`` function is used for this and it checks whether the future
+## completes with an error for you (if it did it will simply raise the
+## error), if there is no error however it returns the value of the future.
+##
+## Asynchronous procedures
+## -----------------------
+##
+## Asynchronous procedures remove the pain of working with callbacks. They do
+## this by allowing you to write asynchronous code the same way as you would
+## write synchronous code.
+##
+## An asynchronous procedure is marked using the ``{.async.}`` pragma.
+## When marking a procedure with the ``{.async.}`` pragma it must have a
+## ``Future[T]`` return type or no return type at all. If you do not specify
+## a return type then ``Future[void]`` is assumed.
+##
+## Inside asynchronous procedures ``await`` can be used to call any
+## procedures which return a
+## ``Future``; this includes asynchronous procedures. When a procedure is
+## "awaited", the asynchronous procedure it is awaited in will
+## suspend its execution
+## until the awaited procedure's Future completes. At which point the
+## asynchronous procedure will resume its execution. During the period
+## when an asynchronous procedure is suspended other asynchronous procedures
+## will be run by the dispatcher.
+##
+## The ``await`` call may be used in many contexts. It can be used on the right
+## hand side of a variable declaration: ``var data = await socket.recv(100)``,
+## in which case the variable will be set to the value of the future
+## automatically. It can be used to await a ``Future`` object, and it can
+## be used to await a procedure returning a ``Future[void]``:
+## ``await socket.send("foobar")``.
+##
+## Discarding futures
+## ------------------
+##
+## Futures should **never** be discarded. This is because they may contain
+## errors. If you do not care for the result of a Future then you should
+## use the ``asyncCheck`` procedure instead of the ``discard`` keyword.
+##
+## Examples
+## --------
+##
+## For examples take a look at the documentation for the modules implementing
+## asynchronous IO. A good place to start is the
+## `asyncnet module <asyncnet.html>`_.
+##
+## Limitations/Bugs
+## ----------------
+## 
+## * ``except`` statement (without `try`) does not work inside async procedures.
+## * The effect system (``raises: []``) does not work with async procedures.
+## * Can't await in a ``except`` body
 
 
-# TODO: ``except`` statement (without `try`) does not work.
-# TODO: Multiple exception names in a ``except`` don't work.
-# TODO: The effect system (raises: []) has trouble with my try transformation.
-# TODO: Can't await in a 'except' body
-# TODO: getCurrentException(Msg) don't work
 # TODO: Check if yielded future is nil and throw a more meaningful exception
 
 # -- Futures
 
 type
-  FutureBase* = ref object of RootObj
+  FutureBase* = ref object of RootObj ## Untyped future.
     cb: proc () {.closure,gcsafe.}
     finished: bool
-    error*: ref Exception
+    error*: ref Exception ## Stored exception
     errorStackTrace*: string
     when not defined(release):
       stackTrace: string ## For debugging purposes only.
       id: int
       fromProc: string
 
-  Future*[T] = ref object of FutureBase
-    value: T
+  Future*[T] = ref object of FutureBase ## Typed future.
+    value: T ## Stored value
 
 {.deprecated: [PFutureBase: FutureBase, PFuture: Future].}
 
 
-var currentID* = 0
+var currentID = 0
 proc newFuture*[T](fromProc: string = "unspecified"): Future[T] =
   ## Creates a new future.
   ##
@@ -161,6 +256,10 @@ proc read*[T](future: Future[T]): T =
     raise newException(ValueError, "Future still in progress.")
 
 proc readError*[T](future: Future[T]): ref Exception =
+  ## Retrieves the exception stored in ``future``.
+  ##
+  ## An ``ValueError`` exception will be thrown if no exception exists
+  ## in the specified Future.
   if future.error != nil: return future.error
   else:
     raise newException(ValueError, "No error in future.")
@@ -173,7 +272,7 @@ proc finished*[T](future: Future[T]): bool =
 
 proc failed*(future: FutureBase): bool =
   ## Determines whether ``future`` completed with an error.
-  future.error != nil
+  return future.error != nil
 
 proc asyncCheck*[T](future: Future[T]) =
   ## Sets a callback on ``future`` which raises an exception if the future
@@ -950,7 +1049,7 @@ proc accept*(socket: TAsyncFD,
 
 # -- Await Macro
 
-template createCb*(retFutureSym, iteratorNameSym,
+template createCb(retFutureSym, iteratorNameSym,
                    name: expr): stmt {.immediate.} =
   var nameIterVar = iteratorNameSym
   #{.push stackTrace: off.}
@@ -1193,7 +1292,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
 
   # -> createCb(retFuture)
   var cbName = newIdentNode("cb")
-  var procCb = newCall("createCb", retFutureSym, iteratorNameSym,
+  var procCb = newCall(bindSym"createCb", retFutureSym, iteratorNameSym,
                        newStrLitNode(prc[0].getName))
   outerProcBody.add procCb
 
@@ -1232,7 +1331,10 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ## is read) then line will be set to ``""``.
   ## The partial line **will be lost**.
   ##
-  ## **Warning**: This assumes that lines are delimited by ``\r\l``.
+  ## **Warning**: This assumes that lines are delimited by ``\r\L``.
+  ##
+  ## **Note**: This procedure is mostly used for testing. You likely want to
+  ## use ``asyncnet.recvLine`` instead.
   
   template addNLIfEmpty(): stmt =
     if result.len == 0:
diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim
index c5a97adfc..fc38dc31a 100644
--- a/lib/pure/asyncftpclient.nim
+++ b/lib/pure/asyncftpclient.nim
@@ -6,6 +6,24 @@
 #    distribution, for details about the copyright.
 #
 
+## This module implement an asynchronous FTP client.
+##
+## Examples
+## --------
+##
+## .. code-block::nim
+##
+##      var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
+##      proc main(ftp: AsyncFtpClient) {.async.} =
+##        await ftp.connect()
+##        echo await ftp.pwd()
+##        echo await ftp.listDirs()
+##        await ftp.store("payload.jpg", "payload.jpg")
+##        await ftp.retrFile("payload.jpg", "payload2.jpg")
+##        echo("Finished")
+##
+##      waitFor main(ftp)
+
 import asyncdispatch, asyncnet, strutils, parseutils, os, times
 
 from ftpclient import FtpBaseObj, ReplyError, FtpEvent
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 931a0c15a..9de0a6268 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -9,7 +9,20 @@
 
 ## This module implements a high performance asynchronous HTTP server.
 ##
-## **Note:** This module is still largely experimental.
+## Examples
+## --------
+##
+## This example will create an HTTP server on port 8080. The server will
+## respond to all requests with a ``200 OK`` response code and "Hello World"
+## as the response body.
+##
+## .. code-block::nim
+##    var server = newAsyncHttpServer()
+##    proc cb(req: TRequest) {.async.} =
+##      await req.respond(Http200, "Hello World")
+##
+##    asyncCheck server.serve(Port(8080), cb)
+##    runForever()
 
 import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
 type
@@ -52,6 +65,7 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int],
   result = protocol.major == major and protocol.minor == minor
 
 proc newAsyncHttpServer*(): PAsyncHttpServer =
+  ## Creates a new ``AsyncHttpServer`` instance.
   new result
 
 proc addHeaders(msg: var string, headers: PStringTable) =
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 4539dfdcb..a16111349 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -10,8 +10,20 @@
 ## This module implements a high-level asynchronous sockets API based on the
 ## asynchronous dispatcher defined in the ``asyncdispatch`` module.
 ##
-## Example
-## =======
+## SSL
+## ---
+##
+## SSL can be enabled by compiling with the ``-d:ssl`` flag.
+##
+## You must create a new SSL context with the ``newContext`` function defined
+## in the ``net`` module. You may then call ``wrapSocket`` on your socket using
+## the newly created SSL context to get an SSL socket.
+##
+## Examples
+## --------
+##
+## Chat server
+## ^^^^^^^^^^^
 ## 
 ## The following example demonstrates a simple chat server.
 ##
@@ -41,8 +53,6 @@
 ##   asyncCheck serve()
 ##   runForever()
 ##
-##
-## **Note:** This module is still largely experimental.
 
 import asyncdispatch
 import rawsockets
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index 07c9b5662..37b25871d 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/pure/ftpclient.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2012 Dominik Picheta
+#        (c) Copyright 2014 Dominik Picheta
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 1548cf231..892ddac40 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -48,6 +48,19 @@
 ##    
 ##   echo(postContent("http://validator.w3.org/check", headers, body))
 ##
+## Asynchronous HTTP requests
+## ==========================
+##
+## You simply have to create a new instance of the ``AsyncHttpClient`` object.
+## You may then use ``await`` on the functions defined for that object.
+## Keep in mind that the following code needs to be inside an asynchronous
+## procedure.
+##
+## .. code-block::nim
+##
+##    var client = newAsyncHttpClient()
+##    var resp = await client.request("http://google.com")
+##
 ## SSL/TLS support
 ## ===============
 ## This requires the OpenSSL library, fortunately it's widely used and installed
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 6b3ee6e6d..c08297b7c 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -80,7 +80,7 @@ when defined(Nimdoc): # only for proper documentation:
       ## search patch components (as in PATH), such as ':' for POSIX or ';' for
       ## Windows.
 
-    FileSystemCaseSensitive* = True
+    FileSystemCaseSensitive* = true
       ## True if the file system is case sensitive, false otherwise. Used by
       ## `cmpPaths` to compare filenames properly.
 
alt'>
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144