diff --git a/README.md b/README.md index b5974308..a66c9aa3 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ **Please, note that `uvw` is still a work in progress**. `uvw` is a header-only, event based, tiny and easy to use C++ wrapper for *libuv*. -The basic idea is to hide completely the *C-ish* interace of *libuv* behind a graceful C++ API. Currently, no *uv_***_t* data structure is actually exposed by the library. +The basic idea is to hide completely the *C-ish* interace of *libuv* behind a graceful C++ API. Currently, no `uv_*_t` data structure is actually exposed by the library. Note that `uvw` stays true to the API of *libuv* and it doesn't add anything to its interface. For the same reason, users of the library must follow the same rules who are used to follow with *libuv*. -As an example, a *handle* should be initialized before any other operation and closed once it is no longer in use. +As an example, a *handle* should be initialized before any other operation and closed once it is no longer in use. -# Code Example +## Code Example ``` #include @@ -52,27 +52,129 @@ int main() { } ``` -# Motivation +## Motivation The main reason for which `uvw` has been written is the fact that it does not exist a valid C++ wrapper for *libuv*. That's all. -# Installation +# Build Instructions + +## Library `uvw` is a header-only library. -This means that include the `uvw.hpp` header or one of the other `uvw/*.hpp` headers is enough to use it. +This means that including the `uvw.hpp` header or one of the other `uvw/*.hpp` headers is enough to use it. It's a matter of adding the following line at the top of a file: #include -Then pass the proper `-I` argument to the compiler to add the `src` directory to the include paths. +Then pass the proper `-I` argument to the compiler to add the `src` directory to the include paths. +Note that users are demanded to correctly setup include directories and libraries search paths for *libuv*. -# API Reference +## Documentation -... Coming soon ... +### API Reference -# Tests +The documentation is based on [`doxygen`](http://www.stack.nl/~dimitri/doxygen/). To build it: -... Coming soon ... +* `$ cd build` +* `$ make docs` + +The API reference will be created in HTML format within the directory `build/docs/html`. +To navigate it with your favorite browser: + +* `$ cd build` +* `$ your_favorite_browser docs/html/index.html` + +### Crash Course + +There is only one rule when using `uvw`: always initialize the handles and close them. +Handles keep themselves alive until one closes them. Because of that, leaks are possible if users simply forget about a handle. +To be honest, initialization is performed under the hood and can be even passed over, as far as resources are created using the `Loop::handle` member method. +Thus the rule quickly become *always close your handles*. It's simple as calling the `close` member method on them. + +The first thing to do to use `uvw` is to create a loop. In case the default one is enough, it's easy as doing this: + + auto loop = uvw::Loop::getDefault(); + +Note that loop objects don't require to be explicitly closed, even if they offer the `close` member method if you want to do that. +Loops can be run using the `run`, `runOnce` and `runWait` member methods. Please refer to the documentation of *libuv* for further details. + +In order to create a handle and to bind it to the given loop, just do the following: + + auto tcp = loop.handle(); + +A tcp handle will be created and initialized, thus a shared pointer to that handle will be returned. +Users should check if pointers have been correctly initialized: in case of errors, they won't be. +Another way to create a handle is: + + auto tcp = Tcp::create(loop); + tcp->init(); + +Pretty annoying indeed. Using a loop is the recommended approach. + +Once a handle has been created, it will keep itself alive until one invoke the `close` member method on it. +To know what are the handles that are still alive and bound to a given loop, just do the following: + + loop.walk([](uvw::BaseHandle &){ /* application code here */ }); + +`BaseHandle` exposes a few methods and cannot be used to know what's the original type of the handle. +Anyway, it can be used to close the handle that origins from it. As an example, all the handles still opened can be easily closed as it follows: + + loop.walk([](uvw::BaseHandle &h){ h.close(); }); + +No need to keep track of them. + +To know what are the available handles, please refer the API reference. + +For `uvw` offers an event-based approach, handles are small event emitters to which listeners can be attached. +Attaching a listener to a handle is the reccomended way to be notified about changes. +Listeners must be callable objects of type `void(const EventType &, HandleType &)`, where: + +* `EventType` is the type of event for which they are designed +* `HandleType` is the type of the handle that has originated the event + +Note that, once more, there is no need to keep around references to the handles: they will pass themselves as an argument whenever an event is published. + +There exist two methods to attach an event to a handle: + +* `handle.once(listener)`: the listener will be automatically removed after the first event of the given type +* `handle.on(listener)`: to be used for long-running listeners + +Both of them return an object of type `HandleType::Connection` (as an example, `Tcp::Connection`). +A connection object can be used later as an argument to the `erase` member method of the handle to remove the listener. +There exists also the `clear` member method to drop all the listeners at once. + +The code below shows how to create a simple tcp server using `uvw`: + +``` +auto loop = uvw::Loop::getDefault(); +auto tcp = loop.handle(); + +tcp->on([](const uvw::ErrorEvent &, uvw::Tcp &srv) { /* something went wrong */ }); + +tcp->on([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutable { + std::shared_ptr client = srv.loop().handle(); + client->once([](const uvw::EndEvent &, uvw::Tcp &client) { client.close(); }); + client->on([](const uvw::DataEvent &, uvw::Tcp &) { /* data received */ }); + srv.accept(*client); + client->read(); +}); + +tcp->bind("127.0.0.1", 4242); +tcp->listen(); +``` + +API reference is the reccomended documentation for further details about handles and their methods. + +## Tests + +To compile and run the tests, `uvw` requires *libuv* and *googletest*. +Run the script `deps.sh` to download them. It is good practice to do it every time one pull the project. + +Then, to build the tests: + +* `$ cd build` +* `$ make` +* `$ make test` # Contributors