From ed058c2148b1091ffa9ed9528f7b976abe1ee4e2 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Tue, 21 Jun 2016 17:28:49 +0200 Subject: [PATCH] WIP: Stream/Connection --- src/uvw/check.hpp | 10 ++++++--- src/uvw/error.hpp | 3 ++- src/uvw/loop.hpp | 35 ++++++++++++++++++++++--------- src/uvw/resource.hpp | 18 ++-------------- src/uvw/stream.hpp | 37 +++++++++++++++----------------- src/uvw/tcp.hpp | 50 +++++++++++++++++++++++++++----------------- src/uvw/timer.hpp | 12 +++++++---- test/main.cpp | 21 +++++++++++++++---- 8 files changed, 109 insertions(+), 77 deletions(-) diff --git a/src/uvw/check.hpp b/src/uvw/check.hpp index 3dc80e1a..724e5f93 100644 --- a/src/uvw/check.hpp +++ b/src/uvw/check.hpp @@ -20,13 +20,14 @@ public: using Callback = std::function; explicit Check(std::shared_ptr ref) - : Resource{HandleType{}, ref} + : Resource{HandleType{}, std::move(ref)} { - uv_check_init(parent(), get()); + initialized = (uv_check_init(parent(), get()) == 0); } void start(Callback cb) noexcept { callback = cb; + get()->data = this; auto err = uv_check_start(get(), &proto); if(err) { @@ -34,10 +35,13 @@ public: } } - bool stop() noexcept { return (uv_check_stop(get()) == 0); } + UVWError stop() noexcept { return UVWError{uv_check_stop(get())}; } + + explicit operator bool() { return initialized; } private: Callback callback; + bool initialized; }; diff --git a/src/uvw/error.hpp b/src/uvw/error.hpp index d28d6753..6ced2e63 100644 --- a/src/uvw/error.hpp +++ b/src/uvw/error.hpp @@ -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; diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index 3bc7f16c..6beb86cd 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "error.hpp" @@ -17,6 +18,9 @@ class Loop; template class Handle { + template + friend class Handle; + friend class Loop; template @@ -24,19 +28,30 @@ class Handle { : res{std::make_shared(std::move(l), std::forward(args)...)} { } + explicit constexpr Handle(std::shared_ptr 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::value>* = nullptr> + constexpr Handle(const Handle &other): res{other.res} { } - constexpr void operator=(const Handle &other) { res = other.res; } - constexpr void operator=(Handle &&other) { res = std::move(other.res); } + template::value>* = nullptr> + constexpr Handle(Handle &&other): res{std::move(other.res)} { } - constexpr explicit operator bool() { return static_cast(res); } + template::value>* = nullptr> + constexpr void operator=(const Handle &other) { res = other.res; } + + template::value>* = nullptr> + constexpr void operator=(Handle &&other) { res = std::move(other.res); } + + constexpr explicit operator bool() const { return static_cast(res); } constexpr operator R&() noexcept { return *res; } - operator const R&() const noexcept { return *res; } + constexpr operator const R&() const noexcept { return *res; } + + template::value>* = nullptr> + constexpr operator Handle() { return Handle{res}; } private: std::shared_ptr res; @@ -51,11 +66,11 @@ class Loop final: public std::enable_shared_from_this { Loop(std::unique_ptr ptr): loop{std::move(ptr)} { } public: - static std::shared_ptr create(bool def = true) { + static std::shared_ptr create() { auto ptr = std::unique_ptr{new uv_loop_t, [](uv_loop_t *l){ delete l; }}; auto loop = std::shared_ptr(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{shared_from_this(), std::forward(args)...}; } - bool close() noexcept { - return (uv_loop_close(loop.get()) == 0); + UVWError close() noexcept { + return UVWError{uv_loop_close(loop.get())}; } bool run() noexcept { diff --git a/src/uvw/resource.hpp b/src/uvw/resource.hpp index 63d8471a..62a3bc37 100644 --- a/src/uvw/resource.hpp +++ b/src/uvw/resource.hpp @@ -24,28 +24,13 @@ protected: template explicit Resource(HandleType, std::shared_ptr r) : ref{std::move(r)}, res{std::make_shared()} - { - get()->data = this; - } + { } template T* get() const noexcept { return reinterpret_cast(res.get()); } uv_loop_t* parent() const noexcept { return ref->loop.get(); } - template - Handle spawn(Args&&... args) { - auto h = ref->handle(std::forward(args)...); - static_cast(h).res = res; - return h; - } - - template - void reset() { - res = std::make_shared(); - get()->data = this; - } - public: using Callback = std::function; @@ -62,6 +47,7 @@ public: void close(Callback cb) noexcept { callback = cb; + get()->data = this; uv_close(get(), &proto); } diff --git a/src/uvw/stream.hpp b/src/uvw/stream.hpp index 605fb4ff..0f994b83 100644 --- a/src/uvw/stream.hpp +++ b/src/uvw/stream.hpp @@ -9,47 +9,44 @@ namespace uvw { -class Connection final: public Resource { - // TODO proxy on a stream client - -public: - explicit Connection(std::shared_ptr ref, uv_stream_t *srv) - : Resource{HandleType{}, ref} - { - // TODO initialized... HOW???? - uv_tcp_init(parent(), get());get() - auto err = uv_accept(srv, get()); - } -}; - - class Stream: public Resource { static void protoListen(uv_stream_t* srv, int status) { - // TODO invoke accept - Stream &stream = *(static_cast(srv->data)); if(status) { - stream.listenCallback(UVWError{status}, Handle{}); + stream.listenCallback(UVWError{status}); } else { - stream.listenCallback(UVWError{}, loop()->handle(get())); + stream.tryAccept(); } } + void tryAccept() const noexcept { + Handle handle = accept(); + + if(handle) { + // TODO invoke cb with handle + } else { + // TODO invoke cb with error + } + } + + virtual Handle accept() const noexcept = 0; + protected: using Resource::Resource; public: - using CallbackListen = std::function)>; + using CallbackListen = std::function; // TODO shutdown void listen(int backlog, CallbackListen cb) noexcept { listenCallback = cb; + get()->data = this; auto err = uv_listen(get(), backlog, &protoListen); if(err) { - listenCallback(UVWError{err}, Handle{}); + listenCallback(UVWError{err}); } } diff --git a/src/uvw/tcp.hpp b/src/uvw/tcp.hpp index 9ea13f0c..95e624e1 100644 --- a/src/uvw/tcp.hpp +++ b/src/uvw/tcp.hpp @@ -16,45 +16,55 @@ namespace uvw { class Tcp final: public Stream { static void protoConnect(uv_connect_t* req, int status) { - Tcp &tcp = *(static_cast(req->handle->data)); + Tcp *tcp = static_cast(req->handle->data); + tcp->connCb(UVWError{status}); + tcp->connCb = nullptr; + } - if(status) { - tcp.connCb(UVWError{status}, Handle{}); - } else { - auto h = tcp.spawn(); - tcp.reset(); - uv_tcp_init(tcp.parent(), tcp.get()); - tcp.connCb(UVWError{}, h); + Handle accept() const noexcept override { + auto handle = loop()->handle(get()); + + if(!handle || !static_cast(handle)) { + handle = Handle{}; } + + return handle; } public: using Time = std::chrono::duration; - using CallbackConnect = std::function)>; + using CallbackConnect = std::function; enum { IPv4, IPv6 }; explicit Tcp(std::shared_ptr ref) - : Stream{HandleType{}, ref}, + : Stream{HandleType{}, std::move(ref)}, conn{std::make_unique()} { - uv_tcp_init(parent(), get()); + initialized = (uv_tcp_init(parent(), get()) == 0); } - bool noDelay(bool value = false) noexcept { - return (uv_tcp_nodelay(get(), value ? 1 : 0) == 0); + explicit Tcp(std::shared_ptr ref, uv_stream_t *srv): Tcp{ref} { + initialized = initialized || (uv_accept(srv, get()) == 0); } - bool keepAlive(bool enable = false, Time time = Time{0}) noexcept { - return (uv_tcp_keepalive(get(), enable ? 1 : 0, time.count()) == 0); + UVWError noDelay(bool value = false) noexcept { + return UVWError{uv_tcp_nodelay(get(), value ? 1 : 0)}; + } + + UVWError keepAlive(bool enable = false, Time time = Time{0}) noexcept { + return UVWError{uv_tcp_keepalive(get(), enable ? 1 : 0, time.count())}; } template void connect(std::string, int, CallbackConnect) noexcept; + explicit operator bool() { return initialized; } + private: std::unique_ptr conn; CallbackConnect connCb; + bool initialized; }; @@ -62,11 +72,12 @@ template<> void Tcp::connect(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()->data = this; auto err = uv_tcp_connect(conn.get(), get(), reinterpret_cast(&addr), &protoConnect); if(err) { - connCb(UVWError{err}, Handle{}); + connCb(UVWError{err}); } } @@ -75,11 +86,12 @@ template<> void Tcp::connect(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()->data = this; auto err = uv_tcp_connect(conn.get(), get(), reinterpret_cast(&addr), &protoConnect); if(err) { - connCb(UVWError{err}, Handle{}); + connCb(UVWError{err}); } } diff --git a/src/uvw/timer.hpp b/src/uvw/timer.hpp index d97ca38c..a62b6601 100644 --- a/src/uvw/timer.hpp +++ b/src/uvw/timer.hpp @@ -22,13 +22,14 @@ public: using Callback = std::function; explicit Timer(std::shared_ptr ref) - : Resource{HandleType{}, ref} + : Resource{HandleType{}, std::move(ref)} { - uv_timer_init(parent(), get()); + initialized = (uv_timer_init(parent(), get()) == 0); } void start(const Time &timeout, const Time &rep, Callback cb) noexcept { callback = cb; + get()->data = this; auto err = uv_timer_start(get(), &proto, timeout.count(), rep.count()); if(err) { @@ -36,13 +37,16 @@ public: } } - void stop() noexcept { uv_timer_stop(get()); } - void again() noexcept { uv_timer_again(get()); } + UVWError stop() noexcept { return UVWError{uv_timer_stop(get())}; } + UVWError again() noexcept { return UVWError{uv_timer_again(get())}; } void repeat(const Time &rep) noexcept { uv_timer_set_repeat(get(), rep.count()); } Time repeat() const noexcept { return Time{uv_timer_get_repeat(get())}; } + explicit operator bool() { return initialized; } + private: Callback callback; + bool initialized; }; diff --git a/test/main.cpp b/test/main.cpp index 4822ffcd..967e2e5b 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -4,14 +4,27 @@ void f(uvw::Loop &loop) { uvw::Handle handle = loop.handle(); - auto cb = [h = handle](uvw::UVWError err, uvw::Handle 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 &tcp = handle; tcp.connect(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(); }