#include "stdafx.h" #include "UploadManager.h" #include "SiaDriveConfig.h" #include "SiaApi.h" using namespace Sia::Api; #define TABLE_CREATE L"create table if not exists %s (%s);" #define UPLOAD_TABLE L"upload_table" #define UPLOAD_TABLE_COLUMNS L"id integer primary key autoincrement, sia_path text unique not null, cache_path text unique not null, status integer not null" #define QUERY_UPLOADS_BY_STATUS "select id, sia_path, status from upload_table where status=@status order by id desc limit 1;" #define QUERY_UPLOADS_BY_2_STATUS "select id, sia_path, status from upload_table where (status=@status1 or status=@status2) order by id desc limit 1;" #define QUERY_UPLOADS_BY_SIA_PATH "select id, sia_path, status from upload_table where sia_path=@sia_path order by id desc limit 1;" #define QUERY_UPLOADS_BY_SIA_PATH_AND_2_STATUS "select id, sia_path, status from upload_table where sia_path=@sia_path and (status=@status1 or status=@status2) order by id desc limit 1;" template String fmt(const String &fmt, Ts... vs) { size_t required = _sntprintf(nullptr, 0, fmt.c_str(), vs...); String ret; ret.resize(required); _sntprintf(&ret[0], required, fmt.c_str(), vs...); return ret; } static void CreateTableIfNotFound(SQLite::Database* database, const String& tableName, const String& columns) { String sqlCreate = fmt(TABLE_CREATE, &tableName[0], &columns[0]); database->exec(CW2A(sqlCreate.c_str())); } CUploadManager::CUploadManager(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig) : CAutoThread(siaCurl, siaDriveConfig), _uploadDatabase(siaDriveConfig->GetRenter_UploadDbFilePath(), SQLite::OPEN_CREATE | SQLite::OPEN_READWRITE) { CreateTableIfNotFound(&_uploadDatabase, UPLOAD_TABLE, UPLOAD_TABLE_COLUMNS); StartAutoThread(); } CUploadManager::~CUploadManager() { StopAutoThread(); } void CUploadManager::AutoThreadCallback(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig) { bool processNext = true; try { CSiaFileTreePtr fileTree(new CSiaFileTree(siaCurl, siaDriveConfig)); json result; if (ApiSuccess(siaCurl.Get(L"/renter/files", result))) { SQLite::Statement query(_uploadDatabase, QUERY_UPLOADS_BY_2_STATUS); query.bind("@status1", static_cast(UploadStatus::Uploading)); query.bind("@status2", static_cast(UploadStatus::Modified)); // TODO Lock here - if file is modified again before a prior upload is complete, delete it and start again later fileTree->BuildTree(result); if (query.executeStep()) { std::string tempSiaPath = query.getColumn(1); String siaPath = CA2W(tempSiaPath.c_str()).m_psz; UploadStatus uploadStatus = static_cast(query.getColumn(2).getUInt()); auto fileList = fileTree->GetFileList(); auto it = std::find_if(fileList.begin(), fileList.end(), [&](const CSiaFilePtr& ptr) { return ptr->GetSiaPath() == siaPath; }); if (it == fileList.end()) { // error condition - should always exist. delete from db and log warning, but continue processing } else if (uploadStatus == UploadStatus::Modified) { // delete existing, change status to queued } else if ((*it)->GetUploadProgress() >= 100) { // upload complete - change status } else { // upload still active processNext = false; } } } else { // error condition - host down? processNext = false; } } catch (const SQLite::Exception& e) { // error condition - database not initialized (i.e. no table)? std::string msg = e.what(); processNext = false; } if (processNext) { try { SQLite::Statement query(_uploadDatabase, QUERY_UPLOADS_BY_STATUS); query.bind("@status", static_cast(UploadStatus::Queued)); // TODO Lock here - if file is modified again before a prior upload is complete, delete it and start again later if (query.executeStep()) { String siaPath = CA2W(query.getColumn(1)).m_psz; String tempFilePath; json response; SiaCurlError cerror = siaCurl.Post(String(L"/renter/upload/") + siaPath, { {L"source", tempFilePath} }, response); if (ApiSuccess(cerror)) { // TODO Update status in DB } } } catch (const SQLite::Exception& e) { // error condition std::string msg = e.what(); } } } UploadStatus CUploadManager::GetUploadStatus(const String& siaPath) { UploadStatus uploadStatus = UploadStatus::NotFound; SQLite::Statement query(_uploadDatabase, QUERY_UPLOADS_BY_SIA_PATH); query.bind("@sia_path", CW2A(siaPath.c_str()).m_psz); if (query.executeStep()) { uploadStatus = static_cast(static_cast(query.getColumn(2))); } return uploadStatus; } void CUploadManager::AddOrUpdate(const String& siaPath, const String& filePath) { SQLite::Statement query(_uploadDatabase, QUERY_UPLOADS_BY_SIA_PATH_AND_2_STATUS); query.bind("@sia_path", CW2A(siaPath.c_str()).m_psz); query.bind("@status1", static_cast(UploadStatus::Uploading)); query.bind("@status2", static_cast(UploadStatus::Modified)); // TODO Lock here - if file is modified again before a prior upload is complete, delete it and start again later if (query.executeStep()) { if (static_cast(static_cast(query.getColumn(2))) == UploadStatus::Uploading) { // set to modified // update file path } } else { } } void CUploadManager::PurgeCompleteStatus() { } void CUploadManager::PurgeErrorStatus() { } void CUploadManager::Remove(const String& siaPath) { }