From 09acc1accf87cbe968ff58173ea42f6464a94200 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Fri, 1 Jul 2016 16:18:51 +0200 Subject: [PATCH] WIP: requests + refactoring --- src/uvw.hpp | 2 +- src/uvw/check.hpp | 16 ++++---- src/uvw/event.hpp | 8 ++++ src/uvw/handle.hpp | 92 +++++++++++++++++++++++++++---------------- src/uvw/idle.hpp | 17 +++----- src/uvw/loop.hpp | 4 +- src/uvw/prepare.hpp | 17 +++----- src/uvw/request.hpp | 29 ++++++++++++++ src/uvw/resource.hpp | 44 --------------------- src/uvw/stream.hpp | 94 +++++++++++++++++++++++++++----------------- src/uvw/tcp.hpp | 12 +++--- src/uvw/timer.hpp | 17 +++----- src/uvw/util.hpp | 29 ++++++++++++++ test/main.cpp | 15 +++++-- 14 files changed, 231 insertions(+), 165 deletions(-) create mode 100644 src/uvw/request.hpp delete mode 100644 src/uvw/resource.hpp diff --git a/src/uvw.hpp b/src/uvw.hpp index dfba0eb4..6743a01e 100644 --- a/src/uvw.hpp +++ b/src/uvw.hpp @@ -5,7 +5,7 @@ #include "uvw/idle.hpp" #include "uvw/loop.hpp" #include "uvw/prepare.hpp" -#include "uvw/resource.hpp" +#include "uvw/request.hpp" #include "uvw/self.hpp" #include "uvw/stream.hpp" #include "uvw/tcp.hpp" diff --git a/src/uvw/check.hpp b/src/uvw/check.hpp index d5523064..a2df6bc3 100644 --- a/src/uvw/check.hpp +++ b/src/uvw/check.hpp @@ -17,11 +17,7 @@ class Check final: public Handle { check.publish(CheckEvent{}); } - explicit Check(std::shared_ptr ref) - : Handle{ResourceType{}, std::move(ref)} - { - initialized = (uv_check_init(parent(), get()) == 0); - } + using Handle::Handle; public: template @@ -29,9 +25,13 @@ public: return std::shared_ptr{new Check{std::forward(args)...}}; } + bool init() { + return Handle::init(&uv_check_init); + } + void start() { using CBF = CallbackFactory; - auto func = CBF::create<&Check::startCallback>(*this); + auto func = &CBF::template proto<&Check::startCallback>; auto err = uv_check_start(get(), func); if(err) publish(ErrorEvent{err}); } @@ -41,10 +41,8 @@ public: if(err) publish(ErrorEvent{err}); } - explicit operator bool() const noexcept { return initialized; } - private: - bool initialized; + bool initialized = false; }; diff --git a/src/uvw/event.hpp b/src/uvw/event.hpp index 7529a353..e642dc2b 100644 --- a/src/uvw/event.hpp +++ b/src/uvw/event.hpp @@ -32,6 +32,12 @@ struct CheckEvent: Event { }; struct CloseEvent: Event { }; struct ConnectEvent: Event { }; +struct DataEvent: Event { + Buffer buffer{}; +}; + +struct EndEvent: Event { }; + struct ErrorEvent: Event { explicit ErrorEvent(int code = 0): ec(code) { } @@ -47,6 +53,8 @@ struct ListenEvent: Event { }; struct PrepareEvent: Event { }; struct ShutdownEvent: Event { }; struct TimerEvent: Event { }; +struct UninitializedEvent: Event { }; +struct WriteEvent: Event { }; } diff --git a/src/uvw/handle.hpp b/src/uvw/handle.hpp index f4e34212..c2469208 100644 --- a/src/uvw/handle.hpp +++ b/src/uvw/handle.hpp @@ -1,10 +1,10 @@ #pragma once +#include #include #include #include "emitter.hpp" -#include "resource.hpp" #include "self.hpp" #include "loop.hpp" @@ -24,10 +24,6 @@ struct UVCallbackFactory; template struct UVCallbackFactory { - template - static auto create(T &) noexcept; - -private: template static void proto(H, Args...) noexcept; }; @@ -36,13 +32,37 @@ private: } +template +struct HandleType; + +template<> struct HandleType { }; +template<> struct HandleType { }; +template<> struct HandleType { }; +template<> struct HandleType { }; +template<> struct HandleType { }; + + template -class Handle: public Emitter, public Self, public ResourceWrapper { +class Handle: public Emitter, public Self { template friend struct details::UVCallbackFactory; + struct BaseWrapper { + virtual ~BaseWrapper() = default; + virtual void * get() const noexcept = 0; + }; + + template + struct Wrapper: BaseWrapper { + Wrapper(): handle{std::make_unique()} { } + void * get() const noexcept override { return handle.get(); } + private: + std::unique_ptr handle; + }; + static void closeCallback(T &ref, uv_handle_t *) { ref.publish(CloseEvent{}); + ref.reset(); } protected: @@ -50,12 +70,37 @@ protected: using CallbackFactory = details::UVCallbackFactory; template - explicit Handle(ResourceType rt, std::shared_ptr ref) - : Emitter{}, Self{}, ResourceWrapper{std::move(rt)}, pLoop{std::move(ref)} - { } + explicit Handle(HandleType, std::shared_ptr ref) + : Emitter{}, Self{}, + wrapper{std::make_unique>()}, + pLoop{std::move(ref)} + { + this->template get()->data = static_cast(this); + } uv_loop_t* parent() const noexcept { return pLoop->loop.get(); } + template + U* get() const noexcept { return reinterpret_cast(wrapper->get()); } + + template + bool init(F &&f) { + bool ret = true; + + if(!active()) { + auto err = std::forward(f)(parent(), get()); + + if(err) { + this->publish(ErrorEvent{err}); + ret = false; + } else { + this->leak(); + } + } + + return ret; + } + public: virtual ~Handle() { static_assert(std::is_base_of, T>::value, "!"); @@ -71,17 +116,15 @@ public: bool referenced() const noexcept { return !(uv_has_ref(get()) == 0); } void close() noexcept { - auto handle = get(); - - if(!uv_is_closing(handle)) { + if(!closing()) { using CBF = CallbackFactory; - T &ref = *static_cast(this); - auto func = CBF::template create<&Handle::closeCallback>(ref); - uv_close(handle, func); + auto func = &CBF::template proto<&Handle::closeCallback>; + uv_close(get(), func); } } private: + std::unique_ptr wrapper; std::shared_ptr pLoop; }; @@ -89,28 +132,11 @@ private: namespace details { -template -template -auto UVCallbackFactory::create(T &ref) noexcept { - Handle &handle = ref; - handle.leak(); - handle.template get()->data = &ref; - return &UVCallbackFactory::proto; -} - - template template void UVCallbackFactory::proto(H handle, Args... args) noexcept { T &ref = *(static_cast(details::get(handle))); - - if(0 == uv_is_active(ref.template get())) { - auto ptr = ref.shared_from_this(); - ref.reset(); - F(*ptr, handle, args...); - } else { - F(ref, handle, args...); - } + F(ref, handle, args...); } diff --git a/src/uvw/idle.hpp b/src/uvw/idle.hpp index 029a441d..3c1c5aba 100644 --- a/src/uvw/idle.hpp +++ b/src/uvw/idle.hpp @@ -17,11 +17,7 @@ class Idle final: public Handle { idle.publish(IdleEvent{}); } - explicit Idle(std::shared_ptr ref) - : Handle{ResourceType{}, std::move(ref)} - { - initialized = (uv_idle_init(parent(), get()) == 0); - } + using Handle::Handle; public: template @@ -29,9 +25,13 @@ public: return std::shared_ptr{new Idle{std::forward(args)...}}; } + bool init() { + return Handle::init(&uv_idle_init); + } + void start() { using CBF = CallbackFactory; - auto func = CBF::create<&Idle::startCallback>(*this); + auto func = &CBF::template proto<&Idle::startCallback>; auto err = uv_idle_start(get(), func); if(err) publish(ErrorEvent{err}); } @@ -40,11 +40,6 @@ public: auto err = uv_idle_stop(get()); if(err) publish(ErrorEvent{err}); } - - explicit operator bool() const noexcept { return initialized; } - -private: - bool initialized; }; diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index e643f264..43d6e40b 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -66,7 +66,9 @@ public: template std::shared_ptr resource(Args&&... args) { - return R::create(shared_from_this(), std::forward(args)...); + auto ptr = R::create(shared_from_this(), std::forward(args)...); + ptr = ptr->init() ? ptr : nullptr; + return ptr; } void close() noexcept { diff --git a/src/uvw/prepare.hpp b/src/uvw/prepare.hpp index 6fcf5078..8929c285 100644 --- a/src/uvw/prepare.hpp +++ b/src/uvw/prepare.hpp @@ -17,11 +17,7 @@ class Prepare final: public Handle { prepare.publish(PrepareEvent{}); } - explicit Prepare(std::shared_ptr ref) - : Handle{ResourceType{}, std::move(ref)} - { - initialized = (uv_prepare_init(parent(), get()) == 0); - } + using Handle::Handle; public: template @@ -29,9 +25,13 @@ public: return std::shared_ptr{new Prepare{std::forward(args)...}}; } + bool init() { + return Handle::init(&uv_prepare_init); + } + void start() { using CBF = CallbackFactory; - auto func = CBF::create<&Prepare::startCallback>(*this); + auto func = &CBF::template proto<&Prepare::startCallback>; auto err = uv_prepare_start(get(), func); if(err) publish(ErrorEvent{err}); } @@ -40,11 +40,6 @@ public: auto err = uv_prepare_stop(get()); if(err) publish(ErrorEvent{err}); } - - explicit operator bool() const noexcept { return initialized; } - -private: - bool initialized; }; diff --git a/src/uvw/request.hpp b/src/uvw/request.hpp new file mode 100644 index 00000000..a50a8da6 --- /dev/null +++ b/src/uvw/request.hpp @@ -0,0 +1,29 @@ +#pragma once + + +#include + + +namespace uvw { + + +template +struct RequestType; + +template<> struct RequestType { }; +template<> struct RequestType { }; +template<> struct RequestType { }; +template<> struct RequestType { }; +template<> struct RequestType { }; +template<> struct RequestType { }; +template<> struct RequestType { }; +template<> struct RequestType { }; + + +template +struct Request: T { + // TODO room for a pointer to a memory pool and a better memory management +}; + + +} diff --git a/src/uvw/resource.hpp b/src/uvw/resource.hpp deleted file mode 100644 index b3192529..00000000 --- a/src/uvw/resource.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - - -#include - - -namespace uvw { - - -template -struct ResourceType { }; - - -class ResourceWrapper { - struct BaseWrapper { - virtual ~BaseWrapper() = default; - virtual void * get() const noexcept = 0; - }; - - template - struct Wrapper: BaseWrapper { - Wrapper(): handle{std::make_unique()} { } - void * get() const noexcept override { return handle.get(); } - private: - std::unique_ptr handle; - }; - -protected: - template - explicit ResourceWrapper(ResourceType) - : wrapper{std::make_unique>()} - { } - - virtual ~ResourceWrapper() = default; - - template - U* get() const noexcept { return reinterpret_cast(wrapper->get()); } - -private: - std::unique_ptr wrapper; -}; - - -} diff --git a/src/uvw/stream.hpp b/src/uvw/stream.hpp index 56fd8211..00d559d0 100644 --- a/src/uvw/stream.hpp +++ b/src/uvw/stream.hpp @@ -8,46 +8,51 @@ #include #include "event.hpp" #include "handle.hpp" +#include "util.hpp" namespace uvw { -template -class Stream; - - -class Buffer final { - template - friend class Stream; - - uv_buf_t uvBuf() const noexcept { - return uv_buf_init(data.get(), size); - } - -public: - Buffer(std::unique_ptr dt, std::size_t s) - : data{std::move(dt)}, size{s} - { } - - Buffer(Buffer &&) = default; - Buffer& operator=(Buffer &&) = default; - - void reset(std::unique_ptr dt, std::size_t s) noexcept { - data.swap(dt); - size = s; - } - -private: - std::unique_ptr data; - std::size_t size; -}; - - template class Stream: public Handle { static constexpr unsigned int DEFAULT_BACKLOG = 128; + static void allocCallback(T &, uv_handle_t *, std::size_t suggested, uv_buf_t *buf) { + buf->base = new char[suggested]; + buf->len = suggested; + } + + static void readCallback(T &ref, uv_stream_t *, ssize_t nread, const uv_buf_t *cbuf) { + uv_buf_t *buf = const_cast(cbuf); + + if(nread == UV_EOF) { + ref.publish(EndEvent{}); + delete buf->base; + } else if(nread > 0) { + std::unique_ptr data{buf->base}; + DataEvent event; + event.buffer.reset(std::move(data), nread); + ref.publish(std::move(event)); + } else { + ref.publish(ErrorEvent(nread)); + delete buf->base; + } + + buf->base = nullptr; + buf->len = 0; + } + + static void writeCallback(T &ref, uv_write_t *req, int status) { + if(status) { + ref.publish(ErrorEvent{status}); + } else { + ref.publish(WriteEvent{}); + } + + delete req; + } + static void shutdownCallback(T &ref, uv_shutdown_t *, int status) { if(status) ref.publish(ErrorEvent{status}); else ref.publish(ShutdownEvent{}); @@ -60,21 +65,21 @@ class Stream: public Handle { protected: template - Stream(ResourceType rt, std::shared_ptr ref) + Stream(HandleType rt, std::shared_ptr ref) : Handle{std::move(rt), std::move(ref)}, sdown{std::make_unique()} { } public: void shutdown() noexcept { using CBF = typename Handle::template CallbackFactory; - auto func = CBF::template create<&Stream::shutdownCallback>(*static_cast(this)); + auto func = &CBF::template proto<&Stream::shutdownCallback>; auto err = uv_shutdown(sdown.get(), this->template get(), func); if(err) this->publish(ErrorEvent{err}); } void listen(int backlog) noexcept { using CBF = typename Handle::template CallbackFactory; - auto func = CBF::template create<&Stream::listenCallback>(*static_cast(this)); + auto func = &CBF::template proto<&Stream::listenCallback>; auto err = uv_listen(this->template get(), backlog, func); if(err) this->publish(ErrorEvent{err}); } @@ -83,14 +88,31 @@ public: listen(DEFAULT_BACKLOG); } - // TODO read + void read() { + using CBFAlloc = typename Handle::template CallbackFactory; + using CBFRead = typename Handle::template CallbackFactory; + auto allocFunc = &CBFAlloc::template proto<&Stream::allocCallback>; + auto readFunc = &CBFRead::template proto<&Stream::readCallback>; + auto err = uv_read_start(this->template get(), allocFunc, readFunc); + if(err) this->publish(ErrorEvent{err}); + } void stop() noexcept { auto err = uv_read_stop(this->template get()); if(err) this->publish(ErrorEvent{err}); } - // TODO write + void write(Buffer buf) { + using CBF = typename Handle::template CallbackFactory; + auto func = &CBF::template proto<&Stream::writeCallback>; + uv_buf_t data[] = { buf.uvBuf() }; + uv_write_t *req = new uv_write_t; + auto err = uv_write(req, this->template get(), data, 1, func); + if(err) { + delete req; + this->publish(ErrorEvent{err}); + } + } int tryWrite(Buffer buf) noexcept { uv_buf_t data[] = { buf.uvBuf() }; diff --git a/src/uvw/tcp.hpp b/src/uvw/tcp.hpp index 7a0b98a1..2009e2e3 100644 --- a/src/uvw/tcp.hpp +++ b/src/uvw/tcp.hpp @@ -21,11 +21,9 @@ class Tcp final: public Stream { } explicit Tcp(std::shared_ptr ref) - : Stream{ResourceType{}, std::move(ref)}, + : Stream{HandleType{}, std::move(ref)}, conn{std::make_unique()} - { - initialized = (uv_tcp_init(parent(), get()) == 0); - } + { } template> Addr address(F &&f) { @@ -63,6 +61,10 @@ public: return std::shared_ptr{new Tcp{std::forward(args)...}}; } + bool init() { + return Stream::init(&uv_tcp_init); + } + void noDelay(bool value = false) noexcept { auto err = uv_tcp_nodelay(get(), value ? 1 : 0); if(err) publish(ErrorEvent{err}); @@ -102,7 +104,7 @@ public: typename Traits::Type addr; Traits::AddrFunc(ip.c_str(), port, &addr); using CBF = CallbackFactory; - auto func = CBF::create<&Tcp::connectCallback>(*this); + auto func = &CBF::proto<&Tcp::connectCallback>; auto err = uv_tcp_connect(conn.get(), get(), reinterpret_cast(&addr), func); if(err) publish(ErrorEvent{err}); } diff --git a/src/uvw/timer.hpp b/src/uvw/timer.hpp index 246e474e..9b27518c 100644 --- a/src/uvw/timer.hpp +++ b/src/uvw/timer.hpp @@ -18,11 +18,7 @@ class Timer final: public Handle { timer.publish(TimerEvent{}); } - explicit Timer(std::shared_ptr ref) - : Handle{ResourceType{}, std::move(ref)} - { - initialized = (uv_timer_init(parent(), get()) == 0); - } + using Handle::Handle; public: using Time = std::chrono::milliseconds; @@ -32,9 +28,13 @@ public: return std::shared_ptr{new Timer{std::forward(args)...}}; } + bool init() { + return Handle::init(&uv_timer_init); + } + void start(Time timeout, Time repeat) { using CBF = CallbackFactory; - auto func = CBF::create<&Timer::startCallback>(*this); + auto func = &CBF::template proto<&Timer::startCallback>; auto err = uv_timer_start(get(), func, timeout.count(), repeat.count()); if(err) publish(ErrorEvent{err}); } @@ -56,11 +56,6 @@ public: Time repeat() { return Time{uv_timer_get_repeat(get())}; } - - explicit operator bool() const noexcept { return initialized; } - -private: - bool initialized; }; diff --git a/src/uvw/util.hpp b/src/uvw/util.hpp index 665fdec1..50afdef0 100644 --- a/src/uvw/util.hpp +++ b/src/uvw/util.hpp @@ -70,4 +70,33 @@ private: using Addr = std::pair; +class Buffer final { + template + friend class Stream; + + uv_buf_t uvBuf() const noexcept { + return uv_buf_init(data.get(), size); + } + +public: + Buffer(): data{}, size{} { } + + Buffer(std::unique_ptr dt, std::size_t s) + : data{std::move(dt)}, size{s} + { } + + Buffer(Buffer &&) = default; + Buffer& operator=(Buffer &&) = default; + + void reset(std::unique_ptr dt, std::size_t s) noexcept { + data.swap(dt); + size = s; + } + +private: + std::unique_ptr data; + std::size_t size; +}; + + } diff --git a/test/main.cpp b/test/main.cpp index f9714feb..8a8b5a56 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -36,7 +36,16 @@ void listen(uvw::Loop &loop) { uvw::Addr remote = client->remote(); std::cout << "remote: " << remote.first << " " << remote.second << std::endl; - client->close(); + client->on([](const uvw::DataEvent &event, uvw::Tcp &) { + std::cout << "data" << std::endl; + }); + + client->on([](const uvw::EndEvent &, uvw::Tcp &client) { + std::cout << "end" << std::endl; + client.close(); + }); + + client->read(); }); tcp->once([](const uvw::CloseEvent &, uvw::Tcp &) mutable { @@ -55,11 +64,11 @@ void conn(uvw::Loop &loop) { std::cout << "error " << std::endl; }); - tcp->once([](const uvw::ConnectEvent &event, uvw::Tcp &tcp) mutable { + tcp->once([](const uvw::ConnectEvent &, uvw::Tcp &tcp) mutable { std::cout << "connect" << std::endl; auto data = std::unique_ptr(new char[1]); - data[0] = 42; + data[0] = 'a'; uvw::Buffer buf{std::move(data), 1}; int bw = tcp.tryWrite(std::move(buf)); std::cout << "written: " << ((int)bw) << std::endl;