Update README.md
This commit is contained in:
parent
f5a269832f
commit
87fca8e55b
124
README.md
124
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 <uvw.hpp>
|
||||
@ -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 <uvw.hpp>
|
||||
|
||||
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<uvw::Tcp>();
|
||||
|
||||
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<EventType>(listener)`: the listener will be automatically removed after the first event of the given type
|
||||
* `handle.on<EventType>(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<uvw::Tcp>();
|
||||
|
||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::Tcp &srv) { /* something went wrong */ });
|
||||
|
||||
tcp->on<uvw::ListenEvent>([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutable {
|
||||
std::shared_ptr<uvw::Tcp> client = srv.loop().handle<uvw::Tcp>();
|
||||
client->once<uvw::EndEvent>([](const uvw::EndEvent &, uvw::Tcp &client) { client.close(); });
|
||||
client->on<uvw::DataEvent>([](const uvw::DataEvent &, uvw::Tcp &) { /* data received */ });
|
||||
srv.accept(*client);
|
||||
client->read();
|
||||
});
|
||||
|
||||
tcp->bind<uvw::Tcp::IPv4>("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
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user