diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/cloud/dropbox/dropboxstorage.cpp | 20 | ||||
-rw-r--r-- | backends/cloud/dropbox/dropboxstorage.h | 3 | ||||
-rw-r--r-- | backends/cloud/dropbox/dropboxuploadrequest.cpp | 163 | ||||
-rw-r--r-- | backends/cloud/dropbox/dropboxuploadrequest.h | 60 | ||||
-rw-r--r-- | backends/cloud/onedrive/onedrivestorage.h | 2 | ||||
-rw-r--r-- | backends/cloud/savessyncrequest.h | 1 | ||||
-rw-r--r-- | backends/cloud/storage.h | 2 | ||||
-rw-r--r-- | backends/module.mk | 1 | ||||
-rw-r--r-- | backends/networking/curl/curljsonrequest.cpp | 2 | ||||
-rw-r--r-- | backends/networking/curl/curlrequest.cpp | 35 | ||||
-rw-r--r-- | backends/networking/curl/curlrequest.h | 7 | ||||
-rw-r--r-- | backends/networking/curl/networkreadstream.cpp | 14 | ||||
-rw-r--r-- | backends/networking/curl/networkreadstream.h | 1 |
13 files changed, 294 insertions, 17 deletions
diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp index b1dd865ee2..1220a99035 100644 --- a/backends/cloud/dropbox/dropboxstorage.cpp +++ b/backends/cloud/dropbox/dropboxstorage.cpp @@ -23,15 +23,16 @@ #include "backends/cloud/dropbox/dropboxstorage.h" #include "backends/cloud/dropbox/dropboxlistdirectoryrequest.h" +#include "backends/cloud/dropbox/dropboxuploadrequest.h" #include "backends/cloud/downloadrequest.h" #include "backends/cloud/folderdownloadrequest.h" #include "backends/networking/curl/connectionmanager.h" #include "backends/networking/curl/curljsonrequest.h" #include "common/config-manager.h" #include "common/debug.h" +#include "common/file.h" #include "common/json.h" #include <curl/curl.h> -#include <common/file.h> namespace Cloud { namespace Dropbox { @@ -99,10 +100,18 @@ void DropboxStorage::printFiles(FileArrayResponse pair) { debug("\t%s", files[i].name().c_str()); } +void DropboxStorage::printBool(BoolResponse pair) { + debug("bool: %s", (pair.value?"true":"false")); +} + Networking::Request *DropboxStorage::listDirectory(Common::String path, FileArrayCallback outerCallback, bool recursive) { return ConnMan.addRequest(new DropboxListDirectoryRequest(_token, path, outerCallback, recursive)); } +Networking::Request *DropboxStorage::upload(Common::String path, Common::SeekableReadStream *contents, BoolCallback callback) { + return ConnMan.addRequest(new DropboxUploadRequest(_token, path, contents, callback)); +} + Networking::Request *DropboxStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback callback) { Common::JSONObject jsonRequestParameters; jsonRequestParameters.setVal("path", new Common::JSONValue(path)); @@ -139,11 +148,20 @@ Networking::Request *DropboxStorage::syncSaves(BoolCallback callback) { //"" is root in Dropbox, not "/" //this must create all these directories: //return download("/remote/test.jpg", "local/a/b/c/d/test.jpg", 0); + /* return downloadFolder( "/not_flat", "local/not_flat_1_level/", new Common::Callback<DropboxStorage, FileArrayResponse>(this, &DropboxStorage::printFiles), false ); + */ + Common::File *file = new Common::File(); + if (!file->open("final.bmp")) { + warning("no such file"); + delete file; + return nullptr; + } + return upload("/remote/test3.bmp", file, new Common::Callback<DropboxStorage, BoolResponse>(this, &DropboxStorage::printBool)); } Networking::Request *DropboxStorage::info(StorageInfoCallback outerCallback) { diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h index da508d7844..cc515fef41 100644 --- a/backends/cloud/dropbox/dropboxstorage.h +++ b/backends/cloud/dropbox/dropboxstorage.h @@ -46,6 +46,7 @@ class DropboxStorage: public Cloud::Storage { void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json); void printFiles(FileArrayResponse pair); + void printBool(BoolResponse pair); public: virtual ~DropboxStorage(); @@ -69,7 +70,7 @@ public: virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false); /** Calls the callback when finished. */ - virtual Networking::Request *upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, BoolCallback callback); /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback); diff --git a/backends/cloud/dropbox/dropboxuploadrequest.cpp b/backends/cloud/dropbox/dropboxuploadrequest.cpp new file mode 100644 index 0000000000..d068078502 --- /dev/null +++ b/backends/cloud/dropbox/dropboxuploadrequest.cpp @@ -0,0 +1,163 @@ +/* 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/dropbox/dropboxuploadrequest.h" +#include "backends/cloud/storage.h" +#include "backends/networking/curl/connectionmanager.h" +#include "backends/networking/curl/curljsonrequest.h" +#include "common/json.h" +#include "common/debug.h" + +namespace Cloud { +namespace Dropbox { + +DropboxUploadRequest::DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::BoolCallback callback): + Networking::Request(0), _token(token), _savePath(path), _contentsStream(contents), _boolCallback(callback), + _workingRequest(nullptr), _ignoreCallback(false) { + start(); +} + +DropboxUploadRequest::~DropboxUploadRequest() { + _ignoreCallback = true; + if (_workingRequest) _workingRequest->finish(); + delete _contentsStream; + delete _boolCallback; +} + + +void DropboxUploadRequest::start() { + _ignoreCallback = true; + if (_workingRequest) _workingRequest->finish(); + if (!_contentsStream->seek(0)) { + warning("DropboxUploadRequest: cannot restart because stream couldn't seek(0)"); + finish(); + } + _ignoreCallback = false; + + uploadNextPart(); +} + +void DropboxUploadRequest::uploadNextPart() { + const uint32 UPLOAD_PER_ONE_REQUEST = 10 * 1024 * 1024; + + Common::String url = "https://content.dropboxapi.com/2/files/upload_session/"; + Common::JSONObject jsonRequestParameters; + + if (_contentsStream->pos() == 0 || _sessionId == "") { + url += "start"; + jsonRequestParameters.setVal("close", new Common::JSONValue(false)); + } else { + if (_contentsStream->size() - _contentsStream->pos() <= UPLOAD_PER_ONE_REQUEST) { + url += "finish"; + Common::JSONObject jsonCursor, jsonCommit; + jsonCursor.setVal("session_id", new Common::JSONValue(_sessionId)); + jsonCursor.setVal("offset", new Common::JSONValue(_contentsStream->pos())); + jsonCommit.setVal("path", new Common::JSONValue(_savePath)); + jsonCommit.setVal("mode", new Common::JSONValue("overwrite")); + jsonCommit.setVal("autorename", new Common::JSONValue(false)); + jsonCommit.setVal("mute", new Common::JSONValue(false)); + jsonRequestParameters.setVal("cursor", new Common::JSONValue(jsonCursor)); + jsonRequestParameters.setVal("commit", new Common::JSONValue(jsonCommit)); + } else { + url += "append_v2"; + Common::JSONObject jsonCursor; + jsonCursor.setVal("session_id", new Common::JSONValue(_sessionId)); + jsonCursor.setVal("offset", new Common::JSONValue(_contentsStream->pos())); + jsonRequestParameters.setVal("cursor", new Common::JSONValue(jsonCursor)); + jsonRequestParameters.setVal("close", new Common::JSONValue(false)); + } + } + + Common::JSONValue value(jsonRequestParameters); + Networking::JsonCallback innerCallback = new Common::Callback<DropboxUploadRequest, Networking::JsonResponse>(this, &DropboxUploadRequest::partUploadedCallback); + Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, url); + request->addHeader("Authorization: Bearer " + _token); + request->addHeader("Content-Type: application/octet-stream"); + request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value)); + + byte *buffer = new byte[UPLOAD_PER_ONE_REQUEST]; + uint32 size = _contentsStream->read(buffer, UPLOAD_PER_ONE_REQUEST); + request->setBuffer(buffer, size); + + _workingRequest = ConnMan.addRequest(request); +} + +void DropboxUploadRequest::partUploadedCallback(Networking::JsonResponse pair) { + if (_ignoreCallback) return; + _workingRequest = nullptr; + + Common::JSONValue *json = pair.value; + if (json) { + bool needsFinishRequest = false; + + if (json->isObject()) { + Common::JSONObject response = json->asObject(); + + //debug("%s", json->stringify(true).c_str()); + + if (response.contains("error") || response.contains("error_summary")) { + warning("Dropbox returned error: %s", response.getVal("error_summary")->asString().c_str()); + delete json; + finish(); + return; + } + + if (response.contains("server_modified")) { + //finished + finishBool(true); + return; + } + + if (_sessionId == "") { + if (response.contains("session_id")) + _sessionId = response.getVal("session_id")->asString(); + else + warning("no session_id found in Dropbox's response"); + needsFinishRequest = true; + } + } + + if (!needsFinishRequest && (_contentsStream->eos() || _contentsStream->pos() >= _contentsStream->size() - 1)) + finishBool(true); + else + uploadNextPart(); + } else { + warning("null, not json"); + finish(); + } + + delete json; +} + +void DropboxUploadRequest::handle() {} + +void DropboxUploadRequest::restart() { start(); } + +void DropboxUploadRequest::finish() { finishBool(false); } + +void DropboxUploadRequest::finishBool(bool success) { + Request::finish(); + if (_boolCallback) (*_boolCallback)(Storage::BoolResponse(this, success)); +} + +} // End of namespace Dropbox +} // End of namespace Cloud diff --git a/backends/cloud/dropbox/dropboxuploadrequest.h b/backends/cloud/dropbox/dropboxuploadrequest.h new file mode 100644 index 0000000000..a7d7a6c581 --- /dev/null +++ b/backends/cloud/dropbox/dropboxuploadrequest.h @@ -0,0 +1,60 @@ +/* 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_DROPBOX_DROPBOXUPLOADREQUEST_H +#define BACKENDS_CLOUD_DROPBOX_DROPBOXUPLOADREQUEST_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 Dropbox { + +class DropboxUploadRequest: public Networking::Request { + Common::String _token; + Common::String _savePath; + Common::SeekableReadStream *_contentsStream; + Storage::BoolCallback _boolCallback; + Request *_workingRequest; + bool _ignoreCallback; + Common::String _sessionId; + + void start(); + void uploadNextPart(); + void partUploadedCallback(Networking::JsonResponse pair); + void finishBool(bool success); + +public: + DropboxUploadRequest(Common::String token, Common::String path, Common::SeekableReadStream *contents, Storage::BoolCallback callback); + virtual ~DropboxUploadRequest(); + + virtual void handle(); + virtual void restart(); + virtual void finish(); +}; + +} // End of namespace Dropbox +} // End of namespace Cloud + +#endif diff --git a/backends/cloud/onedrive/onedrivestorage.h b/backends/cloud/onedrive/onedrivestorage.h index 3dc5b7a7ad..41d84f9770 100644 --- a/backends/cloud/onedrive/onedrivestorage.h +++ b/backends/cloud/onedrive/onedrivestorage.h @@ -76,7 +76,7 @@ public: virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false); /** Calls the callback when finished. */ - virtual Networking::Request *upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) { return nullptr; } //TODO + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, BoolCallback callback) { return nullptr; } //TODO /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback); diff --git a/backends/cloud/savessyncrequest.h b/backends/cloud/savessyncrequest.h index a8c54d44ad..dd43cab2a0 100644 --- a/backends/cloud/savessyncrequest.h +++ b/backends/cloud/savessyncrequest.h @@ -26,6 +26,7 @@ #include "backends/networking/curl/request.h" #include "backends/cloud/storage.h" #include "common/hashmap.h" +#include "common/hash-str.h" namespace Cloud { diff --git a/backends/cloud/storage.h b/backends/cloud/storage.h index ac74f90b57..dbd862822b 100644 --- a/backends/cloud/storage.h +++ b/backends/cloud/storage.h @@ -72,7 +72,7 @@ public: virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false) = 0; /** Calls the callback when finished. */ - virtual Networking::Request *upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) = 0; + virtual Networking::Request *upload(Common::String path, Common::SeekableReadStream *contents, BoolCallback callback) = 0; /** Returns pointer to Networking::NetworkReadStream. */ virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback) = 0; diff --git a/backends/module.mk b/backends/module.mk index a31704a655..281c6a9060 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -29,6 +29,7 @@ MODULE_OBJS += \ cloud/savessyncrequest.o \ cloud/dropbox/dropboxstorage.o \ cloud/dropbox/dropboxlistdirectoryrequest.o \ + cloud/dropbox/dropboxuploadrequest.o \ cloud/onedrive/onedrivestorage.o \ cloud/onedrive/onedrivetokenrefresher.o \ cloud/onedrive/onedrivelistdirectoryrequest.o diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp index d114d69098..fee0932129 100644 --- a/backends/networking/curl/curljsonrequest.cpp +++ b/backends/networking/curl/curljsonrequest.cpp @@ -55,7 +55,7 @@ char *CurlJsonRequest::getPreparedContents() { } void CurlJsonRequest::handle() { - if (!_stream) _stream = new NetworkReadStream(_url.c_str(), _headersList, _postFields); + if (!_stream) _stream = makeStream(); if (_stream) { const int kBufSize = 16*1024; diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp index a745741bc8..64f6c26fb9 100644 --- a/backends/networking/curl/curlrequest.cpp +++ b/backends/networking/curl/curlrequest.cpp @@ -31,12 +31,22 @@ namespace Networking { CurlRequest::CurlRequest(DataCallback cb, Common::String url): - Request(cb), _url(url), _stream(0), _headersList(0) {} + Request(cb), _url(url), _stream(nullptr), _headersList(nullptr), _bytesBuffer(nullptr), _bytesBufferSize(0) {} + +CurlRequest::~CurlRequest() { + delete _stream; + delete _bytesBuffer; +} + +NetworkReadStream *CurlRequest::makeStream() { + if (_bytesBuffer) + return new NetworkReadStream(_url.c_str(), _headersList, _bytesBuffer, _bytesBufferSize, true); + return new NetworkReadStream(_url.c_str(), _headersList, _postFields); +} -CurlRequest::~CurlRequest() { delete _stream; } void CurlRequest::handle() { - if (!_stream) _stream = new NetworkReadStream(_url.c_str(), _headersList, _postFields); + if (!_stream) _stream = makeStream(); if (_stream && _stream->eos()) { if (_stream->httpResponseCode() != 200) @@ -47,13 +57,13 @@ void CurlRequest::handle() { void CurlRequest::restart() { if (_stream) delete _stream; - _stream = 0; + _stream = nullptr; //with no stream available next handle() will create another one } void CurlRequest::setHeaders(Common::Array<Common::String> &headers) { curl_slist_free_all(_headersList); - _headersList = 0; + _headersList = nullptr; for (uint32 i = 0; i < headers.size(); ++i) addHeader(headers[i]); } @@ -63,15 +73,28 @@ void CurlRequest::addHeader(Common::String header) { } void CurlRequest::addPostField(Common::String keyValuePair) { + if (_bytesBuffer) + warning("CurlRequest: added POST fields would be ignored, because there is buffer present"); + if (_postFields == "") _postFields = keyValuePair; else _postFields += "&" + keyValuePair; } +void CurlRequest::setBuffer(byte *buffer, uint32 size) { + if (_postFields != "") + warning("CurlRequest: added POST fields would be ignored, because buffer added"); + + if (_bytesBuffer) delete _bytesBuffer; + + _bytesBuffer = buffer; + _bytesBufferSize = size; +} + NetworkReadStreamResponse CurlRequest::execute() { if (!_stream) { - _stream = new NetworkReadStream(_url.c_str(), _headersList, _postFields); + _stream = makeStream(); ConnMan.addRequest(this); } diff --git a/backends/networking/curl/curlrequest.h b/backends/networking/curl/curlrequest.h index 8623a487d3..461f153b9d 100644 --- a/backends/networking/curl/curlrequest.h +++ b/backends/networking/curl/curlrequest.h @@ -42,6 +42,10 @@ protected: NetworkReadStream *_stream; curl_slist *_headersList; Common::String _postFields; + byte *_bytesBuffer; + uint32 _bytesBufferSize; + + virtual NetworkReadStream *makeStream(); public: CurlRequest(DataCallback cb, Common::String url); @@ -59,6 +63,9 @@ public: /** Adds a post field (key=value pair). */ virtual void addPostField(Common::String field); + /** Sets bytes buffer. */ + virtual void setBuffer(byte *buffer, uint32 size); + /** * Starts this Request with ConnMan. * @return its NetworkReadStream in NetworkReadStreamResponse. diff --git a/backends/networking/curl/networkreadstream.cpp b/backends/networking/curl/networkreadstream.cpp index 997f0b2fc3..f96a069e16 100644 --- a/backends/networking/curl/networkreadstream.cpp +++ b/backends/networking/curl/networkreadstream.cpp @@ -36,8 +36,10 @@ static size_t curlDataCallback(char *d, size_t n, size_t l, void *p) { } NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields): - _easy(0), _eos(false), _requestComplete(false) -{ + NetworkReadStream(url, headersList, (byte *)postFields.c_str(), postFields.size(), false) {} + +NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, byte *buffer, uint32 bufferSize, bool post) : + _easy(0), _eos(false), _requestComplete(false) { _easy = curl_easy_init(); curl_easy_setopt(_easy, CURLOPT_WRITEFUNCTION, curlDataCallback); curl_easy_setopt(_easy, CURLOPT_WRITEDATA, this); //so callback can call us @@ -46,10 +48,10 @@ NetworkReadStream::NetworkReadStream(const char *url, curl_slist *headersList, C curl_easy_setopt(_easy, CURLOPT_URL, url); curl_easy_setopt(_easy, CURLOPT_VERBOSE, 0L); curl_easy_setopt(_easy, CURLOPT_FOLLOWLOCATION, 1L); //probably it's OK to have it always on - curl_easy_setopt(_easy, CURLOPT_HTTPHEADER, headersList); - if (postFields.size() != 0) { - curl_easy_setopt(_easy, CURLOPT_POSTFIELDSIZE, postFields.size()); - curl_easy_setopt(_easy, CURLOPT_COPYPOSTFIELDS, postFields.c_str()); + curl_easy_setopt(_easy, CURLOPT_HTTPHEADER, headersList); + if (post || bufferSize != 0) { + curl_easy_setopt(_easy, CURLOPT_POSTFIELDSIZE, bufferSize); + curl_easy_setopt(_easy, CURLOPT_COPYPOSTFIELDS, buffer); } ConnMan.registerEasyHandle(_easy); } diff --git a/backends/networking/curl/networkreadstream.h b/backends/networking/curl/networkreadstream.h index 33edade8d7..f1f41264aa 100644 --- a/backends/networking/curl/networkreadstream.h +++ b/backends/networking/curl/networkreadstream.h @@ -38,6 +38,7 @@ class NetworkReadStream: public Common::MemoryReadWriteStream { public: NetworkReadStream(const char *url, curl_slist *headersList, Common::String postFields); + NetworkReadStream(const char *url, curl_slist *headersList, byte *buffer, uint32 bufferSize, bool post = true); virtual ~NetworkReadStream(); /** |