diff --git a/build_release_x64.cmd b/build_release_x64.cmd index 7fb8323..8aeafe5 100644 --- a/build_release_x64.cmd +++ b/build_release_x64.cmd @@ -2,7 +2,7 @@ set ROOT=%~dp0% pushd "%ROOT%" -REM call 3rd_party\CEF\create.cmd Release +call 3rd_party\CEF\create.cmd Release mkdir build mkdir build\release diff --git a/htdocs/js/index.js b/htdocs/js/index.js index de8ff3b..350cd0b 100644 --- a/htdocs/js/index.js +++ b/htdocs/js/index.js @@ -114,6 +114,11 @@ console.log('Create wallet'); return window.appActions.createWallet(cb); } + + function _mountDrive(mountLocation, cb) { + console.log('Mount drive: ' + mountLocation); + return window.appActions.mountDrive(mountLocation, cb); + } function _startApp() { window.appActions.startApp(); @@ -124,15 +129,21 @@ } function _unlockWallet(pwd, cb) { - console.log('Unlock wallet'); return window.appActions.unlockWallet(pwd, cb); } + function _unmountDrive(cb) { + console.log('Unmount drive'); + return window.appActions.unmountDrive(cb); + } + return { createWallet: _createWallet, + mountDrive: _mountDrive, startApp: _startApp, stopApp: _stopApp, - unlockWallet: _unlockWallet + unlockWallet: _unlockWallet, + unmountDrive: _unmountDrive }; })(); @@ -162,6 +173,31 @@ function beginMainApplication() { AppActions.startApp(); setMainWindow('app_window'); + const mountButton = document.getElementById('ID_MountButton'); + + const mountHandler = ()=> { + mountButton.onclick = null; + if (mountButton.innerText === "Mount") { + AppActions.mountDrive(document.getElementById('ID_MountDrives').value, (success, reason) => { + if (success) { + mountButton.innerText = "Unmount"; + } else { + displayErrorPopup('Mount Failed', reason); + } + mountButton.onclick = mountHandler; + }); + } else { + AppActions.unmountDrive((success, reason) => { + if (success) { + mountButton.innerText = "Mount"; + } else { + displayErrorPopup('Unmount Failed', reason); + } + mountButton.onclick = mountHandler; + }); + } + }; + mountButton.onclick = mountHandler; } function handleUnlockWallet() { diff --git a/include/siadrive/siadriveapp.h b/include/siadrive/siadriveapp.h index 3c3b43a..235dc7a 100644 --- a/include/siadrive/siadriveapp.h +++ b/include/siadrive/siadriveapp.h @@ -11,6 +11,14 @@ namespace Api class CSiaApi; class CSiaCurl; class CSiaDriveConfig; +#ifdef _WIN32 + namespace Dokan + { + class CSiaDokanDrive; + } +#else + a +#endif } class CSiaDriveApp : @@ -26,6 +34,11 @@ private: std::unique_ptr _siaApi; std::unique_ptr _siaCurl; std::unique_ptr _siaDriveConfig; +#ifdef _WIN32 + std::unique_ptr _siaDrive; +#else + a +#endif bool _appStarted = false; SString _walletReceiveAddress; diff --git a/include/siadrive_api/filepath.h b/include/siadrive_api/filepath.h index a1dd58b..2810940 100644 --- a/include/siadrive_api/filepath.h +++ b/include/siadrive_api/filepath.h @@ -22,6 +22,8 @@ public: public: static SString FinalizePath(const SString& path); + static SString GetTempDirectory(); + static SString GetAppDataDirectory(); private: SString _path; @@ -37,6 +39,7 @@ public: bool DeleteFile() const; bool MoveFile(const FilePath& filePath); FilePath& RemoveFileName(); + FilePath& MakeAbsolute(); public: FilePath& operator=(const FilePath& filePath); diff --git a/include/siadrive_api/sstring.h b/include/siadrive_api/sstring.h index f1fd5a3..3515b24 100644 --- a/include/siadrive_api/sstring.h +++ b/include/siadrive_api/sstring.h @@ -351,6 +351,12 @@ public: return std::equal(str.str().rbegin(), str.str().rend(), _str.rbegin()); } + SString& Fit() + { + _str = _str.c_str(); + return *this; + } + SString &ToLower() { std::transform(_str.begin(), _str.end(), _str.begin(), ::tolower); diff --git a/src/siadrive/siadriveapp.cpp b/src/siadrive/siadriveapp.cpp index 5101c7a..69fe5d6 100644 --- a/src/siadrive/siadriveapp.cpp +++ b/src/siadrive/siadriveapp.cpp @@ -8,6 +8,7 @@ #include #include #include "siadrivehandler.h" +#include /* Work Laptop vitals thirsty tattoo unjustly already lexicon ruthless rated skater voyage avoid jeers aunt tawny richly glass menu kidneys went wounded wounded trendy towel lipstick raking bacon dozen blip aggravate */ @@ -98,6 +99,21 @@ public: _appStarted = false; return true; } + else if (name == "mountDrive") + { + retval = CefV8Value::CreateBool(true); + SString drive = arguments[0]->GetStringValue().ToWString(); + CefRefPtr cb = arguments[1]; + + return true; + } + else if (name == "unmountDrive") + { + retval = CefV8Value::CreateBool(true); + CefRefPtr cb = arguments[0]; + + return true; + } // Function does not exist. return false; @@ -156,14 +172,16 @@ CSiaDriveApp::CSiaDriveApp() hostConfig.RequiredVersion = COMPAT_SIAD_VERSION; _siaCurl.reset(new CSiaCurl(hostConfig)); _siaApi.reset(new CSiaApi(hostConfig, _siaDriveConfig.get())); +#ifdef _WIN32 + _siaDrive.reset(new Dokan::CSiaDokanDrive(*_siaApi, _siaDriveConfig.get())); +#else + a +#endif } void CSiaDriveApp::ExecuteSetter(CefRefPtr context, CefRefPtr obj, const SString& method, const SString& value) { - CefRefPtr setConfirmed = obj->GetValue(method.str()); - CefV8ValueList args; - args.push_back(CefV8Value::CreateString(value.str())); - setConfirmed->ExecuteFunctionWithContext(context, nullptr, args); + ExecuteSetter(context, obj, method, CefV8Value::CreateString(value.str())); } void CSiaDriveApp::ExecuteSetter(CefRefPtr context, CefRefPtr obj, const SString& method, CefRefPtr value) @@ -195,6 +213,8 @@ void CSiaDriveApp::OnContextCreated( obj->SetValue("createWallet", CefV8Value::CreateFunction("createWallet", handler), V8_PROPERTY_ATTRIBUTE_NONE); obj->SetValue("startApp", CefV8Value::CreateFunction("startApp", handler), V8_PROPERTY_ATTRIBUTE_NONE); obj->SetValue("stopApp", CefV8Value::CreateFunction("stopApp", handler), V8_PROPERTY_ATTRIBUTE_NONE); + obj->SetValue("mountDrive", CefV8Value::CreateFunction("mountDrive", handler), V8_PROPERTY_ATTRIBUTE_NONE); + obj->SetValue("unmountDrive", CefV8Value::CreateFunction("unmountDrive", handler), V8_PROPERTY_ATTRIBUTE_NONE); global->SetValue("appActions", obj, V8_PROPERTY_ATTRIBUTE_NONE); _refreshThread.reset(new CAutoThread(*_siaCurl, _siaDriveConfig.get(), [this, context](const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig) @@ -258,6 +278,8 @@ void CSiaDriveApp::OnContextReleased(CefRefPtr browser, CefRefPtrStopAutoThread(); _refreshThread.reset(nullptr); + _siaDrive->Unmount(); + _siaDrive.reset(nullptr); } } @@ -326,7 +348,7 @@ void CSiaDriveApp::SiaApiRefreshCallback(CefRefPtr context, const auto driveList = CefV8Value::CreateArray(drives.size()); for (size_t i = 0; i < drives.size(); i++) { - driveList->SetValue(i, CefV8Value::CreateString(drives[i].str())); + driveList->SetValue(i, CefV8Value::CreateString((drives[i] + ":\\").str())); } ExecuteSetter(context, uiUpdate, "setAvailableDriveLetters", driveList); diff --git a/src/siadrive_api/filepath.cpp b/src/siadrive_api/filepath.cpp index 9153d95..82351a4 100644 --- a/src/siadrive_api/filepath.cpp +++ b/src/siadrive_api/filepath.cpp @@ -1,6 +1,8 @@ #include #include - +#ifdef _WIN32 +#include +#endif using namespace Sia::Api; SString FilePath::FinalizePath(const SString& path) @@ -14,6 +16,31 @@ SString FilePath::FinalizePath(const SString& path) #endif } +SString FilePath::GetTempDirectory() +{ +#ifdef _WIN32 + SString tempPath; + tempPath.Resize(MAX_PATH + 1); + GetTempPath(MAX_PATH, &tempPath[0]); + return std::move(tempPath.Fit()); +#else + a +#endif +} + +SString FilePath::GetAppDataDirectory() +{ +#ifdef _WIN32 + PWSTR localAppData = nullptr; + ::SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &localAppData); + SString ret = localAppData; + ::CoTaskMemFree(localAppData); + return ret; +#else + a +#endif +} + FilePath::FilePath() { } @@ -184,3 +211,18 @@ FilePath::operator SString() const return _path; } +FilePath& FilePath::MakeAbsolute() +{ +#ifdef _DEBUG + if (::PathIsRelative(&_path[0])) + { + SString temp; + temp.Resize(MAX_PATH + 1); + _path = _wfullpath(&temp[0], &_path[0], MAX_PATH); + } +#else + a +#endif + + return *this; +} diff --git a/src/siadrive_api/siadriveconfig.cpp b/src/siadrive_api/siadriveconfig.cpp index 29ac7ba..b0bf200 100644 --- a/src/siadrive_api/siadriveconfig.cpp +++ b/src/siadrive_api/siadriveconfig.cpp @@ -1,9 +1,6 @@ #include #include #include -#ifdef _WIN32 -#include -#endif using namespace Sia::Api; @@ -15,10 +12,8 @@ CSiaDriveConfig::CSiaDriveConfig() : CSiaDriveConfig::CSiaDriveConfig(const SString& filePath) : _FilePath(filePath) { -#ifdef _WIN32 #ifdef _DEBUG - ::DeleteFile(filePath.str().c_str()); -#endif + FilePath(filePath).DeleteFile(); #endif Load(); } @@ -31,33 +26,15 @@ CSiaDriveConfig::~CSiaDriveConfig() void CSiaDriveConfig::LoadDefaults() { SetRenter_UploadDbFilePath(static_cast(FilePath(DEFAULT_RENTER_DB_FILE_PATH))); -#ifdef _WIN32 - SString tempFolder; - tempFolder.Resize(MAX_PATH + 1); - ::GetTempPath(MAX_PATH, &tempFolder[0]); - tempFolder = tempFolder.str().c_str(); - SetTempFolder(tempFolder); + FilePath tempFolder = FilePath::GetTempDirectory(); + SetTempFolder(static_cast(tempFolder)); - PWSTR localAppData = nullptr; - ::SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &localAppData); + FilePath cacheFolder(FilePath::GetAppDataDirectory(), "SiaDrive"); + cacheFolder.Append("Cache"); - SString sdFolder; - sdFolder.Resize(MAX_PATH + 1); - ::PathCombine(&sdFolder[0], localAppData, L"SiaDrive"); - ::CreateDirectory(sdFolder.str().c_str(), nullptr); - sdFolder = sdFolder.str().c_str(); + SetCacheFolder(static_cast(cacheFolder)); - SString cacheFolder; - cacheFolder.Resize(MAX_PATH + 1); - ::PathCombine(&cacheFolder[0], &sdFolder[0], L"Cache"); - ::CreateDirectory(cacheFolder.str().c_str(), nullptr); - cacheFolder = cacheFolder.str().c_str(); - - SetCacheFolder(cacheFolder); -#else - a -#endif SetHostNameOrIp("localhost"); SetHostPort(9980); } diff --git a/src/siadrive_api/uploadmanager.cpp b/src/siadrive_api/uploadmanager.cpp index 20325eb..a830e62 100644 --- a/src/siadrive_api/uploadmanager.cpp +++ b/src/siadrive_api/uploadmanager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace Sia::Api; #define TABLE_CREATE L"create table if not exists %s (%s);" @@ -143,17 +144,13 @@ void CUploadManager::UpdateFileQueueOnStartup() SString siaDriveFilePath = static_cast(query.getColumn(query.getColumnIndex("sd_file_path"))); UploadStatus uploadStatus = static_cast(query.getColumn(query.getColumnIndex("status")).getUInt()); - SString temp = filePath; - ::PathRemoveFileSpec(&temp[0]); - SString rootPath = temp; + FilePath rootPath = filePath; + rootPath.RemoveFileName(); // Strip drive specification (i.e. C:\) // TODO If mount to folder is ever enabled, this will need to change SString siaDriveFileName = GenerateSha256(&filePath[3]) + L".siadrive"; - - SString tempSourcePath; - tempSourcePath.Resize(MAX_PATH + 1); - ::PathCombine(&tempSourcePath[0], rootPath.str().c_str(), (siaDriveFileName + L".temp").str().c_str()); + FilePath tempSourcePath(rootPath, (siaDriveFileName + L".temp")); std::lock_guard l(_fileQueueMutex); if (uploadStatus == UploadStatus::Remove) @@ -221,15 +218,15 @@ void CUploadManager::HandleFileRemove(const CSiaCurl& siaCurl, const SString& si query.bind("@sia_path", SString::ToUtf8(siaPath).c_str()); if (query.executeStep()) { - SString removeFilePath = static_cast(query.getColumn(query.getColumnIndex("file_path"))); + FilePath removeFilePath = SString(static_cast(query.getColumn(query.getColumnIndex("file_path")))); UploadStatus uploadStatus = static_cast(static_cast(query.getColumn(query.getColumnIndex("status")))); // Make sure status is still remove if (uploadStatus == UploadStatus::Remove) { bool deleteFromDb = true; - if (::PathFileExists(removeFilePath.str().c_str())) + if (removeFilePath.IsFile()) { - if (RetryDeleteFileIfExists(removeFilePath.str().c_str())) + if (RetryDeleteFileIfExists(removeFilePath)) { if (!RetryDeleteFileIfExists(siaDriveFilePath)) { @@ -280,7 +277,7 @@ void CUploadManager::HandleFileRemove(const CSiaCurl& siaCurl, const SString& si void CUploadManager::HandleAddFile(const SString& siaPath, const SString& filePath, const SString& tempSourcePath, const SString& siaDriveFilePath) { // Check for retry condition - if (!::PathFileExists(tempSourcePath.str().c_str()) && ::PathFileExists(siaDriveFilePath.str().c_str())) + if (!FilePath(tempSourcePath).IsFile() && FilePath(siaDriveFilePath).IsFile()) { try { @@ -555,21 +552,10 @@ UploadError CUploadManager::AddOrUpdate(const SString& siaPath, SString filePath UploadError ret = UploadError::Success; // Relative to absolute and grab parent folder of source - SString rootPath; - { - SString temp; - if (::PathIsRelative(filePath.str().c_str())) - { - temp.Resize(MAX_PATH + 1); - filePath = _wfullpath(&temp[0], filePath.str().c_str(), MAX_PATH); - } + FilePath rootPath = filePath; + rootPath.MakeAbsolute().RemoveFileName(); - temp = filePath; - ::PathRemoveFileSpec(&temp[0]); - rootPath = temp; - } - - if (::PathFileExists(filePath.str().c_str())) + if (FilePath(filePath).IsFile()) { // Lock here - if file is modified again before a prior upload is complete, delete it and // start again later @@ -597,14 +583,8 @@ UploadError CUploadManager::AddOrUpdate(const SString& siaPath, SString filePath // TODO If mount to folder is ever enabled, this will need to change // TODO Case sensative file names? Going to be a bit of an issue. SString siaDriveFileName = GenerateSha256(&filePath[3]) + L".siadrive"; - - SString siaDriveFilePath; - siaDriveFilePath.Resize(MAX_PATH + 1); - ::PathCombine(&siaDriveFilePath[0], rootPath.str().c_str(), siaDriveFileName.str().c_str()); - - SString tempSourcePath; - tempSourcePath.Resize(MAX_PATH + 1); - ::PathCombine(&tempSourcePath[0], rootPath.str().c_str(), (siaDriveFileName + L".temp").str().c_str()); + FilePath siaDriveFilePath(rootPath, siaDriveFileName); + FilePath tempSourcePath(rootPath, (siaDriveFileName + L".temp")); // Add to db try @@ -655,7 +635,7 @@ UploadError CUploadManager::Remove(const SString& siaPath) std::lock_guard l(_uploadMutex); try { - bool remove = false; + bool remove; SQLite::Statement query(_uploadDatabase, QUERY_STATUS); query.bind("@sia_path", SString::ToUtf8(siaPath).c_str());