Skip to content

Commit

Permalink
线程加锁
Browse files Browse the repository at this point in the history
  • Loading branch information
yjmthu committed Aug 3, 2023
1 parent cdd1881 commit a81953c
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 107 deletions.
2 changes: 2 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.10.1)

return()

file(GLOB sources src/*.cpp)

foreach(item ${sources})
Expand Down
22 changes: 14 additions & 8 deletions pluginmgr/include/httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
#include <string>
#include <map>
#include <httpproxy.h>
#include <memory>

class HttpLib {
private:
struct PostData { void* data; size_t size; } m_PostData;
public:
typedef std::mutex Mutex;
private:
typedef std::lock_guard<Mutex> Locker;
typedef std::unique_lock<Mutex> LockerEx;
public:
typedef uint64_t HttpId;
typedef std::map<std::string, std::string> Headers;
typedef size_t( CallbackFunction )(void*, size_t, size_t, void*);

struct PostData { void* data; size_t size; } m_PostData;
struct Response {
std::string version;
unsigned long status = -1;
Expand All @@ -35,11 +38,13 @@ class HttpLib {
};

template<typename Char=char>
explicit HttpLib(std::basic_string_view<Char> url, bool async=false):
m_Url(url.cbegin(), url.cend()),
m_hSession(nullptr),
m_ProxySet(false),
m_AsyncSet(async) {
explicit HttpLib(std::basic_string_view<Char> url, bool async = false)
: m_Url(url.cbegin(), url.cend())
, m_hSession(nullptr)
, m_ProxySet(false)
, m_AsyncSet(async)
{
IntoPool();
HttpPrepare();
HttpInitialize();
}
Expand Down Expand Up @@ -94,6 +99,7 @@ class HttpLib {
size_t m_RecieveSize = 0;
size_t m_ConnectLength = 0;
private:
void IntoPool();
void HttpInitialize();
void HttpUninitialize();
void HttpPrepare();
Expand All @@ -120,7 +126,7 @@ class HttpLib {
CallbackFunction* m_Callback;
Callback m_AsyncCallback;
void* m_DataBuffer = nullptr;
// Mutex m_AsyncMutex;
HttpId m_AsyncId;
};

#endif
111 changes: 70 additions & 41 deletions pluginmgr/src/httplib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,28 @@
using namespace std::literals;
namespace fs = std::filesystem;
std::optional<HttpProxy> HttpLib::m_Proxy = std::nullopt;
// HttpLib::HttpId HttpLib::m_MaxId = 0;
// std::map<HttpLib::HttpId, HttpLib*> HttpLib::m_AsyncPool;
// HttpLib::Mutex HttpLib::m_AsyncMutex;

static HttpLib::HttpId m_MaxId = 0;
static std::map<HttpLib::HttpId, HttpLib*> m_AsyncPool;
static HttpLib::Mutex m_AsyncMutex;

// https://github.com/JGRennison/OpenTTD-patches/blob/dcc52f7696f4ef2601b9fbca1ca78abcd1211734/src/network/core/http_winhttp.cpp#L145
void HttpLib::RequestStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwInternetInformationLength) {
constexpr auto bufferSize = 8 << 10;
// sometimes maybe nullptr
if (!dwContext) return;

auto object = reinterpret_cast<HttpLib*>(dwContext);
if (object->m_Finished)
LockerEx locker(m_AsyncMutex);
auto objectIter = m_AsyncPool.find(dwContext);
if (objectIter == m_AsyncPool.end())
return;
auto& object = *objectIter->second;

if (object.m_Finished) return;

switch (dwInternetStatus) {
case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME:
case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED:
Expand All @@ -44,82 +56,84 @@ void HttpLib::RequestStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, DW
break;

case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
WinHttpReceiveResponse(object->m_hRequest, nullptr);
locker.unlock();
WinHttpReceiveResponse(hInternet, nullptr);
break;

case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: {
auto bResults = object->ReadStatusCode();

auto bResults = object.ReadStatusCode();
if (bResults) {
bResults = object->m_Response.status < 400;
bResults = object.m_Response.status < 400;
} else {
// locker.unlock();
object->EmitFinish(L"HttpLib Error: HttpLib ReadStatusCode Error.");
object.EmitFinish(L"HttpLib Error: HttpLib ReadStatusCode Error.");
break;
}
if (bResults) {
bResults = object->ReadHeaders();
bResults = object.ReadHeaders();
} else {
// locker.unlock();
object->EmitFinish(L"HttpLib StatusCode Error.");
object.EmitFinish(L"HttpLib StatusCode Error.");
break;
}
if (bResults) {
auto iter = object->m_Response.headers.find("Content-Length");
if (iter != object->m_Response.headers.end()) {
object->m_ConnectLength = std::stoull(iter->second);
auto iter = object.m_Response.headers.find("Content-Length");
if (iter != object.m_Response.headers.end()) {
object.m_ConnectLength = std::stoull(iter->second);
}
object->EmitProcess();
object.EmitProcess();
/* Next step: query for any data. */
WinHttpQueryDataAvailable(object->m_hRequest, NULL);
locker.unlock();
WinHttpQueryDataAvailable(hInternet, NULL);
} else {
// locker.unlock();
object->EmitFinish(L"HttpLib ReadHeaders Error.");
object.EmitFinish(L"HttpLib ReadHeaders Error.");
}
break;
}

