mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-29 04:08:54 +03:00
Windows Shell Integration: Use the QLocalSocket on windo and do the request assynchroniously
Squashed commit of the following: commit 4d9b072f560fa171a1390b7c74425614aa20e955 Author: Olivier Goffart <ogoffart@woboq.com> Date: Tue Oct 14 16:04:02 2014 +0200 Remove useless variable commit 8e85de0307ec5f31bf3f92a7de793fed7d41c2ea Author: Daniel Molkentin <danimo@owncloud.com> Date: Tue Oct 14 16:01:52 2014 +0200 Make Windows Explorer Extension build commit 8e2942cd9fd32e3af72d60cba0d06bd9d6222a45 Author: Daniel Molkentin <danimo@owncloud.com> Date: Tue Oct 14 11:39:37 2014 +0200 Fix compilation commit 0fc0c0e0e0c7e58ad97f62700256c7d1f8c0670b Author: Olivier Goffart <ogoffart@woboq.com> Date: Tue Oct 14 11:48:32 2014 +0200 Windows Shell Integration: Try to let the thread notify about changes when there are changes commit 4a1712b7c03269ca3007f167b8f313ea47655967 Author: Olivier Goffart <ogoffart@woboq.com> Date: Tue Oct 14 11:35:20 2014 +0200 Windows Shell Integration: Share the RemotePathChecker amongst all the OCOverlay instances commit 2d87408e9af5a4d7ab71c460ce606ba1f367c09f Author: Olivier Goffart <ogoffart@woboq.com> Date: Mon Oct 13 18:55:15 2014 +0200 Windows Shell Integration: Attempts to wait on multiple objects (WIP) commit e448e427b6d1561ad7a40d08fc6632f4d2b4ef44 Author: Daniel Molkentin <danimo@owncloud.com> Date: Mon Oct 13 17:58:02 2014 +0200 Introduce a worker thread commit 2344407ec0bc1ce173ebbacadcf3992d62d94078 Author: Olivier Goffart <ogoffart@woboq.com> Date: Mon Oct 13 17:03:47 2014 +0200 Windows Shell Integration: try to keep the socket open using a thread (WIP) commit ea6d5273ed60d8bc3f1c5d5c6936364d783a1c0f Author: Daniel Molkentin <danimo@owncloud.com> Date: Mon Oct 13 15:27:46 2014 +0200 Make Explorer plugin work again with named pipes This is a temporary hack, which needs more refactoring. commit 44a3437a44082379efa0078c9afd7b8bbde930de Author: Daniel Molkentin <danimo@owncloud.com> Date: Sat Oct 11 07:31:24 2014 +0200 Fix code commit 123390a0f3516c0078309d7048c6d2acb9293676 Author: Olivier Goffart <ogoffart@woboq.com> Date: Fri Oct 10 16:29:35 2014 +0200 Windows shell integration: Use named pipe (WIP) commit 9eea7e2321abeac6b8db0bd85bfce612dbf6bb20 Author: Olivier Goffart <ogoffart@woboq.com> Date: Wed Oct 1 12:04:13 2014 +0200 Windows Shell Integration: Simplify StringUtil This fixes a memory leak in CommunicationSocket::ReadLine
This commit is contained in:
parent
8231bc931b
commit
4b001a77b3
8 changed files with 206 additions and 165 deletions
|
@ -36,17 +36,13 @@ extern HINSTANCE instanceHandle;
|
||||||
#define IDM_DISPLAY 0
|
#define IDM_DISPLAY 0
|
||||||
#define IDB_OK 101
|
#define IDB_OK 101
|
||||||
|
|
||||||
namespace {
|
|
||||||
static std::vector<std::wstring> s_watchedDirectories;
|
|
||||||
}
|
|
||||||
|
|
||||||
OCOverlay::OCOverlay(int state)
|
OCOverlay::OCOverlay(int state)
|
||||||
: _communicationSocket(0)
|
: _referenceCount(1)
|
||||||
, _referenceCount(1)
|
|
||||||
, _checker(new RemotePathChecker(PORT))
|
|
||||||
, _state(state)
|
, _state(state)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
static RemotePathChecker s_remotePathChecker;
|
||||||
|
_checker = &s_remotePathChecker;
|
||||||
}
|
}
|
||||||
|
|
||||||
OCOverlay::~OCOverlay(void)
|
OCOverlay::~OCOverlay(void)
|
||||||
|
@ -121,23 +117,13 @@ IFACEMETHODIMP OCOverlay::GetPriority(int *pPriority)
|
||||||
|
|
||||||
IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
|
IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
|
||||||
{
|
{
|
||||||
|
auto watchedDirectories = _checker->WatchedDirectories();
|
||||||
//if(!_IsOverlaysEnabled())
|
|
||||||
//{
|
|
||||||
// return MAKE_HRESULT(S_FALSE, 0, 0);
|
|
||||||
//}
|
|
||||||
|
|
||||||
// FIXME: Use Registry instead, this will only trigger once
|
|
||||||
// and now follow any user changes in the client
|
|
||||||
if (s_watchedDirectories.empty()) {
|
|
||||||
s_watchedDirectories = _checker->WatchedDirectories();
|
|
||||||
}
|
|
||||||
|
|
||||||
wstring wpath(pwszPath);
|
wstring wpath(pwszPath);
|
||||||
wpath.append(L"\\");
|
//wpath.append(L"\\");
|
||||||
vector<wstring>::iterator it;
|
vector<wstring>::iterator it;
|
||||||
bool watched = false;
|
bool watched = false;
|
||||||
for (it = s_watchedDirectories.begin(); it != s_watchedDirectories.end(); ++it) {
|
for (it = watchedDirectories.begin(); it != watchedDirectories.end(); ++it) {
|
||||||
if (StringUtil::begins_with(wpath, *it)) {
|
if (StringUtil::begins_with(wpath, *it)) {
|
||||||
watched = true;
|
watched = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,14 +35,13 @@ public:
|
||||||
IFACEMETHODIMP_(ULONG) Release();
|
IFACEMETHODIMP_(ULONG) Release();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~OCOverlay(void);
|
~OCOverlay();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//bool _GenerateMessage(const wchar_t*, std::wstring*);
|
//bool _GenerateMessage(const wchar_t*, std::wstring*);
|
||||||
|
|
||||||
bool _IsOverlaysEnabled();
|
bool _IsOverlaysEnabled();
|
||||||
long _referenceCount;
|
long _referenceCount;
|
||||||
CommunicationSocket* _communicationSocket;
|
|
||||||
RemotePathChecker* _checker;
|
RemotePathChecker* _checker;
|
||||||
int _state;
|
int _state;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
@ -30,8 +31,8 @@ using namespace std;
|
||||||
|
|
||||||
#define DEFAULT_BUFLEN 4096
|
#define DEFAULT_BUFLEN 4096
|
||||||
|
|
||||||
CommunicationSocket::CommunicationSocket(int port)
|
CommunicationSocket::CommunicationSocket()
|
||||||
: _port(port), _clientSocket(INVALID_SOCKET)
|
: _pipe(INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,64 +44,42 @@ CommunicationSocket::~CommunicationSocket()
|
||||||
bool CommunicationSocket::Close()
|
bool CommunicationSocket::Close()
|
||||||
{
|
{
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
bool closed = (closesocket(_clientSocket) == 0);
|
if (_pipe == INVALID_HANDLE_VALUE) {
|
||||||
shutdown(_clientSocket, SD_BOTH);
|
return false;
|
||||||
_clientSocket = INVALID_SOCKET;
|
}
|
||||||
return closed;
|
CloseHandle(_pipe);
|
||||||
|
_pipe = INVALID_HANDLE_VALUE;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CommunicationSocket::Connect()
|
bool CommunicationSocket::Connect()
|
||||||
{
|
{
|
||||||
WSADATA wsaData;
|
auto pipename = std::wstring(L"\\\\.\\pipe\\");
|
||||||
|
pipename += L"ownCloud";
|
||||||
|
|
||||||
HRESULT iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
_pipe = CreateFile(pipename.data(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
|
||||||
if (iResult != NO_ERROR) {
|
if (_pipe == INVALID_HANDLE_VALUE) {
|
||||||
int error = WSAGetLastError();
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
_clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
|
|
||||||
if (_clientSocket == INVALID_SOCKET) {
|
|
||||||
//int error = WSAGetLastError();
|
|
||||||
Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_in clientService;
|
|
||||||
|
|
||||||
clientService.sin_family = AF_INET;
|
|
||||||
clientService.sin_addr.s_addr = inet_addr(PLUG_IN_SOCKET_ADDRESS);
|
|
||||||
clientService.sin_port = htons(_port);
|
|
||||||
|
|
||||||
iResult = connect(_clientSocket, (SOCKADDR*)&clientService, sizeof(clientService));
|
|
||||||
DWORD timeout = 500; // ms
|
|
||||||
setsockopt(_clientSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout, sizeof(DWORD));
|
|
||||||
|
|
||||||
if (iResult == SOCKET_ERROR) {
|
|
||||||
//int error = WSAGetLastError();
|
|
||||||
Close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommunicationSocket::SendMsg(const wchar_t* message)
|
bool CommunicationSocket::SendMsg(const wchar_t* message)
|
||||||
{
|
{
|
||||||
const char* utf8_msg = StringUtil::toUtf8(message);
|
auto utf8_msg = StringUtil::toUtf8(message);
|
||||||
size_t result = send(_clientSocket, utf8_msg, (int)strlen(utf8_msg), 0);
|
|
||||||
delete[] utf8_msg;
|
|
||||||
|
|
||||||
if (result == SOCKET_ERROR) {
|
DWORD numBytesWritten = 0;
|
||||||
//int error = WSAGetLastError();
|
auto result = WriteFile( _pipe, utf8_msg.c_str(), DWORD(utf8_msg.size()), &numBytesWritten, NULL);
|
||||||
closesocket(_clientSocket);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// qWarning() << "Failed to send data." <<;
|
||||||
|
// look up error code here using GetLastError()
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommunicationSocket::ReadLine(wstring* response)
|
bool CommunicationSocket::ReadLine(wstring* response)
|
||||||
|
@ -109,21 +88,36 @@ bool CommunicationSocket::ReadLine(wstring* response)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<char> resp_utf8;
|
response->clear();
|
||||||
char buffer;
|
|
||||||
|
Sleep(50);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int bytesRead = recv(_clientSocket, &buffer, 1, 0);
|
int lbPos = 0;
|
||||||
if (bytesRead <= 0) {
|
auto it = std::find(_buffer.begin() + lbPos, _buffer.end(), '\n');
|
||||||
response = 0;
|
if (it != _buffer.end()) {
|
||||||
|
*response = StringUtil::toUtf16(_buffer.data(), DWORD(it - _buffer.begin()));
|
||||||
|
_buffer.erase(_buffer.begin(), it + 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<char, 128> resp_utf8;
|
||||||
|
DWORD numBytesRead = 0;
|
||||||
|
DWORD totalBytesAvailable = 0;
|
||||||
|
PeekNamedPipe(_pipe, NULL, 0, 0, &totalBytesAvailable, 0);
|
||||||
|
if (totalBytesAvailable == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer == '\n') {
|
auto result = ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, NULL);
|
||||||
resp_utf8.push_back(0);
|
if (!result) {
|
||||||
*response = StringUtil::toUtf16(&resp_utf8[0], resp_utf8.size());
|
// qWarning() << "Failed to read data from the pipe";
|
||||||
return true;
|
return false;
|
||||||
} else {
|
}
|
||||||
resp_utf8.push_back(buffer);
|
if (numBytesRead <= 0) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
_buffer.insert(_buffer.end(), resp_utf8.begin(), resp_utf8.begin()+numBytesRead);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,13 @@
|
||||||
#pragma warning (disable : 4251)
|
#pragma warning (disable : 4251)
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <WinSock2.h>
|
#include <WinSock2.h>
|
||||||
|
|
||||||
class __declspec(dllexport) CommunicationSocket
|
class __declspec(dllexport) CommunicationSocket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CommunicationSocket(int port);
|
CommunicationSocket();
|
||||||
~CommunicationSocket();
|
~CommunicationSocket();
|
||||||
|
|
||||||
bool Connect();
|
bool Connect();
|
||||||
|
@ -34,9 +35,11 @@ public:
|
||||||
bool SendMsg(const wchar_t*);
|
bool SendMsg(const wchar_t*);
|
||||||
bool ReadLine(std::wstring*);
|
bool ReadLine(std::wstring*);
|
||||||
|
|
||||||
|
HANDLE Event() { return _pipe; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _port;
|
HANDLE _pipe;
|
||||||
SOCKET _clientSocket;
|
std::vector<char> _buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -20,88 +20,120 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <shlobj.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
RemotePathChecker::RemotePathChecker(int port)
|
|
||||||
: _port(port)
|
// This code is run in a thread
|
||||||
|
void RemotePathChecker::workerThreadLoop()
|
||||||
{
|
{
|
||||||
|
CommunicationSocket socket;
|
||||||
|
std::unordered_set<std::wstring> asked;
|
||||||
|
if (!socket.Connect()) {
|
||||||
|
return;
|
||||||
|
//FIXME! what if this fails! what if we are disconnected later?
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!_stop) {
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
while (!_pending.empty() && !_stop) {
|
||||||
|
auto filePath = _pending.front();
|
||||||
|
_pending.pop();
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
if (!asked.count(filePath)) {
|
||||||
|
asked.insert(filePath);
|
||||||
|
socket.SendMsg(wstring(L"RETRIEVE_FILE_STATUS:" + filePath + L'\n').data());
|
||||||
|
}
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring response;
|
||||||
|
while (!_stop && socket.ReadLine(&response)) {
|
||||||
|
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||||
|
wstring responsePath = response.substr(14); // length of REGISTER_PATH:
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_watchedDirectories.push_back(responsePath);
|
||||||
|
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
|
||||||
|
StringUtil::begins_with(response, wstring(L"BROADCAST:"))) {
|
||||||
|
|
||||||
|
auto statusBegin = response.find(L':', 0);
|
||||||
|
assert(statusBegin != std::wstring::npos);
|
||||||
|
|
||||||
|
auto statusEnd = response.find(L':', statusBegin + 1);
|
||||||
|
if (statusEnd == std::wstring::npos) {
|
||||||
|
// the command do not contains two colon?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto responseStatus = response.substr(statusBegin+1, statusEnd - statusBegin-1);
|
||||||
|
auto responsePath = response.substr(statusEnd+1);
|
||||||
|
auto state = _StrToFileState(responseStatus);
|
||||||
|
auto erased = asked.erase(responsePath);
|
||||||
|
|
||||||
|
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_cache[responsePath] = state;
|
||||||
|
}
|
||||||
|
SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, responsePath.data(), NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_stop)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RemotePathChecker::RemotePathChecker()
|
||||||
|
: _thread([this]{ this->workerThreadLoop(); } )
|
||||||
|
, _newQueries(CreateEvent(NULL, true, true, NULL))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RemotePathChecker::~RemotePathChecker()
|
||||||
|
{
|
||||||
|
_stop = true;
|
||||||
|
//_newQueries.notify_all();
|
||||||
|
SetEvent(_newQueries);
|
||||||
|
_thread.join();
|
||||||
|
CloseHandle(_newQueries);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<wstring> RemotePathChecker::WatchedDirectories()
|
vector<wstring> RemotePathChecker::WatchedDirectories()
|
||||||
{
|
{
|
||||||
vector<wstring> watchedDirectories;
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
wstring response;
|
return _watchedDirectories;
|
||||||
bool needed = false;
|
|
||||||
|
|
||||||
CommunicationSocket socket(_port);
|
|
||||||
socket.Connect();
|
|
||||||
|
|
||||||
while (socket.ReadLine(&response)) {
|
|
||||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
|
||||||
size_t pathBegin = response.find(L':', 0);
|
|
||||||
if (pathBegin == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// chop trailing '\n'
|
|
||||||
wstring responsePath = response.substr(pathBegin + 1, response.length()-1);
|
|
||||||
watchedDirectories.push_back(responsePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return watchedDirectories;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
||||||
{
|
{
|
||||||
wstring request;
|
assert(state); assert(filePath);
|
||||||
wstring response;
|
|
||||||
bool needed = false;
|
|
||||||
|
|
||||||
CommunicationSocket socket(_port);
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
socket.Connect();
|
|
||||||
request = L"RETRIEVE_FILE_STATUS:";
|
|
||||||
request += filePath;
|
|
||||||
request += L'\n';
|
|
||||||
|
|
||||||
if (!socket.SendMsg(request.c_str())) {
|
auto path = std::wstring(filePath);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (socket.ReadLine(&response)) {
|
auto it = _cache.find(path);
|
||||||
// discard broadcast messages
|
if (it != _cache.end()) {
|
||||||
if (StringUtil::begins_with(response, wstring(L"STATUS:"))) {
|
*state = it->second;
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
size_t statusBegin = response.find(L':', 0);
|
_pending.push(filePath);
|
||||||
if (statusBegin == -1)
|
SetEvent(_newQueries);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
size_t statusEnd = response.find(L':', statusBegin + 1);
|
|
||||||
if (statusEnd == -1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
|
||||||
wstring responseStatus = response.substr(statusBegin+1, statusEnd - statusBegin-1);
|
|
||||||
wstring responsePath = response.substr(statusEnd+1);
|
|
||||||
if (responsePath == filePath) {
|
|
||||||
if (!state) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*state = _StrToFileState(responseStatus);
|
|
||||||
if (*state == StateNone) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
needed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return needed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemotePathChecker::_StrToFileState(const std::wstring &str)
|
RemotePathChecker::FileState RemotePathChecker::_StrToFileState(const std::wstring &str)
|
||||||
{
|
{
|
||||||
if (str == L"NOP" || str == L"NONE") {
|
if (str == L"NOP" || str == L"NONE") {
|
||||||
return StateNone;
|
return StateNone;
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <queue>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -29,14 +35,32 @@ public:
|
||||||
StateWarning, StateWarningSWM,
|
StateWarning, StateWarningSWM,
|
||||||
StateNone
|
StateNone
|
||||||
};
|
};
|
||||||
RemotePathChecker(int port);
|
RemotePathChecker();
|
||||||
|
~RemotePathChecker();
|
||||||
std::vector<std::wstring> WatchedDirectories();
|
std::vector<std::wstring> WatchedDirectories();
|
||||||
bool IsMonitoredPath(const wchar_t* filePath, int* state);
|
bool IsMonitoredPath(const wchar_t* filePath, int* state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _StrToFileState(const std::wstring &str);
|
FileState _StrToFileState(const std::wstring &str);
|
||||||
int _port;
|
std::mutex _mutex;
|
||||||
|
std::thread _thread;
|
||||||
|
std::atomic<bool> _stop;
|
||||||
|
|
||||||
|
// Everything here is protected by the _mutex
|
||||||
|
|
||||||
|
/** The list of paths we need to query. The main thread fill this, and the worker thread
|
||||||
|
* send that to the socket. */
|
||||||
|
std::queue<std::wstring> _pending;
|
||||||
|
|
||||||
|
std::unordered_map<std::wstring, FileState> _cache;
|
||||||
|
std::vector<std::wstring> _watchedDirectories;
|
||||||
|
|
||||||
|
|
||||||
|
// The main thread notifies when there are new items in _pending
|
||||||
|
//std::condition_variable _newQueries;
|
||||||
|
HANDLE _newQueries;
|
||||||
|
|
||||||
|
void workerThreadLoop();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -11,22 +11,26 @@
|
||||||
* details.
|
* details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <locale>
|
||||||
|
#include <string>
|
||||||
|
#include <codecvt>
|
||||||
|
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
|
|
||||||
char* StringUtil::toUtf8(const wchar_t *utf16, int len)
|
std::string StringUtil::toUtf8(const wchar_t *utf16, int len)
|
||||||
{
|
{
|
||||||
int newlen = WideCharToMultiByte(CP_UTF8, 0, utf16, len, NULL, 0, NULL, NULL);
|
if (len < 0) {
|
||||||
char* str = new char[newlen];
|
len = wcslen(utf16);
|
||||||
WideCharToMultiByte(CP_UTF8, 0, utf16, -1, str, newlen, NULL, NULL);
|
}
|
||||||
return str;
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;
|
||||||
|
return converter.to_bytes(utf16, utf16+len);
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t* StringUtil::toUtf16(const char *utf8, int len)
|
std::wstring StringUtil::toUtf16(const char *utf8, int len)
|
||||||
{
|
{
|
||||||
int newlen = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
|
if (len < 0) {
|
||||||
wchar_t* wstr = new wchar_t[newlen];
|
len = strlen(utf8);
|
||||||
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, newlen);
|
}
|
||||||
return wstr;
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;
|
||||||
|
return converter.from_bytes(utf8, utf8+len);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,14 @@
|
||||||
|
|
||||||
class __declspec(dllexport) StringUtil {
|
class __declspec(dllexport) StringUtil {
|
||||||
public:
|
public:
|
||||||
static char* toUtf8(const wchar_t* utf16, int len = -1);
|
static std::string toUtf8(const wchar_t* utf16, int len = -1);
|
||||||
static wchar_t* toUtf16(const char* utf8, int len = -1);
|
static std::wstring toUtf16(const char* utf8, int len = -1);
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
static bool begins_with(const T& input, const T& match)
|
static bool begins_with(const T& input, const T& match)
|
||||||
{
|
{
|
||||||
return input.size() >= match.size()
|
return input.size() >= match.size()
|
||||||
&& equal(match.begin(), match.end(), input.begin());
|
&& std::equal(match.begin(), match.end(), input.begin());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue