Merge pull request #5 from cynnyx/master
More and more requests, handles, and so on...
This commit is contained in:
commit
1bb837830a
22
README.md
22
README.md
@ -3,8 +3,8 @@
|
||||
**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.
|
||||
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*.
|
||||
The basic idea is to hide completely the *C-ish* interface 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 reasons, 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.
|
||||
|
||||
## Code Example
|
||||
@ -14,10 +14,10 @@ As an example, a *handle* should be initialized before any other operation and c
|
||||
#include <memory>
|
||||
|
||||
void listen(uvw::Loop &loop) {
|
||||
std::shared_ptr<uvw::Tcp> tcp = loop.handle<uvw::Tcp>();
|
||||
std::shared_ptr<uvw::Tcp> tcp = loop.resource<uvw::Tcp>();
|
||||
|
||||
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutable {
|
||||
std::shared_ptr<uvw::Tcp> client = srv.loop().handle<uvw::Tcp>();
|
||||
std::shared_ptr<uvw::Tcp> client = srv.loop().resource<uvw::Tcp>();
|
||||
|
||||
client->on<uvw::CloseEvent>([ptr = srv.shared_from_this()](const uvw::CloseEvent &, uvw::Tcp &) mutable { ptr->close(); });
|
||||
client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::Tcp &client) { client.close(); });
|
||||
@ -31,7 +31,7 @@ void listen(uvw::Loop &loop) {
|
||||
}
|
||||
|
||||
void conn(uvw::Loop &loop) {
|
||||
auto tcp = loop.handle<uvw::Tcp>();
|
||||
auto tcp = loop.resource<uvw::Tcp>();
|
||||
|
||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::Tcp &) { /* handle errors */ });
|
||||
|
||||
@ -90,7 +90,7 @@ To navigate it with your favorite browser:
|
||||
|
||||
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.
|
||||
To be honest, initialization is performed under the hood and can be even passed over, as far as resources are created using the `Loop::resource` member method.
|
||||
Thus the rule quickly becomes *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:
|
||||
@ -102,9 +102,9 @@ Loops can be run using the `run`, `runOnce` and `runWait` member methods. Please
|
||||
|
||||
In order to create a handle and to bind it to the given loop, just do the following:
|
||||
|
||||
auto tcp = loop.handle<uvw::Tcp>();
|
||||
auto tcp = loop.resource<uvw::Tcp>();
|
||||
|
||||
A tcp handle will be created and initialized, thus a shared pointer to that handle will be returned.
|
||||
A tcp handle will be created and initialized, thus a shared pointer to the 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:
|
||||
|
||||
@ -113,7 +113,7 @@ Another way to create a handle is:
|
||||
|
||||
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.
|
||||
Once a handle has been created, it will keep itself alive until one invokes 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 */ });
|
||||
@ -151,12 +151,12 @@ The code below shows how to create a simple tcp server using `uvw`:
|
||||
|
||||
```
|
||||
auto loop = uvw::Loop::getDefault();
|
||||
auto tcp = loop.handle<uvw::Tcp>();
|
||||
auto tcp = loop.resource<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>();
|
||||
std::shared_ptr<uvw::Tcp> client = srv.loop().resource<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);
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
#include "uvw/async.hpp"
|
||||
#include "uvw/check.hpp"
|
||||
#include "uvw/emitter.hpp"
|
||||
#include "uvw/event.hpp"
|
||||
#include "uvw/handle.hpp"
|
||||
#include "uvw/idle.hpp"
|
||||
#include "uvw/loop.hpp"
|
||||
#include "uvw/prepare.hpp"
|
||||
#include "uvw/request.hpp"
|
||||
#include "uvw/signal.hpp"
|
||||
#include "uvw/stream.hpp"
|
||||
#include "uvw/tcp.hpp"
|
||||
#include "uvw/timer.hpp"
|
||||
#include "uvw/tty.hpp"
|
||||
#include "uvw/util.hpp"
|
||||
#include "uvw/work.hpp"
|
||||
|
||||
@ -19,7 +19,7 @@ class Async final: public Handle<Async> {
|
||||
}
|
||||
|
||||
explicit Async(std::shared_ptr<Loop> ref)
|
||||
: Handle{HandleType<uv_async_t>{}, std::move(ref)}
|
||||
: Handle{ResourceType<uv_async_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
|
||||
@ -19,7 +19,7 @@ class Check final: public Handle<Check> {
|
||||
}
|
||||
|
||||
explicit Check(std::shared_ptr<Loop> ref)
|
||||
: Handle{HandleType<uv_check_t>{}, std::move(ref)}
|
||||
: Handle{ResourceType<uv_check_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
|
||||
@ -30,6 +30,7 @@ struct Event: BaseEvent {
|
||||
};
|
||||
|
||||
|
||||
struct AfterWorkEvent: Event<AfterWorkEvent> { };
|
||||
struct AsyncEvent: Event<AsyncEvent> { };
|
||||
struct CheckEvent: Event<CheckEvent> { };
|
||||
struct CloseEvent: Event<CloseEvent> { };
|
||||
@ -82,6 +83,7 @@ private:
|
||||
|
||||
struct TimerEvent: Event<TimerEvent> { };
|
||||
struct UninitializedEvent: Event<UninitializedEvent> { };
|
||||
struct WorkEvent: Event<WorkEvent> { };
|
||||
struct WriteEvent: Event<WriteEvent> { };
|
||||
|
||||
|
||||
|
||||
@ -1,124 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "emitter.hpp"
|
||||
#include "loop.hpp"
|
||||
#include "resource.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
template<typename>
|
||||
struct HandleType;
|
||||
|
||||
template<> struct HandleType<uv_async_t> { };
|
||||
template<> struct HandleType<uv_check_t> { };
|
||||
template<> struct HandleType<uv_idle_t> { };
|
||||
template<> struct HandleType<uv_prepare_t> { };
|
||||
template<> struct HandleType<uv_signal_t> { };
|
||||
template<> struct HandleType<uv_tcp_t> { };
|
||||
template<> struct HandleType<uv_timer_t> { };
|
||||
template<> struct HandleType<uv_tty_t> { };
|
||||
|
||||
|
||||
template<typename T>
|
||||
class Handle
|
||||
: public BaseHandle,
|
||||
public Emitter<T>,
|
||||
public std::enable_shared_from_this<T>
|
||||
{
|
||||
struct BaseWrapper {
|
||||
virtual ~BaseWrapper() = default;
|
||||
virtual void * get() const noexcept = 0;
|
||||
};
|
||||
|
||||
template<typename U>
|
||||
struct Wrapper: BaseWrapper {
|
||||
Wrapper(): handle{std::make_unique<U>()} { }
|
||||
void * get() const noexcept override { return handle.get(); }
|
||||
private:
|
||||
std::unique_ptr<U> handle;
|
||||
};
|
||||
|
||||
class Handle: public BaseHandle, public Resource<T> {
|
||||
static void closeCallback(uv_handle_t *handle) {
|
||||
Handle<T> &ref = *(static_cast<T*>(handle->data));
|
||||
ref.initialized = false;
|
||||
auto ptr = ref.shared_from_this();
|
||||
ptr->reset();
|
||||
ref.publish(CloseEvent{});
|
||||
ref.leak.reset();
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename U>
|
||||
explicit Handle(HandleType<U>, std::shared_ptr<Loop> ref)
|
||||
: Emitter<T>{},
|
||||
std::enable_shared_from_this<T>{},
|
||||
wrapper{std::make_unique<Wrapper<U>>()},
|
||||
pLoop{std::move(ref)},
|
||||
leak{nullptr},
|
||||
initialized{false}
|
||||
{
|
||||
this->template get<uv_handle_t>()->data = static_cast<T*>(this);
|
||||
}
|
||||
|
||||
uv_loop_t* parent() const noexcept { return pLoop->loop.get(); }
|
||||
|
||||
template<typename U>
|
||||
U* get() const noexcept { return reinterpret_cast<U*>(wrapper->get()); }
|
||||
using Resource<T>::Resource;
|
||||
|
||||
template<typename U, typename F, typename... Args>
|
||||
bool initialize(F &&f, Args&&... args) {
|
||||
bool ret = true;
|
||||
|
||||
if(!initialized) {
|
||||
auto err = std::forward<F>(f)(parent(), get<U>(), std::forward<Args>(args)...);
|
||||
if(!this->self()) {
|
||||
auto err = std::forward<F>(f)(this->parent(), this->template get<U>(), std::forward<Args>(args)...);
|
||||
|
||||
if(err) {
|
||||
this->publish(ErrorEvent{err});
|
||||
ret = false;
|
||||
} else {
|
||||
leak = this->shared_from_this();
|
||||
initialized = true;
|
||||
this->leak();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
auto invoke(F &&f, Args&&... args) {
|
||||
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
|
||||
return err;
|
||||
return this->self();
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~Handle() {
|
||||
static_assert(std::is_base_of<Handle<T>, T>::value, "!");
|
||||
bool active() const noexcept override {
|
||||
return !(uv_is_active(this->template get<uv_handle_t>()) == 0);
|
||||
}
|
||||
|
||||
Loop& loop() const noexcept { return *pLoop; }
|
||||
|
||||
bool active() const noexcept override { return !(uv_is_active(get<uv_handle_t>()) == 0); }
|
||||
bool closing() const noexcept override { return !(uv_is_closing(get<uv_handle_t>()) == 0); }
|
||||
|
||||
void reference() noexcept override { uv_ref(get<uv_handle_t>()); }
|
||||
void unreference() noexcept override { uv_unref(get<uv_handle_t>()); }
|
||||
bool referenced() const noexcept override { return !(uv_has_ref(get<uv_handle_t>()) == 0); }
|
||||
bool closing() const noexcept override {
|
||||
return !(uv_is_closing(this->template get<uv_handle_t>()) == 0);
|
||||
}
|
||||
|
||||
void close() noexcept override {
|
||||
if(!closing()) {
|
||||
uv_close(get<uv_handle_t>(), &Handle<T>::closeCallback);
|
||||
uv_close(this->template get<uv_handle_t>(), &Handle<T>::closeCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<BaseWrapper> wrapper;
|
||||
std::shared_ptr<Loop> pLoop;
|
||||
std::shared_ptr<void> leak;
|
||||
bool initialized;
|
||||
void reference() noexcept override {
|
||||
uv_ref(this->template get<uv_handle_t>());
|
||||
}
|
||||
|
||||
void unreference() noexcept override {
|
||||
uv_unref(this->template get<uv_handle_t>());
|
||||
}
|
||||
|
||||
bool referenced() const noexcept override {
|
||||
return !(uv_has_ref(this->template get<uv_handle_t>()) == 0);
|
||||
}
|
||||
|
||||
std::size_t size() const noexcept {
|
||||
return uv_handle_size(this->template get<uv_handle_t>()->type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ class Idle final: public Handle<Idle> {
|
||||
}
|
||||
|
||||
explicit Idle(std::shared_ptr<Loop> ref)
|
||||
: Handle{HandleType<uv_idle_t>{}, std::move(ref)}
|
||||
: Handle{ResourceType<uv_idle_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
|
||||
@ -26,7 +26,7 @@ public:
|
||||
|
||||
class Loop final: public Emitter<Loop>, public std::enable_shared_from_this<Loop> {
|
||||
template<typename>
|
||||
friend class Handle;
|
||||
friend class Resource;
|
||||
|
||||
using Deleter = std::function<void(uv_loop_t *)>;
|
||||
|
||||
@ -76,12 +76,19 @@ public:
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
std::shared_ptr<R> handle(Args&&... args) {
|
||||
std::enable_if_t<std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
|
||||
resource(Args&&... args) {
|
||||
auto ptr = R::create(shared_from_this(), std::forward<Args>(args)...);
|
||||
ptr = ptr->init() ? ptr : nullptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
std::enable_if_t<not std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
|
||||
resource(Args&&... args) {
|
||||
return R::create(shared_from_this(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void close() noexcept {
|
||||
auto err = uv_loop_close(loop.get());
|
||||
if(err) { publish(ErrorEvent{err}); }
|
||||
|
||||
@ -19,7 +19,7 @@ class Prepare final: public Handle<Prepare> {
|
||||
}
|
||||
|
||||
explicit Prepare(std::shared_ptr<Loop> ref)
|
||||
: Handle{HandleType<uv_prepare_t>{}, std::move(ref)}
|
||||
: Handle{ResourceType<uv_prepare_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "resource.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
template<uv_req_type>
|
||||
struct RequestType;
|
||||
|
||||
template<> struct RequestType<UV_CONNECT> { };
|
||||
template<> struct RequestType<UV_WRITE> { };
|
||||
template<> struct RequestType<UV_SHUTDOWN> { };
|
||||
template<> struct RequestType<UV_UDP_SEND> { };
|
||||
template<> struct RequestType<UV_FS> { };
|
||||
template<> struct RequestType<UV_WORK> { };
|
||||
template<> struct RequestType<UV_GETADDRINFO> { };
|
||||
template<> struct RequestType<UV_GETNAMEINFO> { };
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Request: T {
|
||||
// TODO room for a pointer to a memory pool and a better memory management
|
||||
class Request: public Resource<T> {
|
||||
protected:
|
||||
using Resource<T>::Resource;
|
||||
|
||||
public:
|
||||
void cancel() noexcept {
|
||||
invoke(&uv_cancel, this->template get<uv_req_t>());
|
||||
}
|
||||
|
||||
std::size_t size() const noexcept {
|
||||
return uv_req_size(this->template get<uv_req_t>()->type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
80
src/uvw/resource.hpp
Normal file
80
src/uvw/resource.hpp
Normal file
@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "emitter.hpp"
|
||||
#include "self.hpp"
|
||||
#include "loop.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
template<typename>
|
||||
struct ResourceType;
|
||||
|
||||
template<> struct ResourceType<uv_async_t> { };
|
||||
template<> struct ResourceType<uv_check_t> { };
|
||||
template<> struct ResourceType<uv_idle_t> { };
|
||||
template<> struct ResourceType<uv_prepare_t> { };
|
||||
template<> struct ResourceType<uv_signal_t> { };
|
||||
template<> struct ResourceType<uv_tcp_t> { };
|
||||
template<> struct ResourceType<uv_timer_t> { };
|
||||
template<> struct ResourceType<uv_tty_t> { };
|
||||
template<> struct ResourceType<uv_work_t> { };
|
||||
|
||||
|
||||
template<typename T>
|
||||
class Resource: public Emitter<T>, public Self<T> {
|
||||
struct BaseWrapper {
|
||||
virtual ~BaseWrapper() = default;
|
||||
virtual void * get() const noexcept = 0;
|
||||
};
|
||||
|
||||
template<typename U>
|
||||
struct Wrapper: BaseWrapper {
|
||||
Wrapper(): resource{std::make_unique<U>()} { }
|
||||
void * get() const noexcept override { return resource.get(); }
|
||||
private:
|
||||
std::unique_ptr<U> resource;
|
||||
};
|
||||
|
||||
protected:
|
||||
template<typename U>
|
||||
explicit Resource(ResourceType<U>, std::shared_ptr<Loop> ref)
|
||||
: Emitter<T>{},
|
||||
Self<T>{},
|
||||
wrapper{std::make_unique<Wrapper<U>>()},
|
||||
pLoop{std::move(ref)}
|
||||
{
|
||||
this->template get<U>()->data = static_cast<T*>(this);
|
||||
}
|
||||
|
||||
uv_loop_t* parent() const noexcept { return pLoop->loop.get(); }
|
||||
|
||||
template<typename U>
|
||||
U* get() const noexcept { return reinterpret_cast<U*>(wrapper->get()); }
|
||||
|
||||
template<typename F, typename... Args>
|
||||
auto invoke(F &&f, Args&&... args) {
|
||||
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
if(err) { Emitter<T>::publish(ErrorEvent{err}); }
|
||||
return err;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~Resource() {
|
||||
static_assert(std::is_base_of<Resource<T>, T>::value, "!");
|
||||
}
|
||||
|
||||
Loop& loop() const noexcept { return *pLoop; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<BaseWrapper> wrapper;
|
||||
std::shared_ptr<Loop> pLoop;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
21
src/uvw/self.hpp
Normal file
21
src/uvw/self.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Self: std::enable_shared_from_this<T> {
|
||||
void leak() noexcept { ptr = this->shared_from_this(); }
|
||||
void reset() noexcept { ptr.reset(); }
|
||||
bool self() const noexcept { return static_cast<bool>(ptr); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<void> ptr{nullptr};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@ -19,7 +19,7 @@ class Signal final: public Handle<Signal> {
|
||||
}
|
||||
|
||||
explicit Signal(std::shared_ptr<Loop> ref)
|
||||
: Handle{HandleType<uv_signal_t>{}, std::move(ref)}
|
||||
: Handle{ResourceType<uv_signal_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
|
||||
@ -37,6 +37,7 @@ class Stream: public Handle<T> {
|
||||
}
|
||||
|
||||
static void writeCallback(uv_write_t *req, int status) {
|
||||
// TODO migrate to Request (see request.hpp for further details)
|
||||
T &ref = *(static_cast<T*>(req->handle->data));
|
||||
if(status) { ref.publish(ErrorEvent{status}); }
|
||||
else { ref.publish(WriteEvent{}); }
|
||||
@ -44,6 +45,7 @@ class Stream: public Handle<T> {
|
||||
}
|
||||
|
||||
static void shutdownCallback(uv_shutdown_t *req, int status) {
|
||||
// TODO migrate to Request (see request.hpp for further details)
|
||||
T &ref = *(static_cast<T*>(req->handle->data));
|
||||
if(status) { ref.publish(ErrorEvent{status}); }
|
||||
else { ref.publish(ShutdownEvent{}); }
|
||||
@ -57,9 +59,9 @@ class Stream: public Handle<T> {
|
||||
|
||||
protected:
|
||||
template<typename U>
|
||||
Stream(HandleType<U> rt, std::shared_ptr<Loop> ref)
|
||||
: Handle<T>{std::move(rt),
|
||||
std::move(ref)},
|
||||
Stream(ResourceType<U> rt, std::shared_ptr<Loop> ref)
|
||||
: Handle<T>{std::move(rt), std::move(ref)},
|
||||
// TODO migrate to Request (see request.hpp for further details)
|
||||
sdown{std::make_unique<uv_shutdown_t>()}
|
||||
{ }
|
||||
|
||||
@ -86,6 +88,7 @@ public:
|
||||
|
||||
void write(char *data, ssize_t length) {
|
||||
uv_buf_t bufs[] = { uv_buf_init(data, length) };
|
||||
// TODO migrate to Request (see request.hpp for further details)
|
||||
uv_write_t *req = new uv_write_t;
|
||||
|
||||
auto err = uv_write(req, this->template get<uv_stream_t>(), bufs, 1, &Stream<T>::writeCallback);
|
||||
@ -125,6 +128,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO migrate to Request (see request.hpp for further details)
|
||||
std::unique_ptr<uv_shutdown_t> sdown;
|
||||
};
|
||||
|
||||
|
||||
@ -16,13 +16,15 @@ namespace uvw {
|
||||
|
||||
class Tcp final: public Stream<Tcp> {
|
||||
static void connectCallback(uv_connect_t *req, int status) {
|
||||
// TODO migrate to Request (see request.hpp for further details)
|
||||
Tcp &tcp = *(static_cast<Tcp*>(req->handle->data));
|
||||
if(status) { tcp.publish(ErrorEvent{status}); }
|
||||
else { tcp.publish(ConnectEvent{}); }
|
||||
}
|
||||
|
||||
explicit Tcp(std::shared_ptr<Loop> ref)
|
||||
: Stream{HandleType<uv_tcp_t>{}, std::move(ref)},
|
||||
// TODO migrate to Request (see request.hpp for further details)
|
||||
: Stream{ResourceType<uv_tcp_t>{}, std::move(ref)},
|
||||
conn{std::make_unique<uv_connect_t>()}
|
||||
{ }
|
||||
|
||||
@ -112,6 +114,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO migrate to Request (see request.hpp for further details)
|
||||
std::unique_ptr<uv_connect_t> conn;
|
||||
};
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ class Timer final: public Handle<Timer> {
|
||||
}
|
||||
|
||||
explicit Timer(std::shared_ptr<Loop> ref)
|
||||
: Handle{HandleType<uv_timer_t>{}, std::move(ref)}
|
||||
: Handle{ResourceType<uv_timer_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
|
||||
@ -31,7 +31,7 @@ class TTY final: public Stream<TTY> {
|
||||
explicit TTY(std::shared_ptr<Loop> ref,
|
||||
details::FileDescriptor<FD>,
|
||||
bool readable)
|
||||
: Stream{HandleType<uv_tty_t>{}, std::move(ref)},
|
||||
: Stream{ResourceType<uv_tty_t>{}, std::move(ref)},
|
||||
fd{FD},
|
||||
rw{readable ? 1 : 0}
|
||||
{ }
|
||||
|
||||
47
src/uvw/work.hpp
Normal file
47
src/uvw/work.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <uv.h>
|
||||
#include "event.hpp"
|
||||
#include "request.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
|
||||
namespace uvw {
|
||||
|
||||
|
||||
class Work final: public Request<Work> {
|
||||
static void workCallback(uv_work_t *req) {
|
||||
Work &work = *(static_cast<Work*>(req->data));
|
||||
work.publish(WorkEvent{});
|
||||
}
|
||||
|
||||
static void afterWorkCallback(uv_work_t *req, int status) {
|
||||
Work &work = *(static_cast<Work*>(req->data));
|
||||
auto ptr = work.shared_from_this();
|
||||
ptr->reset();
|
||||
if(status) { work.publish(ErrorEvent{status}); }
|
||||
else { work.publish(AfterWorkEvent{}); }
|
||||
}
|
||||
|
||||
explicit Work(std::shared_ptr<Loop> ref)
|
||||
: Request{ResourceType<uv_work_t>{}, std::move(ref)}
|
||||
{ }
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
static std::shared_ptr<Work> create(Args&&... args) {
|
||||
return std::shared_ptr<Work>{new Work{std::forward<Args>(args)...}};
|
||||
}
|
||||
|
||||
void queue() noexcept {
|
||||
if(0 == invoke(&uv_queue_work, parent(), get<uv_work_t>(), &workCallback, &afterWorkCallback)) {
|
||||
leak();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
|
||||
void listen(uvw::Loop &loop) {
|
||||
std::shared_ptr<uvw::Tcp> tcp = loop.handle<uvw::Tcp>();
|
||||
std::shared_ptr<uvw::Tcp> tcp = loop.resource<uvw::Tcp>();
|
||||
|
||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::Tcp &) {
|
||||
std::cout << "error " << std::endl;
|
||||
@ -15,7 +15,7 @@ void listen(uvw::Loop &loop) {
|
||||
tcp->once<uvw::ListenEvent>([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutable {
|
||||
std::cout << "listen" << std::endl;
|
||||
|
||||
std::shared_ptr<uvw::Tcp> client = srv.loop().handle<uvw::Tcp>();
|
||||
std::shared_ptr<uvw::Tcp> client = srv.loop().resource<uvw::Tcp>();
|
||||
|
||||
client->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::Tcp &) {
|
||||
std::cout << "error " << std::endl;
|
||||
@ -62,7 +62,7 @@ void listen(uvw::Loop &loop) {
|
||||
|
||||
|
||||
void conn(uvw::Loop &loop) {
|
||||
auto tcp = loop.handle<uvw::Tcp>();
|
||||
auto tcp = loop.resource<uvw::Tcp>();
|
||||
|
||||
tcp->on<uvw::ErrorEvent>([](const uvw::ErrorEvent &, uvw::Tcp &) {
|
||||
std::cout << "error " << std::endl;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user