Commit bd94ea0d authored by Paweł Wegner's avatar Paweł Wegner

Refactored download, upload to use EitherError.

parent d8d79299
......@@ -84,7 +84,10 @@ class MockProvider : public ICloudProvider {
IDownloadFileCallback::Pointer);
void finish() override { function_.wait(); }
void cancel() override { function_.wait(); }
void result() override { function_.get(); }
EitherError<void> result() override {
function_.get();
return nullptr;
}
private:
IDownloadFileCallback::Pointer callback_;
......
......@@ -96,12 +96,12 @@ class DownloadFileCallback : public cloudstorage::IDownloadFileCallback {
void done() override {
file_.close();
callback_(true);
callback_(nullptr);
}
void error(const std::string&) override {
void error(const std::string& error) override {
file_.close();
callback_(false);
callback_(cloudstorage::Error{400, error});
}
void progress(uint32_t, uint32_t) override {}
......@@ -134,9 +134,11 @@ class UploadFileCallback : public cloudstorage::IUploadFileCallback {
uint64_t size() override { return size_; }
void done() override { callback_(true); }
void done() override { callback_(nullptr); }
void error(const std::string&) override { callback_(false); }
void error(const std::string& d) override {
callback_(cloudstorage::Error{400, d});
}
void progress(uint32_t, uint32_t) override {}
......
......@@ -108,7 +108,7 @@ class TransferListener : public mega::MegaTransferListener, public Listener {
IDownloadFileCallback::Pointer download_callback_;
IUploadFileCallback::Pointer upload_callback_;
Request<void>* request_;
Request<EitherError<void>>* request_;
std::string error_;
};
......@@ -143,7 +143,7 @@ class HttpData : public IHttpServer::IResponse::ICallback {
}
Buffer::Pointer buffer_;
std::shared_ptr<Request<void>> request_;
std::shared_ptr<Request<EitherError<void>>> request_;
};
class HttpDataCallback : public IDownloadFileCallback {
......@@ -177,7 +177,7 @@ IHttpServer::IResponse::Pointer MegaNz::HttpServerCallback::receivedConnection(
if (!node) return server.createResponse(404, {}, "file not found");
auto buffer = std::make_shared<Buffer>();
auto data = util::make_unique<HttpData>(buffer);
auto request = std::make_shared<Request<void>>(
auto request = std::make_shared<Request<EitherError<void>>>(
std::weak_ptr<CloudProvider>(provider_->shared_from_this()));
data->request_ = request;
provider_->addStreamRequest(request);
......@@ -352,10 +352,10 @@ ICloudProvider::ListDirectoryRequest::Pointer MegaNz::listDirectoryAsync(
-> EitherError<std::vector<IItem::Pointer>> {
if (!ensureAuthorized(r)) {
Error e = {401, "authorization failed"};
if (!r->is_cancelled()) {
e = {IHttpRequest::Aborted, ""};
if (!r->is_cancelled())
callback->error("Authorization failed.");
}
else
e = {IHttpRequest::Aborted, ""};
return e;
}
std::unique_ptr<mega::MegaNode> node(
......@@ -379,7 +379,7 @@ ICloudProvider::ListDirectoryRequest::Pointer MegaNz::listDirectoryAsync(
ICloudProvider::DownloadFileRequest::Pointer MegaNz::downloadFileAsync(
IItem::Pointer item, IDownloadFileCallback::Pointer callback) {
auto r = util::make_unique<Request<void>>(shared_from_this());
auto r = util::make_unique<Request<EitherError<void>>>(shared_from_this());
r->set_resolver(downloadResolver(item, callback));
return std::move(r);
}
......@@ -387,25 +387,35 @@ ICloudProvider::DownloadFileRequest::Pointer MegaNz::downloadFileAsync(
ICloudProvider::UploadFileRequest::Pointer MegaNz::uploadFileAsync(
IItem::Pointer item, const std::string& filename,
IUploadFileCallback::Pointer callback) {
auto r = util::make_unique<Request<void>>(shared_from_this());
r->set_resolver([this, item, callback, filename](Request<void>* r) {
auto r = util::make_unique<Request<EitherError<void>>>(shared_from_this());
r->set_resolver([this, item, callback, filename](
Request<EitherError<void>>* r) -> EitherError<void> {
if (!ensureAuthorized(r)) {
if (!r->is_cancelled()) callback->error("Authorization failed.");
return;
Error e = {401, "authorization failed"};
if (!r->is_cancelled())
callback->error("Authorization failed.");
else
e = {IHttpRequest::Aborted, ""};
return e;
}
std::string cache = temporaryFileName();
{
std::fstream mega_cache(cache.c_str(),
std::fstream::out | std::fstream::binary);
if (!mega_cache)
return callback->error("Couldn't open cache file " + cache);
if (!mega_cache) {
callback->error("Couldn't open cache file " + cache);
return Error{403, "couldn't open cache file" + cache};
}
std::array<char, BUFFER_SIZE> buffer;
while (auto length = callback->putData(buffer.data(), BUFFER_SIZE)) {
if (r->is_cancelled()) return;
if (r->is_cancelled()) {
std::remove(cache.c_str());
return Error{IHttpRequest::Aborted, ""};
}
mega_cache.write(buffer.data(), length);
}
}
Request<void>::Semaphore semaphore(r);
Request<EitherError<void>>::Semaphore semaphore(r);
TransferListener listener(&semaphore);
listener.upload_callback_ = callback;
listener.request_ = r;
......@@ -415,26 +425,36 @@ ICloudProvider::UploadFileRequest::Pointer MegaNz::uploadFileAsync(
semaphore.wait();
if (r->is_cancelled())
while (listener.status_ == Listener::IN_PROGRESS) semaphore.wait();
std::remove(cache.c_str());
mega_->removeTransferListener(&listener);
if (listener.status_ != Listener::SUCCESS) {
if (!r->is_cancelled())
if (!r->is_cancelled()) {
callback->error("Upload error: " + listener.error_);
} else
return Error{500, listener.error_};
} else
return Error{IHttpRequest::Aborted, ""};
} else {
callback->done();
std::remove(cache.c_str());
return nullptr;
}
});
return std::move(r);
}
ICloudProvider::DownloadFileRequest::Pointer MegaNz::getThumbnailAsync(
IItem::Pointer item, IDownloadFileCallback::Pointer callback) {
auto r = util::make_unique<Request<void>>(shared_from_this());
r->set_resolver([this, item, callback](Request<void>* r) {
auto r = util::make_unique<Request<EitherError<void>>>(shared_from_this());
r->set_resolver([this, item, callback](
Request<EitherError<void>>* r) -> EitherError<void> {
if (!ensureAuthorized(r)) {
if (!r->is_cancelled()) callback->error("Authorization failed.");
return;
Error e = {401, "authorization failed"};
if (!r->is_cancelled())
callback->error("Authorization failed.");
else
e = {IHttpRequest::Aborted, ""};
return e;
}
Request<void>::Semaphore semaphore(r);
Request<EitherError<void>>::Semaphore semaphore(r);
RequestListener listener(&semaphore);
std::string cache = temporaryFileName();
std::unique_ptr<mega::MegaNode> node(
......@@ -447,8 +467,10 @@ ICloudProvider::DownloadFileRequest::Pointer MegaNz::getThumbnailAsync(
if (listener.status_ == Listener::SUCCESS) {
std::fstream cache_file(cache.c_str(),
std::fstream::in | std::fstream::binary);
if (!cache_file)
return callback->error("Couldn't open cache file " + cache);
if (!cache_file) {
callback->error("Couldn't open cache file " + cache);
return Error{500, "couldn't open cache file " + cache};
}
std::array<char, BUFFER_SIZE> buffer;
do {
cache_file.read(buffer.data(), BUFFER_SIZE);
......@@ -459,6 +481,7 @@ ICloudProvider::DownloadFileRequest::Pointer MegaNz::getThumbnailAsync(
cloudstorage::DownloadFileRequest::generateThumbnail(r, item, callback);
}
std::remove(cache.c_str());
return nullptr;
});
return std::move(r);
}
......@@ -589,17 +612,23 @@ ICloudProvider::RenameItemRequest::Pointer MegaNz::renameItemAsync(
return std::move(r);
}
std::function<void(Request<void>*)> MegaNz::downloadResolver(
IItem::Pointer item, IDownloadFileCallback::Pointer callback, int64_t start,
int64_t size) {
return [this, item, callback, start, size](Request<void>* r) {
std::function<EitherError<void>(Request<EitherError<void>>*)>
MegaNz::downloadResolver(IItem::Pointer item,
IDownloadFileCallback::Pointer callback, int64_t start,
int64_t size) {
return [this, item, callback, start,
size](Request<EitherError<void>>* r) -> EitherError<void> {
if (!ensureAuthorized(r)) {
if (!r->is_cancelled()) callback->error("Authorization failed.");
return;
Error e = {401, "authorization failed"};
if (!r->is_cancelled())
callback->error("Authorization failed.");
else
e = {IHttpRequest::Aborted, ""};
return e;
}
std::unique_ptr<mega::MegaNode> node(
mega_->getNodeByPath(item->id().c_str()));
Request<void>::Semaphore semaphore(r);
Request<EitherError<void>>::Semaphore semaphore(r);
TransferListener listener(&semaphore);
listener.download_callback_ = callback;
listener.request_ = r;
......@@ -611,9 +640,15 @@ std::function<void(Request<void>*)> MegaNz::downloadResolver(
while (listener.status_ == Listener::IN_PROGRESS) semaphore.wait();
mega_->removeTransferListener(&listener);
if (listener.status_ != Listener::SUCCESS) {
if (!r->is_cancelled()) callback->error("Failed to download");
} else
if (!r->is_cancelled()) {
callback->error("Failed to download");
return Error{500, "failed to download"};
} else
return Error{IHttpRequest::Aborted, ""};
} else {
callback->done();
return nullptr;
}
};
}
......
......@@ -87,9 +87,9 @@ class MegaNz : public CloudProvider {
const std::string& name,
RenameItemCallback) override;
std::function<void(Request<void>*)> downloadResolver(
IItem::Pointer item, IDownloadFileCallback::Pointer, int64_t start = 0,
int64_t size = -1);
std::function<EitherError<void>(Request<EitherError<void>>*)>
downloadResolver(IItem::Pointer item, IDownloadFileCallback::Pointer,
int64_t start = 0, int64_t size = -1);
bool login(Request<bool>* r);
std::string passwordHash(const std::string& password) const;
......
......@@ -44,13 +44,14 @@ std::string OneDrive::endpoint() const { return "https://api.onedrive.com"; }
ICloudProvider::UploadFileRequest::Pointer OneDrive::uploadFileAsync(
IItem::Pointer parent, const std::string& filename,
IUploadFileCallback::Pointer callback) {
auto r = util::make_unique<Request<void>>(shared_from_this());
r->set_error_callback(
[callback](Request<void>* r, int code, const std::string& desc) {
callback->error(r->error_string(code, desc));
});
r->set_resolver([=](Request<void>* r) {
auto r = util::make_unique<Request<EitherError<void>>>(shared_from_this());
r->set_error_callback([callback](Request<EitherError<void>>* r, int code,
const std::string& desc) {
callback->error(r->error_string(code, desc));
});
r->set_resolver([=](Request<EitherError<void>>* r) -> EitherError<void> {
std::stringstream output;
Error error;
int code = r->sendRequest(
[=](std::ostream&) {
return http()->create(
......@@ -58,10 +59,10 @@ ICloudProvider::UploadFileRequest::Pointer OneDrive::uploadFileAsync(
http()->escape(filename) + ":/upload.createSession",
"POST");
},
output);
output, &error);
if (!IHttpRequest::isSuccess(code)) {
callback->error("Failed to create upload session.");
return;
return error;
}
Json::Value response;
output >> response;
......@@ -70,6 +71,7 @@ ICloudProvider::UploadFileRequest::Pointer OneDrive::uploadFileAsync(
std::vector<char> buffer(CHUNK_SIZE);
while (sent < size) {
uint32_t length = callback->putData(buffer.begin().base(), CHUNK_SIZE);
Error error;
code = r->sendRequest(
[=](std::ostream& stream) {
auto request =
......@@ -81,17 +83,18 @@ ICloudProvider::UploadFileRequest::Pointer OneDrive::uploadFileAsync(
stream.write(buffer.data(), length);
return request;
},
output, nullptr,
output, &error,
[=](uint32_t, uint32_t now) {
callback->progress(size, sent + now);
});
if (!IHttpRequest::isSuccess(code)) {
callback->error("Failed to upload chunk.");
return;
return error;
}
sent += length;
}
callback->done();
return nullptr;
});
return std::move(r);
}
......
......@@ -49,10 +49,9 @@ IItem::Pointer YandexDisk::rootDirectory() const {
ICloudProvider::GetItemDataRequest::Pointer YandexDisk::getItemDataAsync(
const std::string& id, GetItemDataCallback callback) {
auto r = util::make_unique<Request<EitherError<IItem>>>(
shared_from_this());
r->set_resolver([this, id, callback](Request<EitherError<IItem>>* r)
-> EitherError<IItem> {
auto r = util::make_unique<Request<EitherError<IItem>>>(shared_from_this());
r->set_resolver([this, id, callback](
Request<EitherError<IItem>>* r) -> EitherError<IItem> {
std::stringstream output;
Error error;
int code = r->sendRequest(
......@@ -92,12 +91,13 @@ ICloudProvider::GetItemDataRequest::Pointer YandexDisk::getItemDataAsync(
ICloudProvider::DownloadFileRequest::Pointer YandexDisk::downloadFileAsync(
IItem::Pointer item, IDownloadFileCallback::Pointer callback) {
auto r = util::make_unique<Request<void>>(shared_from_this());
r->set_error_callback(
[this, callback](Request<void>* r, int code, const std::string& desc) {
callback->error(r->error_string(code, desc));
});
r->set_resolver([this, item, callback](Request<void>* r) -> void {
auto r = util::make_unique<Request<EitherError<void>>>(shared_from_this());
r->set_error_callback([this, callback](Request<EitherError<void>>* r,
int code, const std::string& desc) {
callback->error(r->error_string(code, desc));
});
r->set_resolver([this, item, callback](
Request<EitherError<void>>* r) -> EitherError<void> {
std::stringstream output;
int code = r->sendRequest(
[this, item](std::ostream&) {
......@@ -129,13 +129,15 @@ ICloudProvider::DownloadFileRequest::Pointer YandexDisk::downloadFileAsync(
ICloudProvider::UploadFileRequest::Pointer YandexDisk::uploadFileAsync(
IItem::Pointer directory, const std::string& filename,
IUploadFileCallback::Pointer callback) {
auto r = util::make_unique<Request<void>>(shared_from_this());
r->set_error_callback(
[callback](Request<void>* r, int code, const std::string& desc) {
callback->error(r->error_string(code, desc));
});
r->set_resolver([this, directory, filename, callback](Request<void>* r) {
auto r = util::make_unique<Request<EitherError<void>>>(shared_from_this());
r->set_error_callback([callback](Request<EitherError<void>>* r, int code,
const std::string& desc) {
callback->error(r->error_string(code, desc));
});
r->set_resolver([this, directory, filename,
callback](Request<EitherError<void>>* r) {
std::stringstream output;
Error error;
int code = r->sendRequest(
[this, directory, filename](std::ostream&) {
auto request =
......@@ -146,7 +148,7 @@ ICloudProvider::UploadFileRequest::Pointer YandexDisk::uploadFileAsync(
request->setParameter("path", path);
return request;
},
output);
output, &error);
if (IHttpRequest::isSuccess(code)) {
Json::Value response;
output >> response;
......@@ -162,11 +164,16 @@ ICloudProvider::UploadFileRequest::Pointer YandexDisk::uploadFileAsync(
input.rdbuf(&wrapper);
return request;
},
output, nullptr,
output, &error,
std::bind(&IUploadFileCallback::progress, callback.get(), _1, _2));
if (IHttpRequest::isSuccess(code)) callback->done();
} else
if (IHttpRequest::isSuccess(code))
callback->done();
else
return error;
} else {
callback->error("Couldn't get upload url.");
return error;
}
});
return std::move(r);
}
......
......@@ -161,15 +161,16 @@ ICloudProvider::GetItemDataRequest::Pointer YouTube::getItemDataAsync(
ICloudProvider::DownloadFileRequest::Pointer YouTube::downloadFileAsync(
IItem::Pointer item, IDownloadFileCallback::Pointer callback) {
auto r = util::make_unique<Request<void>>(shared_from_this());
r->set_error_callback(
[this, callback](Request<void>* r, int code, const std::string& desc) {
callback->error(r->error_string(code, desc));
});
r->set_resolver([this, item, callback](Request<void>* r) -> void {
auto r = util::make_unique<Request<EitherError<void>>>(shared_from_this());
r->set_error_callback([this, callback](Request<EitherError<void>>* r,
int code, const std::string& desc) {
callback->error(r->error_string(code, desc));
});
r->set_resolver([this, item, callback](
Request<EitherError<void>>* r) -> EitherError<void> {
std::string url = item->url();
if (item->type() == IItem::FileType::Audio) {
Request<void>::Semaphore semaphore(r);
Request<EitherError<void>>::Semaphore semaphore(r);
auto t = getItemDataAsync(
item->id(), [&semaphore](EitherError<IItem>) { semaphore.notify(); });
semaphore.wait();
......@@ -181,11 +182,17 @@ ICloudProvider::DownloadFileRequest::Pointer YouTube::downloadFileAsync(
DownloadStreamWrapper wrapper(std::bind(
&IDownloadFileCallback::receivedData, callback.get(), _1, _2));
std::ostream stream(&wrapper);
Error error;
int code = r->sendRequest(
[this, url](std::ostream&) { return http()->create(url, "GET"); },
stream, nullptr,
stream, &error,
std::bind(&IDownloadFileCallback::progress, callback.get(), _1, _2));
if (IHttpRequest::isSuccess(code)) callback->done();
if (IHttpRequest::isSuccess(code)) {
callback->done();
return nullptr;
} else {
return error;
}
});
return std::move(r);
}
......
......@@ -47,8 +47,8 @@ class ICloudProvider {
using ListDirectoryRequest =
IRequest<EitherError<std::vector<IItem::Pointer>>>;
using GetItemRequest = IRequest<EitherError<IItem>>;
using DownloadFileRequest = IRequest<void>;
using UploadFileRequest = IRequest<void>;
using DownloadFileRequest = IRequest<EitherError<void>>;
using UploadFileRequest = IRequest<EitherError<void>>;
using GetItemDataRequest = IRequest<EitherError<IItem>>;
using DeleteItemRequest = IRequest<EitherError<void>>;
using CreateDirectoryRequest = IRequest<EitherError<IItem>>;
......@@ -379,7 +379,7 @@ class ICloudProvider {
*/
virtual DownloadFileRequest::Pointer downloadFileAsync(
IItem::Pointer item, const std::string& filename,
DownloadFileCallback callback = [](bool) {}) = 0;
DownloadFileCallback callback = [](EitherError<void>) {}) = 0;
/**
* Simplified version of getThumbnailAsync.
......@@ -395,7 +395,7 @@ class ICloudProvider {
*/
virtual DownloadFileRequest::Pointer getThumbnailAsync(
IItem::Pointer item, const std::string& filename,
GetThumbnailCallback callback = [](bool) {}) = 0;
GetThumbnailCallback callback = [](EitherError<void>) {}) = 0;
/**
* Simplified version of uploadFileAsync.
......@@ -415,7 +415,7 @@ class ICloudProvider {
virtual UploadFileRequest::Pointer uploadFileAsync(
IItem::Pointer parent, const std::string& path,
const std::string& filename,
UploadFileCallback callback = [](bool) {}) = 0;
UploadFileCallback callback = [](EitherError<void>) {}) = 0;
};
} // namespace cloudstorage
......
......@@ -219,9 +219,9 @@ using MoveItemCallback = std::function<void(EitherError<void>)>;
using RenameItemCallback = std::function<void(EitherError<void>)>;
using ListDirectoryCallback =
std::function<void(EitherError<std::vector<IItem::Pointer>>)>;
using DownloadFileCallback = std::function<void(bool)>;
using UploadFileCallback = std::function<void(bool)>;
using GetThumbnailCallback = std::function<void(bool)>;
using DownloadFileCallback = std::function<void(EitherError<void>)>;
using UploadFileCallback = std::function<void(EitherError<void>)>;
using GetThumbnailCallback = std::function<void(EitherError<void>)>;
} // namespace cloudstorage
......
......@@ -41,27 +41,33 @@ DownloadFileRequest::DownloadFileRequest(std::shared_ptr<CloudProvider> p,
callback_(std::move(callback)),
request_factory_(request_factory),
fallback_thumbnail_(fallback_thumbnail) {
set_resolver([this](Request* r) {
set_resolver([this](Request* r) -> EitherError<void> {
std::ostream response_stream(&stream_wrapper_);
Error error;
int code = sendRequest(
[this](std::ostream& input) { return request_factory_(*file_, input); },
response_stream, nullptr,
response_stream, &error,
std::bind(&DownloadFileRequest::ICallback::progress, callback_.get(),
_1, _2));
if (IHttpRequest::isSuccess(code))
if (IHttpRequest::isSuccess(code)) {
callback_->done();
else if (fallback_thumbnail_)
return nullptr;
} else if (fallback_thumbnail_) {
generateThumbnail(r, file_, callback_);
return nullptr;
} else {
return error;
}
});
}
DownloadFileRequest::~DownloadFileRequest() { cancel(); }
void DownloadFileRequest::generateThumbnail(
Request<void>* r, IItem::Pointer item,
Request<EitherError<void>>* r, IItem::Pointer item,
IDownloadFileCallback::Pointer callback) {
if (!r->provider()->thumbnailer()) return;
Request<void>::Semaphore semaphore(r);
Request<EitherError<void>>::Semaphore semaphore(r);
auto item_data = r->provider()->getItemDataAsync(
item->id(), [&semaphore](EitherError<IItem>) { semaphore.notify(); });
semaphore.wait();
......
......@@ -40,7 +40,7 @@ class DownloadStreamWrapper : public std::streambuf {
std::function<void(const char*, uint32_t)> callback_;
};
class DownloadFileRequest : public Request<void> {
class DownloadFileRequest : public Request<EitherError<void>> {
public:
using RequestFactory =
std::function<IHttpRequest::Pointer(const IItem&, std::ostream&)>;
......@@ -51,7 +51,7 @@ class DownloadFileRequest : public Request<void> {
bool fallback_thumbnail = false);
~DownloadFileRequest();
static void generateThumbnail(Request<void>*, IItem::Pointer,
static void generateThumbnail(Request<EitherError<void>>*, IItem::Pointer,
ICallback::Pointer);
protected:
......
......@@ -38,12 +38,13 @@ UploadFileRequest::UploadFileRequest(
stream_wrapper_(std::bind(&ICallback::putData, callback.get(), _1, _2),
callback->size()),
callback_(callback) {
set_resolver([this](Request*) {
set_resolver([this](Request*) -> EitherError<void> {
if (directory_->type() != IItem::FileType::Directory) {
callback_->error("Can't upload into non-directory.");
return;
return Error{403, "can't upload into non-directory"};
}
std::stringstream response_stream;
Error error;
int code = sendRequest(
[this](std::ostream& input) {
callback_->reset();
......@@ -53,9 +54,14 @@ UploadFileRequest::UploadFileRequest(
stream_wrapper_.prefix_,
stream_wrapper_.suffix_);
},
response_stream, nullptr,
response_stream, &error,
std::bind(&ICallback::progress, callback_.get(), _1, _2));
if (IHttpRequest::isSuccess(code)) callback_->done();
if (IHttpRequest::isSuccess(code)) {
callback_->done();
return nullptr;
} else {
return error;
}
});
}
......
......@@ -50,7 +50,7 @@ class UploadStreamWrapper : public std::streambuf {
pos_type position_;
};
class UploadFileRequest : public Request<void> {
class UploadFileRequest : public Request<EitherError<void>> {
public:
using ICallback = IUploadFileCallback;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment