diff options
Diffstat (limited to 'backends')
| -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 | ||||
| -rw-r--r-- | backends/module.mk | 1 | 
6 files changed, 256 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); diff --git a/backends/module.mk b/backends/module.mk index 2c2a4e2cfc..07ba98348c 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -29,6 +29,7 @@ MODULE_OBJS += \  	cloud/folderdownloadrequest.o \  	cloud/savessyncrequest.o \  	cloud/box/boxstorage.o \ +	cloud/box/boxlistdirectorybyidrequest.o \  	cloud/box/boxtokenrefresher.o \  	cloud/dropbox/dropboxstorage.o \  	cloud/dropbox/dropboxcreatedirectoryrequest.o \  | 
