OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo() { auto pipename = CommunicationSocket::DefaultPipePath(); CommunicationSocket socket; if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) { return {}; } if (!socket.Connect(pipename)) { return {}; } socket.SendMsg(L"SHARE_MENU_TITLE\n"); ContextMenuInfo info; std::wstring response; int sleptCount = 0; while (sleptCount < 5) { if (socket.ReadLine(&response)) { if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) { wstring responsePath = response.substr(14); // length of REGISTER_PATH info.watchedDirectories.push_back(responsePath); } else if (StringUtil::begins_with(response, wstring(L"SHARE_MENU_TITLE:"))) { info.shareMenuTitle = response.substr(17); // length of SHARE_MENU_TITLE: break; // Stop once we received the last sent request } } else { Sleep(50); ++sleptCount; } } return info; }
void OCClientInterface::ShareObject(const std::wstring &path) { auto pipename = CommunicationSocket::DefaultPipePath(); CommunicationSocket socket; if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) { return; } if (!socket.Connect(pipename)) { return; } wchar_t msg[SOCK_BUFFER] = { 0 }; if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"SHARE:%s\n", path.c_str()))) { socket.SendMsg(msg); } }
// This code is run in a thread void RemotePathChecker::workerThreadLoop() { auto pipename = CommunicationSocket::DefaultPipePath(); bool connected = false; CommunicationSocket socket; std::unordered_set<std::wstring> asked; while(!_stop) { Sleep(50); if (!connected) { asked.clear(); if (!WaitNamedPipe(pipename.data(), 100)) { continue; } if (!socket.Connect(pipename)) { continue; } connected = true; std::unique_lock<std::mutex> lock(_mutex); _connected = true; } { 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); } SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL); } else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) { wstring responsePath = response.substr(16); // length of UNREGISTER_PATH: { std::unique_lock<std::mutex> lock(_mutex); _watchedDirectories.erase( std::remove(_watchedDirectories.begin(), _watchedDirectories.end(), responsePath), _watchedDirectories.end()); // Remove any item from the cache for (auto it = _cache.begin(); it != _cache.end() ; ) { if (StringUtil::begins_with(it->first, responsePath)) { it = _cache.erase(it); } else { ++it; } } // Assume that we won't need this at this point, UNREGISTER_PATH is rare _oldCache.clear(); } SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL); } 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); bool wasAsked = asked.erase(responsePath) > 0; bool changed = false; { std::unique_lock<std::mutex> lock(_mutex); bool wasCached = _cache.find(responsePath) != _cache.end(); if (wasAsked || wasCached) { auto &it = _cache[responsePath]; changed = (it != state); it = state; } } if (changed) { SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL); } } else if (StringUtil::begins_with(response, wstring(L"UPDATE_VIEW"))) { std::unique_lock<std::mutex> lock(_mutex); // Keep the old states to continue having something to display while the new state is // requested from the client, triggered by clearing _cache. _oldCache.insert(_cache.cbegin(), _cache.cend()); // Swap to make a copy of the cache under the mutex and clear the one stored. std::unordered_map<std::wstring, FileState> cache; swap(cache, _cache); lock.unlock(); // Let explorer know about the invalidated cache entries, it will re-request the ones it needs. for (auto it = cache.begin(); it != cache.end(); ++it) { SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL); } } } if (socket.Event() == INVALID_HANDLE_VALUE) { std::unique_lock<std::mutex> lock(_mutex); _cache.clear(); _oldCache.clear(); _watchedDirectories.clear(); _connected = connected = false; } if (_stop) return; HANDLE handles[2] = { _newQueries, socket.Event() }; WaitForMultipleObjects(2, handles, false, 0); } }