Commit 811994e5 authored by Paweł Wegner's avatar Paweł Wegner

cloudbrowser: split up CloudContext into multiple files.

parent 40ecfd09
......@@ -11,6 +11,18 @@ cloudbrowser_LDADD = libcloudbrowser.la
noinst_HEADERS = \
src/CloudContext.h \
src/CloudItem.h \
src/HttpServer.h \
src/Request/CloudRequest.h \
src/Request/ListDirectory.h \
src/Request/GetThumbnail.h \
src/Request/GetUrl.h \
src/Request/CreateDirectory.h \
src/Request/DeleteItem.h \
src/Request/RenameItem.h \
src/Request/MoveItem.h \
src/Request/UploadItem.h \
src/Request/DownloadItem.h \
src/GenerateThumbnail.h \
src/AndroidUtility.h \
src/DesktopUtility.h \
......@@ -22,6 +34,18 @@ noinst_HEADERS = \
libcloudbrowser_la_SOURCES = \
src/CloudContext.cpp \
src/CloudItem.cpp \
src/HttpServer.cpp \
src/Request/CloudRequest.cpp \
src/Request/ListDirectory.cpp \
src/Request/GetThumbnail.cpp \
src/Request/GetUrl.cpp \
src/Request/CreateDirectory.cpp \
src/Request/DeleteItem.cpp \
src/Request/RenameItem.cpp \
src/Request/MoveItem.cpp \
src/Request/UploadItem.cpp \
src/Request/DownloadItem.cpp \
src/GenerateThumbnail.cpp \
src/AndroidUtility.cpp \
src/DesktopUtility.cpp \
......@@ -31,8 +55,8 @@ libcloudbrowser_la_SOURCES = \
src/File.cpp
libcloudbrowser_la_CXXFLAGS = \
-I$(top_srcdir)/bin/cloudbrowser/src \
-I$(top_srcdir)/src \
-Isrc \
$(qt_CFLAGS)
libcloudbrowser_la_LIBADD = \
......@@ -54,6 +78,17 @@ endif
nodist_libcloudbrowser_la_SOURCES = \
src/CloudContext.moc.cpp \
src/CloudItem.moc.cpp \
src/Request/CloudRequest.moc.cpp \
src/Request/ListDirectory.moc.cpp \
src/Request/GetThumbnail.moc.cpp \
src/Request/GetUrl.moc.cpp \
src/Request/CreateDirectory.moc.cpp \
src/Request/DeleteItem.moc.cpp \
src/Request/RenameItem.moc.cpp \
src/Request/MoveItem.moc.cpp \
src/Request/UploadItem.moc.cpp \
src/Request/DownloadItem.moc.cpp \
src/FileDialog.moc.cpp \
src/IPlatformUtility.moc.cpp \
resources.cpp
......
......@@ -24,6 +24,7 @@ QMAKE_INCDIR_POST =
QMAKE_LIBS_PRIVATE =
INCLUDEPATH = \
../src \
../../../src/ \
$$ANDROID_TOOLCHAIN_PATH/include \
$$ANDROID_TOOLCHAIN_PATH/include/c++/4.9.x \
......@@ -36,16 +37,53 @@ LIBS += \
-lboost_filesystem -lboost_system \
-lVLCQtQml -lVLCQtCore -lvlcjni
HEADERS += \
../src/CloudContext.h \
../src/CloudItem.h \
../src/HttpServer.h \
../src/Request/CloudRequest.h \
../src/Request/ListDirectory.h \
../src/Request/GetThumbnail.h \
../src/Request/GetUrl.h \
../src/Request/CreateDirectory.h \
../src/Request/DeleteItem.h \
../src/Request/RenameItem.h \
../src/Request/MoveItem.h \
../src/Request/UploadItem.h \
../src/Request/DownloadItem.h \
../src/GenerateThumbnail.h \
../src/AndroidUtility.h \
../src/DesktopUtility.h \
../src/WinRTUtility.h \
../src/FileDialog.h \
../src/Exec.h \
../src/File.h \
../src/IPlatformUtility.h
SOURCES += \
../main.cpp \
../CloudContext.cpp \
../GenerateThumbnail.cpp \
../Exec.cpp \
../FileDialog.cpp \
../File.cpp \
../AndroidUtility.cpp
../src/CloudContext.cpp \
../src/CloudItem.cpp \
../src/HttpServer.cpp \
../src/Request/CloudRequest.cpp \
../src/Request/ListDirectory.cpp \
../src/Request/GetThumbnail.cpp \
../src/Request/GetUrl.cpp \
../src/Request/CreateDirectory.cpp \
../src/Request/DeleteItem.cpp \
../src/Request/RenameItem.cpp \
../src/Request/MoveItem.cpp \
../src/Request/UploadItem.cpp \
../src/Request/DownloadItem.cpp \
../src/GenerateThumbnail.cpp \
../src/AndroidUtility.cpp \
../src/DesktopUtility.cpp \
../src/WinRTUtility.cpp \
../src/FileDialog.cpp \
../src/Exec.cpp \
../src/File.cpp
SOURCES += \
../src/main.cpp \
../../../src/Utility/CloudStorage.cpp \
../../../src/Utility/Auth.cpp \
../../../src/Utility/Item.cpp \
......@@ -99,13 +137,6 @@ DISTFILES += \
build.gradle \
project.properties
HEADERS += \
../CloudContext.h \
../FileDialog.h \
../File.h \
../AndroidUtility.h \
../IPlatformUtility.h
ANDROID_PACKAGE_SOURCE_DIR = $$PWD
ANDROID_EXTRA_LIBS = \
......
......@@ -19,8 +19,6 @@
#include "ICloudStorage.h"
#include "Utility/Utility.h"
#undef CreateDirectory
using namespace cloudstorage;
namespace {
......@@ -36,59 +34,6 @@ QString sanitize(const QString& name) {
return result;
}
std::string first_url_part(const std::string& url) {
auto idx = url.find_first_of('/', 1);
if (idx == std::string::npos)
return url.substr(1);
else
return std::string(url.begin() + 1, url.begin() + idx);
}
class DownloadToString : public IDownloadFileCallback {
public:
void receivedData(const char* data, uint32_t length) override {
data_ += std::string(data, length);
}
void progress(uint64_t, uint64_t) override {}
void done(EitherError<void>) override {}
const std::string& data() const { return data_; }
private:
std::string data_;
};
class DownloadCallback : public IDownloadFileCallback {
public:
DownloadCallback(RequestNotifier* notifier, QUrl path)
: notifier_(notifier), file_(path.toString()) {
file_.open(QFile::WriteOnly);
}
void receivedData(const char* data, uint32_t length) override {
file_.write(data, static_cast<qint64>(length));
}
void progress(uint64_t total, uint64_t now) override {
emit notifier_->progressChanged(static_cast<qint64>(total),
static_cast<qint64>(now));
}
void done(EitherError<void> e) override {
file_.close();
emit notifier_->finishedVoid(e);
emit notifier_->progressChanged(0, 0);
notifier_->deleteLater();
}
protected:
RequestNotifier* notifier_;
QString name_;
File file_;
};
} // namespace
CloudContext::CloudContext(QObject* parent)
......@@ -571,616 +516,6 @@ void CloudContext::RequestPool::add(std::shared_ptr<ICloudProvider> p,
condition_.notify_one();
}
CloudItem::CloudItem(const Provider& p, IItem::Pointer item, QObject* parent)
: QObject(parent), provider_(p), item_(item) {}
QString CloudItem::filename() const { return item_->filename().c_str(); }
QString CloudItem::type() const {
switch (item_->type()) {
case IItem::FileType::Unknown:
return "file";
case IItem::FileType::Audio:
return "audio";
case IItem::FileType::Image:
return "image";
case IItem::FileType::Video:
return "video";
case IItem::FileType::Directory:
return "directory";
default:
return "";
}
}
bool CloudItem::supports(QString operation) const {
auto provider = this->provider().provider_;
if (operation == "delete")
return provider->supportedOperations() & ICloudProvider::DeleteItem;
else if (operation == "upload")
return provider->supportedOperations() & ICloudProvider::UploadFile;
else if (operation == "move")
return provider->supportedOperations() & ICloudProvider::MoveItem;
else if (operation == "rename")
return provider->supportedOperations() & ICloudProvider::RenameItem;
else if (operation == "mkdir")
return provider->supportedOperations() & ICloudProvider::CreateDirectory;
else if (operation == "download")
return provider->supportedOperations() & ICloudProvider::DownloadFile;
else
return true;
}
ListDirectoryCacheKey CloudItem::key() const {
return {provider().provider_->name(), provider().label_, item()->id()};
}
void ListDirectoryModel::set_provider(const Provider& p) { provider_ = p; }
void ListDirectoryModel::add(IItem::Pointer t) {
beginInsertRows(QModelIndex(), rowCount(), rowCount());
list_.push_back(t);
id_.insert(t->id());
endInsertRows();
}
void ListDirectoryModel::clear() {
beginRemoveRows(QModelIndex(), 0, std::max<int>(rowCount() - 1, 0));
list_.clear();
id_.clear();
endRemoveRows();
}
int ListDirectoryModel::find(IItem::Pointer item) const {
if (id_.find(item->id()) == std::end(id_)) return -1;
for (size_t i = 0; i < list_.size(); i++)
if (list_[i]->id() == item->id()) return i;
return -1;
}
void ListDirectoryModel::insert(int idx, IItem::Pointer item) {
beginInsertRows(QModelIndex(), idx, idx);
list_.insert(list_.begin() + idx, item);
id_.insert(item->id());
endInsertRows();
}
void ListDirectoryModel::remove(int idx) {
beginRemoveRows(QModelIndex(), idx, idx);
id_.erase(id_.find(list_[idx]->id()));
list_.erase(list_.begin() + idx);
endRemoveRows();
}
void ListDirectoryModel::match(const std::vector<IItem::Pointer>& lst) {
std::unordered_set<std::string> id;
for (size_t i = lst.size(); i-- > 0;) {
auto idx = find(lst[i]);
if (idx == -1) {
beginInsertRows(QModelIndex(), 0, 0);
list_.insert(list_.begin(), lst[i]);
id_.insert(lst[i]->id());
endInsertRows();
} else {
list_[idx] = lst[i];
emit dataChanged(createIndex(idx, 0), createIndex(idx, 0));
}
id.insert(lst[i]->id());
}
for (size_t i = 0; i < list().size();) {
if (id.find(list()[i]->id()) == std::end(id)) {
remove(i);
} else {
i++;
}
}
}
int ListDirectoryModel::rowCount(const QModelIndex&) const {
return static_cast<int>(list_.size());
}
QVariant ListDirectoryModel::data(const QModelIndex& id, int) const {
if (static_cast<uint32_t>(id.row()) >= list_.size()) return QVariant();
auto item = new CloudItem(provider_, list_[static_cast<size_t>(id.row())]);
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
return QVariant::fromValue(item);
}
QHash<int, QByteArray> ListDirectoryModel::roleNames() const {
return {{Qt::DisplayRole, "modelData"}};
}
ListDirectoryModel* ListDirectoryRequest::list() { return &list_; }
void ListDirectoryRequest::update(CloudContext* context, CloudItem* item) {
list_.set_provider(item->provider());
auto cache_key = item->key();
auto cached = context->cachedDirectory(cache_key);
bool cache_found = !cached.empty();
if (!cached.empty()) {
list_.match(cached);
}
set_done(false);
connect(this, &Request::errorOccurred, context,
[=](QVariantMap provider, int code, QString description) {
emit context->errorOccurred("ListDirectory", provider, code,
description);
});
connect(this, &ListDirectoryRequest::finished, context,
[=](ListDirectoryCacheKey key, const std::vector<IItem::Pointer>& r) {
context->cacheDirectory(key, r);
});
auto object = new RequestNotifier;
auto provider = item->provider().variant();
connect(object, &RequestNotifier::finishedList, this,
[=](EitherError<std::vector<IItem::Pointer>> r) {
set_done(true);
if (r.left())
return errorOccurred(provider, r.left()->code_,
r.left()->description_.c_str());
if (cache_found) list_.match(*r.right());
emit finished(cache_key, *r.right());
});
connect(object, &RequestNotifier::addedItem, this, [=](IItem::Pointer item) {
if (!cache_found) list_.add(item);
});
class ListDirectoryCallback : public IListDirectoryCallback {
public:
ListDirectoryCallback(RequestNotifier* r) : notifier_(r) {}
void receivedItem(IItem::Pointer item) override {
notifier_->addedItem(item);
}
void done(EitherError<std::vector<IItem::Pointer>> r) override {
emit notifier_->finishedList(r);
notifier_->deleteLater();
}
private:
RequestNotifier* notifier_;
};
auto r = item->provider().provider_->listDirectoryAsync(
item->item(), util::make_unique<ListDirectoryCallback>(object));
context->add(item->provider().provider_, std::move(r));
}
void Request::set_done(bool done) {
if (done_ == done) return;
done_ = done;
emit doneChanged();
}
void GetThumbnailRequest::update(CloudContext* context, CloudItem* item) {
if (item->type() == "directory") return set_done(true);
set_done(false);
auto path = CloudContext::thumbnail_path(item->filename());
QFile file(path);
if (file.exists() && file.size() > 0) {
source_ = QUrl::fromLocalFile(path).toString();
set_done(true);
emit sourceChanged();
} else {
auto object = new RequestNotifier;
auto provider = item->provider().variant();
connect(this, &Request::errorOccurred, context,
[=](QVariantMap provider, int code, QString description) {
emit context->errorOccurred("GetThumbnail", provider, code,
description);
});
connect(this, &GetThumbnailRequest::cacheFileAdded, context,
[=](quint64 size) { context->addCacheSize(size); });
connect(object, &RequestNotifier::finishedVariant, this,
[=](EitherError<QVariant> e) {
set_done(true);
if (e.left())
return errorOccurred(provider, e.left()->code_,
e.left()->description_.c_str());
auto map = e.right()->toMap();
source_ = QUrl::fromLocalFile(map["path"].toString()).toString();
emit sourceChanged();
emit cacheFileAdded(map["length"].toULongLong());
});
class DownloadThumbnailCallback : public IDownloadFileCallback {
public:
DownloadThumbnailCallback(CloudContext* context,
RequestNotifier* notifier,
std::shared_ptr<ICloudProvider> p,
IItem::Pointer item)
: context_(context), notifier_(notifier), provider_(p), item_(item) {}
void receivedData(const char* data, uint32_t length) override {
data_ += std::string(data, length);
}
void progress(uint64_t total, uint64_t now) override {
emit notifier_->progressChanged(static_cast<qint64>(total),
static_cast<qint64>(now));
}
static void submit(RequestNotifier* notifier, QString path,
const std::string& data) {
auto e = save(path, data);
if (e.left()) {
emit notifier->finishedVariant(e.left());
} else {
QVariantMap result;
result["length"] = QVariant::fromValue(data.size());
result["path"] = e.right()->c_str();
emit notifier->finishedVariant(QVariant::fromValue(result));
}
notifier->deleteLater();
}
static EitherError<std::string> save(QString path,
const std::string& data) {
QSaveFile file(path);
if (!file.open(QFile::WriteOnly))
return Error{IHttpRequest::Bad, "couldn't open file"};
file.write(data.c_str(), static_cast<qint64>(data.size()));
if (file.commit()) {
return path.toStdString();
} else {
return Error{IHttpRequest::Bad, "couldn't commit file"};
}
}
void done(EitherError<void> e) override {
#ifdef WITH_THUMBNAILER
if (e.left() && (item_->type() == IItem::FileType::Image ||
item_->type() == IItem::FileType::Video)) {
auto path = CloudContext::thumbnail_path(item_->filename().c_str());
auto provider = provider_;
auto item = item_;
auto notifier = notifier_;
std::thread([path, provider, item, notifier] {
auto r = provider->getItemUrlAsync(item)->result();
if (r.left()) {
emit notifier->finishedVariant(r.left());
return notifier->deleteLater();
}
if (item->type() == IItem::FileType::Image) {
if (item->size() < 2 * 1024 * 1024) {
auto downloader = std::make_shared<DownloadToString>();
auto e =
provider->downloadFileAsync(item, downloader)->result();
if (e.left())
emit notifier->finishedVariant(e.left());
else
return submit(notifier, path, downloader->data());
} else {
emit notifier->finishedVariant(
Error{IHttpRequest::ServiceUnavailable, "image too big"});
}
return notifier->deleteLater();
}
auto e = generate_thumbnail(*r.right());
if (e.left()) {
emit notifier->finishedVariant(e.left());
return notifier->deleteLater();
}
submit(notifier, path, *e.right());
}).detach();
return;
}
#endif
if (e.left())
emit notifier_->finishedVariant(e.left());
else {
auto notifier = notifier_;
auto path = CloudContext::thumbnail_path(item_->filename().c_str());
auto data = std::move(data_);
context_->schedule([notifier, path, data] {
submit(notifier, path, std::move(data));
});
}
}
private:
CloudContext* context_;
RequestNotifier* notifier_;
std::string data_;
std::shared_ptr<ICloudProvider> provider_;
IItem::Pointer item_;
};
auto p = item->provider().provider_;
auto r = p->getThumbnailAsync(item->item(),
util::make_unique<DownloadThumbnailCallback>(
context, object, p, item->item()));
context->add(p, std::move(r));
}
}
void GetUrlRequest::update(CloudContext* context, CloudItem* item) {
set_done(false);
auto object = new RequestNotifier;
auto provider = item->provider().variant();
connect(this, &Request::errorOccurred, context,
[=](QVariantMap provider, int code, QString description) {
emit context->errorOccurred("GetItemUrl", provider, code,
description);
});
connect(object, &RequestNotifier::finishedString, this,
[=](EitherError<std::string> e) {
if (e.left()) {
source_ = "";
emit errorOccurred(provider, e.left()->code_,
e.left()->description_.c_str());
} else
source_ = e.right()->c_str();
emit sourceChanged();
set_done(true);
});
auto p = item->provider().provider_;
auto r =
p->getItemUrlAsync(item->item(), [object](EitherError<std::string> e) {
emit object->finishedString(e);
object->deleteLater();
});
context->add(p, std::move(r));
}
void CreateDirectoryRequest::update(CloudContext* context, CloudItem* parent,
QString name) {
set_done(false);
auto object = new RequestNotifier;
auto provider = parent->provider().variant();
connect(this, &Request::errorOccurred, context,
[=](QVariantMap provider, int code, QString description) {
emit context->errorOccurred("CreateDirectory", provider, code,
description);
});
connect(object, &RequestNotifier::finishedItem, this,
[=](EitherError<IItem> e) {
set_done(true);
emit createdDirectory();