diff options
Diffstat (limited to 'backends/cloud')
-rw-r--r-- | backends/cloud/box/boxlistdirectorybyidrequest.cpp | 169 | ||||
-rw-r--r-- | backends/cloud/box/boxlistdirectorybyidrequest.h | 63 | ||||
-rw-r--r-- | backends/cloud/box/boxstorage.cpp | 9 | ||||
-rw-r--r-- | backends/cloud/box/boxstorage.h | 1 | ||||
-rw-r--r-- | backends/cloud/iso8601.cpp | 19 |
5 files changed, 255 insertions, 6 deletions
diff --git a/backends/cloud/box/boxlistdirectorybyidrequest.cpp b/backends/cloud/box/boxlistdirectorybyidrequest.cpp new file mode 100644 index 0000000000..d4606b1851 --- /dev/null +++ b/backends/cloud/box/boxlistdirectorybyidrequest.cpp @@ -0,0 +1,169 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "backends/cloud/box/boxlistdirectorybyidrequest.h" +#include "backends/cloud/box/boxstorage.h" +#include "backends/cloud/box/boxtokenrefresher.h" +#include "backends/cloud/iso8601.h" +#include "backends/cloud/storage.h" +#include "backends/networking/curl/connectionmanager.h" +#include "backends/networking/curl/curljsonrequest.h" +#include "backends/networking/curl/networkreadstream.h" +#include "common/json.h" + +namespace Cloud { +namespace Box { + +#define BOX_LIST_DIRECTORY_LIMIT 1000 + +BoxListDirectoryByIdRequest::BoxListDirectoryByIdRequest(BoxStorage *storage, Common::String id, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb): + Networking::Request(nullptr, ecb), _requestedId(id), _storage(storage), _listDirectoryCallback(cb), + _workingRequest(nullptr), _ignoreCallback(false) { + start(); +} + +BoxListDirectoryByIdRequest::~BoxListDirectoryByIdRequest() { + _ignoreCallback = true; + if (_workingRequest) _workingRequest->finish(); + delete _listDirectoryCallback; +} + +void BoxListDirectoryByIdRequest::start() { + _ignoreCallback = true; + if (_workingRequest) _workingRequest->finish(); + _files.clear(); + _ignoreCallback = false; + + makeRequest(0); +} + +void BoxListDirectoryByIdRequest::makeRequest(uint32 offset) { + Common::String url = Common::String::format( + "https://api.box.com/2.0/folders/%s/items?offset=%u&limit=%u&fields=%s", + _requestedId.c_str(), + offset, + BOX_LIST_DIRECTORY_LIMIT, + "id,type,name,size,modified_at" + ); + + Networking::JsonCallback callback = new Common::Callback<BoxListDirectoryByIdRequest, Networking::JsonResponse>(this, &BoxListDirectoryByIdRequest::responseCallback); + Networking::ErrorCallback failureCallback = new Common::Callback<BoxListDirectoryByIdRequest, Networking::ErrorResponse>(this, &BoxListDirectoryByIdRequest::errorCallback); + Networking::CurlJsonRequest *request = new BoxTokenRefresher(_storage, callback, failureCallback, url.c_str()); + request->addHeader("Authorization: Bearer " + _storage->accessToken()); + _workingRequest = ConnMan.addRequest(request); +} + +void BoxListDirectoryByIdRequest::responseCallback(Networking::JsonResponse response) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + if (response.request) _date = response.request->date(); + + Networking::ErrorResponse error(this); + Networking::CurlJsonRequest *rq = (Networking::CurlJsonRequest *)response.request; + if (rq && rq->getNetworkReadStream()) + error.httpResponseCode = rq->getNetworkReadStream()->httpResponseCode(); + + Common::JSONValue *json = response.value; + if (json) { + Common::JSONObject responseObject = json->asObject(); + + //debug("%s", json->stringify(true).c_str()); + + //TODO: check that error is returned the right way + /* + if (responseObject.contains("error") || responseObject.contains("error_summary")) { + warning("Box returned error: %s", responseObject.getVal("error_summary")->asString().c_str()); + error.failed = true; + error.response = json->stringify(); + finishError(error); + delete json; + return; + } + */ + + //TODO: check that ALL keys exist AND HAVE RIGHT TYPE to avoid segfaults + + if (responseObject.contains("entries") && responseObject.getVal("entries")->isArray()) { + Common::JSONArray items = responseObject.getVal("entries")->asArray(); + for (uint32 i = 0; i < items.size(); ++i) { + Common::JSONObject item = items[i]->asObject(); + Common::String id = item.getVal("id")->asString(); + Common::String name = item.getVal("name")->asString(); + bool isDirectory = (item.getVal("type")->asString() == "folder"); + uint32 size = 0, timestamp = 0; + if (item.contains("size")) { + if (item.getVal("size")->isString()) + size = item.getVal("size")->asString().asUint64(); + else if (item.getVal("size")->isIntegerNumber()) + size = item.getVal("size")->asIntegerNumber(); + else + warning("strange type for field 'size'"); + } + if (item.contains("modified_at") && item.getVal("modified_at")->isString()) + timestamp = ISO8601::convertToTimestamp(item.getVal("modified_at")->asString()); + + //as we list directory by id, we can't determine full path for the file, so we leave it empty + _files.push_back(StorageFile(id, "", name, size, timestamp, isDirectory)); + } + } + + uint32 received = 0; + uint32 totalCount = 0; + if (responseObject.contains("total_count") && responseObject.getVal("total_count")->isIntegerNumber()) + totalCount = responseObject.getVal("total_count")->asIntegerNumber(); + if (responseObject.contains("offset") && responseObject.getVal("offset")->isIntegerNumber()) + received = responseObject.getVal("offset")->asIntegerNumber(); + if (responseObject.contains("limit") && responseObject.getVal("limit")->isIntegerNumber()) + received += responseObject.getVal("limit")->asIntegerNumber(); + bool hasMore = (received < totalCount); + + if (hasMore) makeRequest(received); + else finishListing(_files); + } else { + warning("null, not json"); + error.failed = true; + finishError(error); + } + + delete json; +} + +void BoxListDirectoryByIdRequest::errorCallback(Networking::ErrorResponse error) { + _workingRequest = nullptr; + if (_ignoreCallback) return; + if (error.request) _date = error.request->date(); + finishError(error); +} + +void BoxListDirectoryByIdRequest::handle() {} + +void BoxListDirectoryByIdRequest::restart() { start(); } + +Common::String BoxListDirectoryByIdRequest::date() const { return _date; } + +void BoxListDirectoryByIdRequest::finishListing(Common::Array<StorageFile> &files) { + Request::finishSuccess(); + if (_listDirectoryCallback) (*_listDirectoryCallback)(Storage::ListDirectoryResponse(this, files)); +} + +} // End of namespace Box +} // End of namespace Cloud diff --git a/backends/cloud/box/boxlistdirectorybyidrequest.h b/backends/cloud/box/boxlistdirectorybyidrequest.h new file mode 100644 index 0000000000..ccf8d2e342 --- /dev/null +++ b/backends/cloud/box/boxlistdirectorybyidrequest.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef BACKENDS_CLOUD_BOX_BOXLISTDIRECTORYBYIDREQUEST_H +#define BACKENDS_CLOUD_BOX_BOXLISTDIRECTORYBYIDREQUEST_H + +#include "backends/cloud/storage.h" +#include "backends/networking/curl/curljsonrequest.h" +#include "backends/networking/curl/request.h" +#include "common/callback.h" + +namespace Cloud { +namespace Box { + +class BoxStorage; + +class BoxListDirectoryByIdRequest: public Networking::Request { + Common::String _requestedId; + BoxStorage *_storage; + + Storage::ListDirectoryCallback _listDirectoryCallback; + Common::Array<StorageFile> _files; + Request *_workingRequest; + bool _ignoreCallback; + Common::String _date; + + void start(); + void makeRequest(uint32 offset); + void responseCallback(Networking::JsonResponse response); + void errorCallback(Networking::ErrorResponse error); + void finishListing(Common::Array<StorageFile> &files); +public: + BoxListDirectoryByIdRequest(BoxStorage *storage, Common::String id, Storage::ListDirectoryCallback cb, Networking::ErrorCallback ecb); + virtual ~BoxListDirectoryByIdRequest(); + + virtual void handle(); + virtual void restart(); + virtual Common::String date() const; +}; + +} // End of namespace Box +} // End of namespace Cloud + +#endif diff --git a/backends/cloud/box/boxstorage.cpp b/backends/cloud/box/boxstorage.cpp index 85bbf34221..9842ed2796 100644 --- a/backends/cloud/box/boxstorage.cpp +++ b/backends/cloud/box/boxstorage.cpp @@ -22,6 +22,7 @@ #define FORBIDDEN_SYMBOL_ALLOW_ALL #include "backends/cloud/box/boxstorage.h" +#include "backends/cloud/box/boxlistdirectorybyidrequest.h" #include "backends/cloud/box/boxtokenrefresher.h" #include "backends/cloud/cloudmanager.h" #include "backends/networking/curl/connectionmanager.h" @@ -210,10 +211,18 @@ void BoxStorage::fileInfoCallback(Networking::NetworkReadStreamCallback outerCal } Networking::Request *BoxStorage::listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive) { + if (!errorCallback) errorCallback = getErrorPrintingCallback(); + if (!callback) callback = new Common::Callback<BoxStorage, FileArrayResponse>(this, &BoxStorage::printFiles); //return addRequest(new BoxListDirectoryRequest(this, path, callback, errorCallback, recursive)); return nullptr; //TODO } +Networking::Request *BoxStorage::listDirectoryById(Common::String id, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback) { + if (!errorCallback) errorCallback = getErrorPrintingCallback(); + if (!callback) callback = new Common::Callback<BoxStorage, FileArrayResponse>(this, &BoxStorage::printFiles); + return addRequest(new BoxListDirectoryByIdRequest(this, id, callback, errorCallback)); +} + Networking::Request *BoxStorage::upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) { //return addRequest(new BoxUploadRequest(this, path, contents, callback, errorCallback)); return nullptr; //TODO diff --git a/backends/cloud/box/boxstorage.h b/backends/cloud/box/boxstorage.h index b58608c7f0..3ce7a37f10 100644 --- a/backends/cloud/box/boxstorage.h +++ b/backends/cloud/box/boxstorage.h @@ -81,6 +81,7 @@ public: /** Returns ListDirectoryStatus struct with list of files. */ virtual Networking::Request *listDirectory(Common::String path, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback, bool recursive = false); + virtual Networking::Request *listDirectoryById(Common::String id, ListDirectoryCallback callback, Networking::ErrorCallback errorCallback); /** Returns UploadStatus struct with info about uploaded file. */ virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback); diff --git a/backends/cloud/iso8601.cpp b/backends/cloud/iso8601.cpp index 3bc169ae85..1675c7ce54 100644 --- a/backends/cloud/iso8601.cpp +++ b/backends/cloud/iso8601.cpp @@ -33,6 +33,12 @@ Common::String getSubstring(const Common::String &s, uint32 beginning, uint32 en return result; } +int find(const char *cstr, uint32 startPosition, char needle) { + const char *res = strchr(cstr + startPosition, needle); + if (res == nullptr) return -1; + return res - cstr; +} + } namespace Cloud { @@ -41,12 +47,13 @@ namespace ISO8601 { uint32 convertToTimestamp(const Common::String &iso8601Date) { //2015-05-12T15:50:38Z const char *cstr = iso8601Date.c_str(); - uint32 firstHyphen = strchr(cstr, '-') - cstr; - uint32 secondHyphen = strchr(cstr + firstHyphen + 1, '-') - cstr; - uint32 tSeparator = strchr(cstr + secondHyphen + 1, 'T') - cstr; - uint32 firstColon = strchr(cstr + tSeparator + 1, ':') - cstr; - uint32 secondColon = strchr(cstr + firstColon + 1, ':') - cstr; - uint32 zSeparator = strchr(cstr + secondColon + 1, 'Z') - cstr; + int firstHyphen = find(cstr, 0, '-'); + int secondHyphen = find(cstr, firstHyphen + 1, '-'); + int tSeparator = find(cstr, secondHyphen + 1, 'T'); + int firstColon = find(cstr, tSeparator + 1, ':'); + int secondColon = find(cstr, firstColon + 1, ':'); + int zSeparator = find(cstr, secondColon + 1, 'Z'); + if (zSeparator == -1) zSeparator = find(cstr, secondColon + 1, '-'); // Box's RFC 3339 //now note '+1' which means if there ever was '-1' result of find(), we still did a valid find() from 0th char Common::String year = getSubstring(iso8601Date, 0, firstHyphen); |