WIP: Stream/Connection

This commit is contained in:
Michele Caini 2016-06-21 17:28:49 +02:00
parent b42f18cbf4
commit ed058c2148
8 changed files with 109 additions and 77 deletions

View File

@ -20,13 +20,14 @@ public:
using Callback = std::function<void(UVWError)>;
explicit Check(std::shared_ptr<Loop> ref)
: Resource{HandleType<uv_check_t>{}, ref}
: Resource{HandleType<uv_check_t>{}, std::move(ref)}
{
uv_check_init(parent(), get<uv_check_t>());
initialized = (uv_check_init(parent(), get<uv_check_t>()) == 0);
}
void start(Callback cb) noexcept {
callback = cb;
get<uv_check_t>()->data = this;
auto err = uv_check_start(get<uv_check_t>(), &proto);
if(err) {
@ -34,10 +35,13 @@ public:
}
}
bool stop() noexcept { return (uv_check_stop(get<uv_check_t>()) == 0); }
UVWError stop() noexcept { return UVWError{uv_check_stop(get<uv_check_t>())}; }
explicit operator bool() { return initialized; }
private:
Callback callback;
bool initialized;
};

View File

@ -33,7 +33,8 @@ public:
public:
explicit operator bool() const noexcept { return !(ec == 0); }
const char* str() const noexcept { return uv_strerror(ec); }
operator const char *() const noexcept { return uv_strerror(ec); }
operator int() const noexcept { return ec; }
private:
int ec;

View File

