#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BRYNET_HAVE_LANG_CXX17 #include #else #include #endif namespace brynet { namespace net { namespace detail { class AsyncConnectorDetail : public brynet::base::NonCopyable { protected: void startWorkerThread() { #ifdef BRYNET_HAVE_LANG_CXX17 std::lock_guard lck(mThreadGuard); #else std::lock_guard lck(mThreadGuard); #endif if (mThread != nullptr) { return; } mIsRun = std::make_shared(true); mWorkInfo = std::make_shared(); mEventLoop = std::make_shared(); auto eventLoop = mEventLoop; auto workerInfo = mWorkInfo; auto isRun = mIsRun; mThread = std::make_shared([eventLoop, workerInfo, isRun]() { while (*isRun) { detail::RunOnceCheckConnect(eventLoop, workerInfo); } workerInfo->causeAllFailed(); }); } void stopWorkerThread() { #ifdef BRYNET_HAVE_LANG_CXX17 std::lock_guard lck(mThreadGuard); #else std::lock_guard lck(mThreadGuard); #endif if (mThread == nullptr) { return; } mEventLoop->runAsyncFunctor([this]() { *mIsRun = false; }); try { if (mThread->joinable()) { mThread->join(); } } catch (std::system_error & e) { (void)e; } mEventLoop = nullptr; mWorkInfo = nullptr; mIsRun = nullptr; mThread = nullptr; } void asyncConnect(const std::vector& options) { #ifdef BRYNET_HAVE_LANG_CXX17 std::shared_lock lck(mThreadGuard); #else std::lock_guard lck(mThreadGuard); #endif detail::ConnectOptionsInfo option; for (const auto& func : options) { func(option); } if (option.completedCallback == nullptr && option.faledCallback == nullptr) { throw ConnectException("all callback is nullptr"); } if (option.ip.empty()) { throw ConnectException("addr is empty"); } if (!(*mIsRun)) { throw ConnectException("work thread already stop"); } auto workInfo = mWorkInfo; auto address = detail::AsyncConnectAddr(std::move(option.ip), option.port, option.timeout, std::move(option.completedCallback), std::move(option.faledCallback), std::move(option.processCallbacks)); mEventLoop->runAsyncFunctor([workInfo, address]() { workInfo->processConnect(address); }); } protected: AsyncConnectorDetail() { mIsRun = std::make_shared(false); } virtual ~AsyncConnectorDetail() { stopWorkerThread(); } private: std::shared_ptr mEventLoop; std::shared_ptr mWorkInfo; std::shared_ptr mThread; #ifdef BRYNET_HAVE_LANG_CXX17 std::shared_mutex mThreadGuard; #else std::mutex mThreadGuard; #endif std::shared_ptr mIsRun; }; } } }