2020-11-24 15:41:18 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <brynet/base/CPP_VERSION.hpp>
|
2021-04-30 16:10:14 +02:00
|
|
|
#include <brynet/base/NonCopyable.hpp>
|
2020-11-24 15:41:18 +01:00
|
|
|
#include <brynet/net/EventLoop.hpp>
|
2021-04-30 16:10:14 +02:00
|
|
|
#include <brynet/net/Exception.hpp>
|
2020-11-24 15:41:18 +01:00
|
|
|
#include <brynet/net/detail/ConnectorWorkInfo.hpp>
|
2021-04-30 16:10:14 +02:00
|
|
|
#include <functional>
|
|
|
|
#include <memory>
|
|
|
|
#include <thread>
|
2020-11-24 15:41:18 +01:00
|
|
|
|
|
|
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
|
|
|
#include <shared_mutex>
|
|
|
|
#else
|
|
|
|
#include <mutex>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace brynet { namespace net { namespace detail {
|
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
class AsyncConnectorDetail : public brynet::base::NonCopyable
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
void startWorkerThread()
|
2020-11-24 15:41:18 +01:00
|
|
|
{
|
|
|
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
2021-04-30 16:10:14 +02:00
|
|
|
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
|
2020-11-24 15:41:18 +01:00
|
|
|
#else
|
2021-04-30 16:10:14 +02:00
|
|
|
std::lock_guard<std::mutex> lck(mThreadGuard);
|
2020-11-24 15:41:18 +01:00
|
|
|
#endif
|
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
if (mThread != nullptr)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
mIsRun = std::make_shared<bool>(true);
|
|
|
|
mWorkInfo = std::make_shared<detail::ConnectorWorkInfo>();
|
|
|
|
mEventLoop = std::make_shared<EventLoop>();
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
auto eventLoop = mEventLoop;
|
|
|
|
auto workerInfo = mWorkInfo;
|
|
|
|
auto isRun = mIsRun;
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
mThread = std::make_shared<std::thread>([eventLoop, workerInfo, isRun]() {
|
|
|
|
while (*isRun)
|
|
|
|
{
|
|
|
|
detail::RunOnceCheckConnect(eventLoop, workerInfo);
|
|
|
|
}
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
workerInfo->causeAllFailed();
|
|
|
|
});
|
|
|
|
}
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
void stopWorkerThread()
|
|
|
|
{
|
2020-11-24 15:41:18 +01:00
|
|
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
2021-04-30 16:10:14 +02:00
|
|
|
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
|
2020-11-24 15:41:18 +01:00
|
|
|
#else
|
2021-04-30 16:10:14 +02:00
|
|
|
std::lock_guard<std::mutex> lck(mThreadGuard);
|
2020-11-24 15:41:18 +01:00
|
|
|
#endif
|
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
if (mThread == nullptr)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
mEventLoop->runAsyncFunctor([this]() {
|
|
|
|
*mIsRun = false;
|
|
|
|
});
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if (mThread->joinable())
|
2020-11-24 15:41:18 +01:00
|
|
|
{
|
2021-04-30 16:10:14 +02:00
|
|
|
mThread->join();
|
2020-11-24 15:41:18 +01:00
|
|
|
}
|
|
|
|
}
|
2021-04-30 16:10:14 +02:00
|
|
|
catch (std::system_error& e)
|
2020-11-24 15:41:18 +01:00
|
|
|
{
|
2021-04-30 16:10:14 +02:00
|
|
|
(void) e;
|
|
|
|
}
|
|
|
|
|
|
|
|
mEventLoop = nullptr;
|
|
|
|
mWorkInfo = nullptr;
|
|
|
|
mIsRun = nullptr;
|
|
|
|
mThread = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void asyncConnect(detail::ConnectOption option)
|
|
|
|
{
|
2020-11-24 15:41:18 +01:00
|
|
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
2021-04-30 16:10:14 +02:00
|
|
|
std::shared_lock<std::shared_mutex> lck(mThreadGuard);
|
2020-11-24 15:41:18 +01:00
|
|
|
#else
|
2021-04-30 16:10:14 +02:00
|
|
|
std::lock_guard<std::mutex> lck(mThreadGuard);
|
2020-11-24 15:41:18 +01:00
|
|
|
#endif
|
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
if (option.completedCallback == nullptr && option.failedCallback == nullptr)
|
|
|
|
{
|
|
|
|
throw ConnectException("all callback is nullptr");
|
2020-11-24 15:41:18 +01:00
|
|
|
}
|
2021-04-30 16:10:14 +02:00
|
|
|
if (option.ip.empty())
|
2020-11-24 15:41:18 +01:00
|
|
|
{
|
2021-04-30 16:10:14 +02:00
|
|
|
throw ConnectException("addr is empty");
|
2020-11-24 15:41:18 +01:00
|
|
|
}
|
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
if (!(*mIsRun))
|
2020-11-24 15:41:18 +01:00
|
|
|
{
|
2021-04-30 16:10:14 +02:00
|
|
|
throw ConnectException("work thread already stop");
|
2020-11-24 15:41:18 +01:00
|
|
|
}
|
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
auto workInfo = mWorkInfo;
|
|
|
|
auto address = detail::AsyncConnectAddr(std::move(option.ip),
|
|
|
|
option.port,
|
|
|
|
option.timeout,
|
|
|
|
std::move(option.completedCallback),
|
|
|
|
std::move(option.failedCallback),
|
|
|
|
std::move(option.processCallbacks));
|
|
|
|
mEventLoop->runAsyncFunctor([workInfo, address]() {
|
|
|
|
workInfo->processConnect(address);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
AsyncConnectorDetail()
|
|
|
|
{
|
|
|
|
mIsRun = std::make_shared<bool>(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~AsyncConnectorDetail()
|
|
|
|
{
|
|
|
|
stopWorkerThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::shared_ptr<EventLoop> mEventLoop;
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
std::shared_ptr<detail::ConnectorWorkInfo> mWorkInfo;
|
|
|
|
std::shared_ptr<std::thread> mThread;
|
2020-11-24 15:41:18 +01:00
|
|
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
2021-04-30 16:10:14 +02:00
|
|
|
std::shared_mutex mThreadGuard;
|
2020-11-24 15:41:18 +01:00
|
|
|
#else
|
2021-04-30 16:10:14 +02:00
|
|
|
std::mutex mThreadGuard;
|
2020-11-24 15:41:18 +01:00
|
|
|
#endif
|
2021-04-30 16:10:14 +02:00
|
|
|
std::shared_ptr<bool> mIsRun;
|
|
|
|
};
|
2020-11-24 15:41:18 +01:00
|
|
|
|
2021-04-30 16:10:14 +02:00
|
|
|
}}}// namespace brynet::net::detail
|