case WINHTTP_CALLBACK_STATUS_REDIRECT:
/* Make sure we are not in a redirect loop. */
if (object->m_RedirectDepth++ > 5) {
// locker.unlock();
object->EmitFinish(L"HTTP request failed: too many redirects");
if (object.m_RedirectDepth++ > 5) {
object.EmitFinish(L"HTTP request failed: too many redirects");
}
break;

case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: {
// Retrieve the number of bytes to read
// Allocate a buffer for the data
auto buffer = reinterpret_cast<std::u8string*>(object.m_DataBuffer);
auto size = *reinterpret_cast<DWORD*>(lpvStatusInformation);
auto pszOutBuffer = size == 0 ? nullptr : new char8_t[size];
if (!buffer) return;
buffer->resize(size);
auto pszOutBuffer = size == 0 ? nullptr : buffer->data();
// Read the data from the server
WinHttpReadData(object->m_hRequest, pszOutBuffer, size, nullptr);
locker.unlock();
WinHttpReadData(object.m_hRequest, pszOutBuffer, size, nullptr);
break;
}

case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: {
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
if (dwInternetInformationLength) {
object->m_RecieveSize += dwInternetInformationLength;
object->m_AsyncCallback.m_WriteCallback->operator()(lpvStatusInformation, dwInternetInformationLength);
object->EmitProcess();
}
delete[] reinterpret_cast<char8_t*>(lpvStatusInformation);

if (dwInternetInformationLength == 0) {
// locker.unlock();
object->EmitFinish();
} else {
WinHttpQueryDataAvailable(object->m_hRequest, nullptr);
object.m_RecieveSize += dwInternetInformationLength;
object.m_AsyncCallback.m_WriteCallback->operator()(lpvStatusInformation, dwInternetInformationLength);
object.EmitProcess();

locker.unlock();
WinHttpQueryDataAvailable(object.m_hRequest, nullptr);
} else{
object.EmitFinish();
}
break;
}

case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: {
auto const* pAsyncResult = (WINHTTP_ASYNC_RESULT*)lpvStatusInformation;
DWORD dwError = pAsyncResult->dwError; // The error code
DWORD dwResult = pAsyncResult->dwResult; // The ID of the called function
// locker.unlock();
object->EmitFinish(std::format(L"Winhttp status error. Error code: {}, error id: {}.", dwError, dwResult));
object.EmitFinish(std::format(L"Winhttp status error. Error code: {}, error id: {}.", dwError, dwResult));
break;
}
}
Expand Down Expand Up @@ -188,6 +202,9 @@ size_t HttpLib::WriteString(void* buffer,
HttpLib::~HttpLib() {
if (m_AsyncSet) {
ExitAsync();
m_AsyncMutex.lock();
m_AsyncPool.erase(m_AsyncId);
m_AsyncMutex.unlock();
} else {
m_Finished = true;
HttpUninitialize();
Expand Down Expand Up @@ -266,6 +283,16 @@ std::u8string HttpLib::GetPath()
return result;
}

void HttpLib::IntoPool()
{
if (m_AsyncSet) {
m_AsyncMutex.lock();
m_AsyncId = ++m_MaxId;
m_AsyncPool[m_AsyncId] = this;
m_AsyncMutex.unlock();
}
}

void HttpLib::HttpPrepare()
{
#ifdef _WIN32
Expand Down Expand Up @@ -436,7 +463,7 @@ bool HttpLib::SendRequest()
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
m_PostData.data, m_PostData.size,
m_PostData.size,
reinterpret_cast<DWORD_PTR>(this)
static_cast<DWORD_PTR>(m_AsyncId)
);
#else
curl_easy_setopt(m_hSession, CURLOPT_POST, 1L);
Expand All @@ -448,7 +475,7 @@ bool HttpLib::SendRequest()
return WinHttpSendRequest(m_hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0, 0,
reinterpret_cast<DWORD_PTR>(this)
static_cast<DWORD_PTR>(m_AsyncId)
);
#endif
}
Expand Down Expand Up @@ -694,8 +721,8 @@ void HttpLib::EmitFinish(std::wstring message)
cb(message, &m_Response);
}
// Locker locker(m_AsyncMutex);
// delete reinterpret_cast<std::u8string*>(m_DataBuffer);
// m_DataBuffer = nullptr;
delete reinterpret_cast<std::u8string*>(m_DataBuffer);
m_DataBuffer = nullptr;
}