@ -4,6 +4,7 @@
#include <new>
#include <memory>
#include <utility>
#include <type_traits>
#include <uv.h>
#include "error.hpp"
@ -17,6 +18,9 @@ class Loop;
template<typename R>
class Handle {
template<typename>
friend class Handle;
friend class Loop;
template<typename... Args>
@ -24,19 +28,30 @@ class Handle {
: res{std::make_shared<R>(std::move(l), std::forward<Args>(args)...)}
{ }
explicit constexpr Handle(std::shared_ptr<R> ptr): res{std::move(ptr)} { }
public:
explicit constexpr Handle(): res{} { }
constexpr Handle(const Handle &other): res{other.res} { }
constexpr Handle(Handle &&other): res{std::move(other.res)} { }
template<typename T, std::enable_if_t<std::is_base_of<R, T>::value>* = nullptr>
constexpr Handle(const Handle<T> &other): res{other.res} { }
constexpr void operator=(const Handle &other) { res = other.res; }
constexpr void operator=(Handle &&other) { res = std::move(other.res); }
template<typename T, std::enable_if_t<std::is_base_of<R, T>::value>* = nullptr>
constexpr Handle(Handle<T> &&other): res{std::move(other.res)} { }
constexpr explicit operator bool() { return static_cast<bool>(res); }
template<typename T, std::enable_if_t<std::is_base_of<R, T>::value>* = nullptr>
constexpr void operator=(const Handle<T> &other) { res = other.res; }
template<typename T, std::enable_if_t<std::is_base_of<R, T>::value>* = nullptr>
constexpr void operator=(Handle<T> &&other) { res = std::move(other.res); }
constexpr explicit operator bool() const { return static_cast<bool>(res); }
constexpr operator R&() noexcept { return *res; }
operator const R&() const noexcept { return *res; }
constexpr operator const R&() const noexcept { return *res; }
template<typename T, std::enable_if_t<std::is_base_of<T, R>::value>* = nullptr>
constexpr operator Handle<T>() { return Handle<T>{res}; }
private:
std::shared_ptr<R> res;
@ -51,11 +66,11 @@ class Loop final: public std::enable_shared_from_this<Loop> {
Loop(std::unique_ptr<uv_loop_t, Deleter> ptr): loop{std::move(ptr)} { }
public:
static std::shared_ptr<Loop> create(bool def = true) {
static std::shared_ptr<Loop> create() {
auto ptr = std::unique_ptr<uv_loop_t, Deleter>{new uv_loop_t, [](uv_loop_t *l){ delete l; }};
auto loop = std::shared_ptr<Loop>(new Loop{std::move(ptr)});
if(!uv_loop_init(loop->loop.get())) {
if(uv_loop_init(loop->loop.get())) {
loop = nullptr;
}
@ -98,8 +113,8 @@ public:
return Handle<R>{shared_from_this(), std::forward<Args>(args)...};
}
bool close() noexcept {
return (uv_loop_close(loop.get()) == 0);
UVWError close() noexcept {
return UVWError{uv_loop_close(loop.get())};
}
bool run() noexcept {

View File

@ -24,28 +24,13 @@ protected:
template<typename T>
explicit Resource(HandleType<T>, std::shared_ptr<Loop> r)
: ref{std::move(r)}, res{std::make_shared<T>()}
{
get<uv_handle_t>()->data = this;
}
{ }
template<typename T>
T* get() const noexcept { return reinterpret_cast<T*>(res.get()); }
uv_loop_t* parent() const noexcept { return ref->loop.get(); }
template<typename T, typename... Args>
Handle<T> spawn(Args&&... args) {
auto h = ref->handle<T>(std::forward<Args>(args)...);
static_cast<T&>(h).res = res;
return h;
}
template<typename T>
void reset() {
res = std::make_shared<T>();
get<uv_handle_t>()->data = this;
}
public:
using Callback = std::function<void(UVWError)>;
@ -62,6 +47,7 @@ public:
void close(Callback cb) noexcept {
callback = cb;
get<uv_handle_t>()->data = this;
uv_close(get<uv_handle_t>(), &proto);
}

View File

@ -9,47 +9,44 @@
namespace uvw {
class Connection final: public Resource {
// TODO proxy on a stream client
public:
explicit Connection(std::shared_ptr<Loop> ref, uv_stream_t *srv)
: Resource{HandleType<uv_stream_t>{}, ref}
{
// TODO initialized... HOW????
uv_tcp_init(parent(), get<uv_tcp_t>());get<uv_stream_t>()
auto err = uv_accept(srv, get<uv_stream_t>());
}
};
class Stream: public Resource {
static void protoListen(uv_stream_t* srv, int status) {
// TODO invoke accept
Stream &stream = *(static_cast<Stream*>(srv->data));
if(status) {
stream.listenCallback(UVWError{status}, Handle<Connection>{});
stream.listenCallback(UVWError{status});
} else {
stream.listenCallback(UVWError{}, loop()->handle(get<uv_stream_t>()));
stream.tryAccept();
}
}
void tryAccept() const noexcept {
Handle<Stream> handle = accept();
if(handle) {
// TODO invoke cb with handle
} else {
// TODO invoke cb with error
}
}
virtual Handle<Stream> accept() const noexcept = 0;
protected:
using Resource::Resource;
public:
using CallbackListen = std::function<void(UVWError, Handle<Connection>)>;
using CallbackListen = std::function<void(UVWError)>;
// TODO shutdown
void listen(int backlog, CallbackListen cb) noexcept {
listenCallback = cb;
get<uv_stream_t>()->data = this;
auto err = uv_listen(get<uv_stream_t>(), backlog, &protoListen);
if(err) {
listenCallback(UVWError{err}, Handle<Connection>{});
listenCallback(UVWError{err});
}
}

View File

@ -16,45 +16,55 @@ namespace uvw {
class Tcp final: public Stream {
static void protoConnect(uv_connect_t* req, int status) {
Tcp &tcp = *(static_cast<Tcp*>(req->handle->data));
Tcp *tcp = static_cast<Tcp*>(req->handle->data);
tcp->connCb(UVWError{status});
tcp->connCb = nullptr;
}
if(status) {
tcp.connCb(UVWError{status}, Handle<Connection>{});
} else {
auto h = tcp.spawn<Connection>();
tcp.reset<uv_tcp_t>();
uv_tcp_init(tcp.parent(), tcp.get<uv_tcp_t>());
tcp.connCb(UVWError{}, h);
Handle<Stream> accept() const noexcept override {
auto handle = loop()->handle<Tcp>(get<uv_stream_t>());
if(!handle || !static_cast<Tcp&>(handle)) {
handle = Handle<Tcp>{};
}
return handle;
}
public:
using Time = std::chrono::duration<uint64_t>;
using CallbackConnect = std::function<void(UVWError, Handle<Connection>)>;
using CallbackConnect = std::function<void(UVWError)>;
enum { IPv4, IPv6 };
explicit Tcp(std::shared_ptr<Loop> ref)
: Stream{HandleType<uv_tcp_t>{}, ref},
: Stream{HandleType<uv_tcp_t>{}, std::move(ref)},
conn{std::make_unique<uv_connect_t>()}
{
uv_tcp_init(parent(), get<uv_tcp_t>());
initialized = (uv_tcp_init(parent(), get<uv_tcp_t>()) == 0);
}
bool noDelay(bool value = false) noexcept {
return (uv_tcp_nodelay(get<uv_tcp_t>(), value ? 1 : 0) == 0);
explicit Tcp(std::shared_ptr<Loop> ref, uv_stream_t *srv): Tcp{ref} {
initialized = initialized || (uv_accept(srv, get<uv_stream_t>()) == 0);
}
bool keepAlive(bool enable = false, Time time = Time{0}) noexcept {
return (uv_tcp_keepalive(get<uv_tcp_t>(), enable ? 1 : 0, time.count()) == 0);
UVWError noDelay(bool value = false) noexcept {
return UVWError{uv_tcp_nodelay(get<uv_tcp_t>(), value ? 1 : 0)};
}
UVWError keepAlive(bool enable = false, Time time = Time{0}) noexcept {
return UVWError{uv_tcp_keepalive(get<uv_tcp_t>(), enable ? 1 : 0, time.count())};
}
template<int>
void connect(std::string, int, CallbackConnect) noexcept;
explicit operator bool() { return initialized; }
private:
std::unique_ptr<uv_connect_t> conn;
CallbackConnect connCb;
bool initialized;
};
@ -62,11 +72,12 @@ template<>
void Tcp::connect<Tcp::IPv4>(std::string ip, int port, CallbackConnect cb) noexcept {
sockaddr_in addr;
uv_ip4_addr(ip.c_str(), port, &addr);
connCb = cb;
connCb = std::move(cb);
get<uv_tcp_t>()->data = this;
auto err = uv_tcp_connect(conn.get(), get<uv_tcp_t>(), reinterpret_cast<const sockaddr*>(&addr), &protoConnect);
if(err) {
connCb(UVWError{err}, Handle<Connection>{});
connCb(UVWError{err});
}
}
@ -75,11 +86,12 @@ template<>
void Tcp::connect<Tcp::IPv6>(std::string ip, int port, CallbackConnect cb) noexcept {
sockaddr_in6 addr;
uv_ip6_addr(ip.c_str(), port, &addr);
connCb = cb;
connCb = std::move(cb);
get<uv_tcp_t>()->data = this;
auto err = uv_tcp_connect(conn.get(), get<uv_tcp_t>(), reinterpret_cast<const sockaddr*>(&addr), &protoConnect);
if(err) {
connCb(UVWError{err}, Handle<Connection>{});
connCb(UVWError{err});
}
}

View File

@ -22,13 +22,14 @@ public:
using Callback = std::function<void(UVWError)>;
explicit Timer(std::shared_ptr<Loop> ref)
: Resource{HandleType<uv_timer_t>{}, ref}
: Resource{HandleType<uv_timer_t>{}, std::move(ref)}
{
uv_timer_init(parent(), get<uv_timer_t>());
initialized = (uv_timer_init(parent(), get<uv_timer_t>()) == 0);
}
void start(const Time &timeout, const Time &rep, Callback cb) noexcept {
callback = cb;
get<uv_timer_t>()->data = this;
auto err = uv_timer_start(get<uv_timer_t>(), &proto, timeout.count(), rep.count());
if(err) {
@ -36,13 +37,16 @@ public:
}
}
void stop() noexcept { uv_timer_stop(get<uv_timer_t>()); }
void again() noexcept { uv_timer_again(get<uv_timer_t>()); }
UVWError stop() noexcept { return UVWError{uv_timer_stop(get<uv_timer_t>())}; }
UVWError again() noexcept { return UVWError{uv_timer_again(get<uv_timer_t>())}; }
void repeat(const Time &rep) noexcept { uv_timer_set_repeat(get<uv_timer_t>(), rep.count()); }
Time repeat() const noexcept { return Time{uv_timer_get_repeat(get<uv_timer_t>())}; }
explicit operator bool() { return initialized; }
private:
Callback callback;
bool initialized;
};

View File

@ -4,14 +4,27 @@
void f(uvw::Loop &loop) {
uvw::Handle<uvw::Tcp> handle = loop.handle<uvw::Tcp>();
auto cb = [h = handle](uvw::UVWError err, uvw::Handle<uvw::Connection> conn){ std::cout << "---" << ((bool)err) << std::endl; };
auto cb = [handle](uvw::UVWError err) mutable {
std::cout << "---" << ((bool)err) << std::endl;
uvw::Tcp &tcp = handle;
tcp.close([handle](uvw::UVWError err) mutable {
std::cout << "---" << ((bool)err) << std::endl;
handle = uvw::Handle<uvw::Tcp>{};
});
};
uvw::Tcp &tcp = handle;
tcp.connect<uvw::Tcp::IPv4>(std::string{"127.0.0.1"}, 80, cb);
}
int main() {
void g() {
auto loop = uvw::Loop::getDefault();
f(*loop);
loop->runWait();
loop->run();
loop = nullptr;
}
int main() {
g();
}