#ifndef SafeWebsocketDeferredSend_h #define SafeWebsocketDeferredSend_h #include #include #include #include #include "common.h" class SafeWebsocketDeferredSend { public: class impl : public std::enable_shared_from_this { public: virtual void send(const std::string_view & data, uWS::OpCode op) = 0; virtual ~impl() { }; }; virtual ~SafeWebsocketDeferredSend() { }; virtual std::shared_ptr get() = 0; }; template class SafeWebsocketDeferredSendT final : public SafeWebsocketDeferredSend { public: SafeWebsocketDeferredSendT(WebSocket * ws, uWS::Loop * loop) : pimpl(impl::make(ws, loop)) { } ~SafeWebsocketDeferredSendT() { pimpl->clear(); } class impl final : public SafeWebsocketDeferredSend::impl { struct Private { }; friend class SafeWebsocketDeferredSendT; std::shared_mutex cleanupMutex; WebSocket * ws; uWS::Loop * loop; platform_thread_t eventLoopThd; void clear() { std::unique_lock lock(cleanupMutex); loop = nullptr; ws = nullptr; } static std::shared_ptr make(WebSocket * ws, uWS::Loop * loop) { return std::make_shared(Private{}, ws, loop); } public: impl(Private p, WebSocket * ws, uWS::Loop * loop) : ws(ws), loop(loop) { eventLoopThd = platformGetCurrentThread(); } impl(const impl&) = delete; virtual void send(const std::string_view & data, uWS::OpCode op) override { if(platformGetCurrentThread() == eventLoopThd) { if(!ws) { return; } ws->send(data, op); return; } auto dataCopy = std::string(data); auto thisShared = std::dynamic_pointer_cast(this->shared_from_this()); std::shared_lock lock(cleanupMutex); if(!loop) { return; } loop->defer([=,dataCopy=std::move(dataCopy)]{ if(!thisShared->ws) { return; } ws->send(dataCopy, op); }); } }; virtual std::shared_ptr get() override { return pimpl; } private: std::shared_ptr pimpl; }; #endif /* SafeWebsocketDeferredSend_h */