HttpLib::Response* HttpLib::Get()
Expand Down Expand Up @@ -747,7 +774,7 @@ void HttpLib::GetAsync(Callback callback)
m_Finished = false;
m_Response.body.clear();
m_AsyncCallback = std::move(callback);
// m_DataBuffer = new std::u8string;
m_DataBuffer = new std::u8string;
if (!m_AsyncCallback.m_WriteCallback) {
m_AsyncCallback.m_WriteCallback = [this](auto data, auto size){
m_Response.body.append(reinterpret_cast<const char*>(data), size);
Expand All @@ -757,7 +784,9 @@ void HttpLib::GetAsync(Callback callback)
}

void HttpLib::ExitAsync() {
m_AsyncMutex.lock();
m_Response.status = -1;
EmitFinish(L"Httplib Error: User terminate.");
HttpInitialize();
}
m_AsyncMutex.unlock();
HttpUninitialize();
}
6 changes: 0 additions & 6 deletions pluginmgr/src/update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ PluginUpdate::~PluginUpdate()
{
delete m_Timer;
m_DataRequest = nullptr;
if (m_File.is_open()) {
m_File.close();
}
}


Expand Down Expand Up @@ -159,7 +156,6 @@ void PluginUpdate::DownloadUpgrade(Callback cb)
if (!url.ends_with(u8".zip")) {
continue;
}
if (m_File.is_open()) m_File.close();
m_File.open(GetTempFilePath(), std::ios::out | std::ios::binary);
if (!m_File.is_open()) return;

Expand All @@ -176,9 +172,7 @@ void PluginUpdate::DownloadUpgrade(Callback cb)
}
},
};

m_DataRequest->GetAsync(std::move(callback));

return;
}
}
Expand Down
12 changes: 7 additions & 5 deletions pluginmgr/widgets/neomsgdlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ void NeoMsgDlg::ShowMessage(const QString& text)
m_Data.push(text);
return;
}
m_Data.push(text);
m_pLabel->setText(text);
show();
// m_pFrame->setWindowOpacity();
HandleShowMsg();
QMetaObject::invokeMethod(this, [this, text]() {
m_Data.push(text);
m_pLabel->setText(text);
show();
// m_pFrame->setWindowOpacity();
HandleShowMsg();
});
}

void NeoMsgDlg::InitWindowStyle()
Expand Down
1 change: 0 additions & 1 deletion pluginmgr/widgets/tabversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,6 @@ void TabVersion::DoUpgrade(const YJson& data)
continue;
}
if (!DownloadNew(url)) {
mgr->ShowMsg("下载失败!");
return;
}
fs::path dataDir = fs::absolute(L"junk") / L"Neobox";
Expand Down
4 changes: 3 additions & 1 deletion plugins/neowallpaper_core/include/download.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ class DownloadJob {
static bool IsImageFile(const std::u8string & fileName);

static std::map<std::filesystem::path, const DownloadJob*> m_Pool;
inline static std::mutex m_Mutex;
static std::mutex m_Mutex;
static const String m_ImgNamePattern;
static void ClearPool();
static bool IsPoolEmpty();
private:
DownloadJob(std::filesystem::path path, std::u8string url, Callback callback);
~DownloadJob();
Expand Down
2 changes: 1 addition & 1 deletion plugins/neowallpaper_core/include/wallbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class WallBase {

public:
enum { WALLHAVEN = 0, BINGAPI, DIRECTAPI, NATIVE, SCRIPTOUTPUT, FAVORITE };
static WallBase* GetNewInstance(YJson& setting, int type);
static WallBase* GetNewInstance(YJson& setting, uint32_t type);
static void ClearInstatnce();
explicit WallBase(YJson& setting):
m_Setting(setting)
Expand Down
Loading

0 comments on commit a81953c

Please sign in to comment.