diff options
| author | Alexander Tkachev | 2016-05-27 15:21:06 +0600 | 
|---|---|---|
| committer | Alexander Tkachev | 2016-08-24 16:07:55 +0600 | 
| commit | 98150beb38f73b56c7bc76f95dcc1d72290e4ac7 (patch) | |
| tree | c56f8d97d30fb15f41f07f402c80e83a13cc03fc /backends | |
| parent | 83b349a033d71e92e292d1f1da0578d557ec6411 (diff) | |
| download | scummvm-rg350-98150beb38f73b56c7bc76f95dcc1d72290e4ac7.tar.gz scummvm-rg350-98150beb38f73b56c7bc76f95dcc1d72290e4ac7.tar.bz2 scummvm-rg350-98150beb38f73b56c7bc76f95dcc1d72290e4ac7.zip | |
CLOUD: Refactor ConnectionManager/Requests system
ConnectionManager now storages Request * (not generates ids for it),
Requests have control on their RequestState, RequestIdPair is now called
Response and storages Request * with some response together.
All related classes are changed to use it in more clean and
understandable way.
Request, RequestState and Response are carefully commented/documented.
Diffstat (limited to 'backends')
19 files changed, 323 insertions, 237 deletions
| diff --git a/backends/cloud/downloadrequest.cpp b/backends/cloud/downloadrequest.cpp index 661d6fd56b..c7f6f75346 100644 --- a/backends/cloud/downloadrequest.cpp +++ b/backends/cloud/downloadrequest.cpp @@ -29,14 +29,13 @@ namespace Cloud {  DownloadRequest::DownloadRequest(Storage *storage, Storage::BoolCallback callback, Common::String remoteFile, Common::DumpFile *dumpFile):  	Request(0), _boolCallback(callback), _remoteFileStream(0), _localFile(dumpFile) { -	storage->streamFile(remoteFile, new Common::Callback<DownloadRequest, Storage::RequestReadStreamPair>(this, &DownloadRequest::streamCallback)); +	storage->streamFile(remoteFile, new Common::Callback<DownloadRequest, Networking::NetworkReadStreamResponse>(this, &DownloadRequest::streamCallback));  } -void DownloadRequest::streamCallback(Storage::RequestReadStreamPair pair) { +void DownloadRequest::streamCallback(Networking::NetworkReadStreamResponse pair) {  	if (!pair.value) {  		warning("DownloadRequest: no ReadStream passed"); -		ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -		if (_boolCallback) (*_boolCallback)(Storage::RequestBoolPair(_id, false)); +		finish();  		return;  	} @@ -46,15 +45,13 @@ void DownloadRequest::streamCallback(Storage::RequestReadStreamPair pair) {  void DownloadRequest::handle() {	  	if (!_localFile) {  		warning("DownloadRequest: no file to write"); -		ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -		if (_boolCallback) (*_boolCallback)(Storage::RequestBoolPair(_id, false)); +		finish();  		return;  	}  	if (!_localFile->isOpen()) {  		warning("DownloadRequest: failed to open file to write"); -		ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -		if (_boolCallback) (*_boolCallback)(Storage::RequestBoolPair(_id, false)); +		finish();  		return;  	} @@ -70,8 +67,7 @@ void DownloadRequest::handle() {  	if (readBytes != 0)  		if (_localFile->write(buf, readBytes) != readBytes) {  			warning("DownloadRequest: unable to write all received bytes into output file"); -			ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -			if (_boolCallback) (*_boolCallback)(Storage::RequestBoolPair(_id, false)); +			finish();  			return;  		} @@ -81,8 +77,7 @@ void DownloadRequest::handle() {  			//TODO: do something about it actually			  		} -		ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -		if (_boolCallback) (*_boolCallback)(Storage::RequestBoolPair(_id, _remoteFileStream->httpResponseCode() == 200)); +		finishBool(_remoteFileStream->httpResponseCode() == 200);  		_localFile->close(); //yes, I know it's closed automatically in ~DumpFile()		  	} @@ -92,9 +87,17 @@ void DownloadRequest::restart() {  	//this request doesn't know anything about the _remoteFileStream it's reading  	//thus, it can't restart it  	warning("DownloadRequest: cannot be restarted"); -	ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -	if (_boolCallback) (*_boolCallback)(Storage::RequestBoolPair(_id, false)); +	finish();  	//TODO: fix that  } +void DownloadRequest::finish() { +	finishBool(false); +} + +void DownloadRequest::finishBool(bool success) { +	Request::finish(); +	if (_boolCallback) (*_boolCallback)(Storage::BoolResponse(this, success)); +} +  } //end of namespace Cloud diff --git a/backends/cloud/downloadrequest.h b/backends/cloud/downloadrequest.h index 181536beba..4ea85760ae 100644 --- a/backends/cloud/downloadrequest.h +++ b/backends/cloud/downloadrequest.h @@ -26,7 +26,7 @@  #include "backends/networking/curl/request.h"  #include "backends/networking/curl/networkreadstream.h"  #include "backends/cloud/storage.h" -#include <common/file.h> +#include "common/file.h"  namespace Cloud { @@ -35,13 +35,16 @@ class DownloadRequest: public Networking::Request {  	Networking::NetworkReadStream *_remoteFileStream;  	Common::DumpFile *_localFile;	 -	void streamCallback(Storage::RequestReadStreamPair pair); +	void streamCallback(Networking::NetworkReadStreamResponse pair); + +	void finishBool(bool success);  public:  	DownloadRequest(Storage *storage, Storage::BoolCallback callback, Common::String remoteFile, Common::DumpFile *dumpFile);  	virtual ~DownloadRequest() { delete _localFile; }  	virtual void handle();  	virtual void restart(); +	virtual void finish();  };  } //end of namespace Cloud diff --git a/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp b/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp index 3158149c02..04fbf46ac6 100644 --- a/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp +++ b/backends/cloud/dropbox/dropboxlistdirectoryrequest.cpp @@ -32,7 +32,7 @@ namespace Dropbox {  DropboxListDirectoryRequest::DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::FileArrayCallback cb, bool recursive):  	Networking::Request(0), _requestedPath(path), _requestedRecursive(recursive), _filesCallback(cb), -	_token(token), _complete(false), _requestId(-1) { +	_token(token), _complete(false), _innerRequest(nullptr) {  	startupWork();  } @@ -40,7 +40,7 @@ void DropboxListDirectoryRequest::startupWork() {  	_files.clear();  	_complete = false; -	Networking::JsonCallback innerCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::RequestJsonPair>(this, &DropboxListDirectoryRequest::responseCallback); +	Networking::JsonCallback innerCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::JsonResponse>(this, &DropboxListDirectoryRequest::responseCallback);  	Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/2/files/list_folder");  	request->addHeader("Authorization: Bearer " + _token);  	request->addHeader("Content-Type: application/json"); @@ -54,11 +54,11 @@ void DropboxListDirectoryRequest::startupWork() {  	Common::JSONValue value(jsonRequestParameters);  	request->addPostField(Common::JSON::stringify(&value)); -	_requestId = ConnMan.addRequest(request); +	_innerRequest = ConnMan.addRequest(request);  } -void DropboxListDirectoryRequest::responseCallback(Networking::RequestJsonPair pair) { +void DropboxListDirectoryRequest::responseCallback(Networking::JsonResponse pair) {  	Common::JSONValue *json = pair.value;  	if (json) {  		Common::JSONObject response = json->asObject(); @@ -89,7 +89,7 @@ void DropboxListDirectoryRequest::responseCallback(Networking::RequestJsonPair p  		bool hasMore = response.getVal("has_more")->asBool();  		if (hasMore) { -			Networking::JsonCallback innerCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::RequestJsonPair>(this, &DropboxListDirectoryRequest::responseCallback); +			Networking::JsonCallback innerCallback = new Common::Callback<DropboxListDirectoryRequest, Networking::JsonResponse>(this, &DropboxListDirectoryRequest::responseCallback);  			Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/2/files/list_folder/continue");  			request->addHeader("Authorization: Bearer " + _token);  			request->addHeader("Content-Type: application/json"); @@ -113,22 +113,28 @@ void DropboxListDirectoryRequest::responseCallback(Networking::RequestJsonPair p  }  void DropboxListDirectoryRequest::handle() { -	if (_complete) { -		ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -		if (_filesCallback) (*_filesCallback)(Storage::RequestFileArrayPair(_id, _files)); -	} +	if (_complete) finishFiles(_files);	  }  void DropboxListDirectoryRequest::restart() { -	if (_requestId != -1) { -		Networking::RequestInfo &info = ConnMan.getRequestInfo(_requestId); +	if (_innerRequest) {		  		//TODO: I'm really not sure some CurlRequest would handle this (it must stop corresponding CURL transfer) -		info.state = Networking::FINISHED; //may be CANCELED or INTERRUPTED or something? -		_requestId = -1; +		_innerRequest->finish(); //may be CANCELED or INTERRUPTED or something? +		_innerRequest = nullptr;  	}  	startupWork();  } +void DropboxListDirectoryRequest::finish() { +	Common::Array<StorageFile> files; +	finishFiles(files); +} + +void DropboxListDirectoryRequest::finishFiles(Common::Array<StorageFile> &files) { +	Request::finish(); +	if (_filesCallback) (*_filesCallback)(Storage::FileArrayResponse(this, files)); +} +  } //end of namespace Dropbox  } //end of namespace Cloud diff --git a/backends/cloud/dropbox/dropboxlistdirectoryrequest.h b/backends/cloud/dropbox/dropboxlistdirectoryrequest.h index 9a82ef7091..e2a9ebf3a4 100644 --- a/backends/cloud/dropbox/dropboxlistdirectoryrequest.h +++ b/backends/cloud/dropbox/dropboxlistdirectoryrequest.h @@ -39,17 +39,20 @@ class DropboxListDirectoryRequest: public Networking::Request {  	Common::String _token;  	bool _complete;  	Common::Array<StorageFile> _files; -	int32 _requestId; +	Request *_innerRequest; -	void responseCallback(Networking::RequestJsonPair pair); +	void responseCallback(Networking::JsonResponse pair);  	void startupWork(); +	void finishFiles(Common::Array<StorageFile> &files); +  public:  	DropboxListDirectoryRequest(Common::String token, Common::String path, Storage::FileArrayCallback cb, bool recursive = false);  	virtual ~DropboxListDirectoryRequest() { delete _filesCallback; }  	virtual void handle();  	virtual void restart(); +	virtual void finish();  };  } //end of namespace Dropbox diff --git a/backends/cloud/dropbox/dropboxstorage.cpp b/backends/cloud/dropbox/dropboxstorage.cpp index b5292c83c7..a1a97e00dd 100644 --- a/backends/cloud/dropbox/dropboxstorage.cpp +++ b/backends/cloud/dropbox/dropboxstorage.cpp @@ -38,7 +38,7 @@ namespace Dropbox {  Common::String DropboxStorage::KEY; //can't use ConfMan there yet, loading it on instance creation/auth  Common::String DropboxStorage::SECRET; //TODO: hide these secrets somehow -static void saveAccessTokenCallback(Networking::RequestJsonPair pair) { +static void saveAccessTokenCallback(Networking::JsonResponse pair) {  	Common::JSONValue *json = (Common::JSONValue *)pair.value;  	if (json) {  		debug("saveAccessTokenCallback:"); @@ -55,6 +55,7 @@ static void saveAccessTokenCallback(Networking::RequestJsonPair pair) {  			ConfMan.set("storage1_access_token", result.getVal("access_token")->asString(), "cloud");  			ConfMan.set("storage1_user_id", result.getVal("uid")->asString(), "cloud");  			ConfMan.removeKey("dropbox_code", "cloud"); +			ConfMan.flushToDisk();  			debug("Now please restart ScummVM to apply the changes.");  		} @@ -84,11 +85,11 @@ void DropboxStorage::printFiles(Common::Array<StorageFile> files) {  		debug("\t%s", files[i].name().c_str());  } -int32 DropboxStorage::listDirectory(Common::String path, FileArrayCallback outerCallback, bool recursive) { +Networking::Request *DropboxStorage::listDirectory(Common::String path, FileArrayCallback outerCallback, bool recursive) {  	return ConnMan.addRequest(new DropboxListDirectoryRequest(_token, path, outerCallback, recursive));  } -int32 DropboxStorage::streamFile(Common::String path, ReadStreamCallback callback) { +Networking::Request *DropboxStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback callback) {  	Common::JSONObject jsonRequestParameters;  	jsonRequestParameters.setVal("path", new Common::JSONValue(path));  	Common::JSONValue value(jsonRequestParameters); @@ -98,32 +99,32 @@ int32 DropboxStorage::streamFile(Common::String path, ReadStreamCallback callbac  	request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value));  	request->addHeader("Content-Type: "); //required to be empty (as we do POST, it's usually app/form-url-encoded) -	RequestReadStreamPair pair = request->execute(); +	Networking::NetworkReadStreamResponse pair = request->execute();  	if (callback) (*callback)(pair); -	return pair.id; +	return pair.request;  } -int32 DropboxStorage::download(Common::String remotePath, Common::String localPath, BoolCallback callback) { +Networking::Request *DropboxStorage::download(Common::String remotePath, Common::String localPath, BoolCallback callback) {  	Common::DumpFile *f = new Common::DumpFile();  	if (!f->open(localPath, true)) {  		warning("DropboxStorage: unable to open file to download into"); -		if (callback) (*callback)(RequestBoolPair(-1, false)); +		if (callback) (*callback)(BoolResponse(nullptr, false));  		delete f; -		return -1; +		return nullptr;  	}  	return ConnMan.addRequest(new DownloadRequest(this, callback, remotePath, f));  } -int32 DropboxStorage::syncSaves(BoolCallback callback) { +Networking::Request *DropboxStorage::syncSaves(BoolCallback callback) {  	//this is not the real syncSaves() implementation	  	//"" is root in Dropbox, not "/"  	//this must create all these directories:  	return download("/remote/test.jpg", "local/a/b/c/d/test.jpg", 0);  } -int32 DropboxStorage::info(StorageInfoCallback outerCallback) { -	Networking::JsonCallback innerCallback = new Common::CallbackBridge<DropboxStorage, RequestStorageInfoPair, Networking::RequestJsonPair>(this, &DropboxStorage::infoInnerCallback, outerCallback); +Networking::Request *DropboxStorage::info(StorageInfoCallback outerCallback) { +	Networking::JsonCallback innerCallback = new Common::CallbackBridge<DropboxStorage, StorageInfoResponse, Networking::JsonResponse>(this, &DropboxStorage::infoInnerCallback, outerCallback);  	Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://api.dropboxapi.com/1/account/info");  	request->addHeader("Authorization: Bearer " + _token);  	return ConnMan.addRequest(request); @@ -133,7 +134,7 @@ int32 DropboxStorage::info(StorageInfoCallback outerCallback) {  	//and then calls the outerCallback (which wants to receive StorageInfo, not void *)  } -void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::RequestJsonPair pair) { +void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse pair) {  	Common::JSONValue *json = pair.value;  	if (!json) {  		warning("NULL passed instead of JSON"); @@ -151,14 +152,14 @@ void DropboxStorage::infoInnerCallback(StorageInfoCallback outerCallback, Networ  		uint32 quotaNormal = quota.getVal("normal")->asNumber();  		uint32 quotaShared = quota.getVal("shared")->asNumber();  		uint32 quotaAllocated = quota.getVal("quota")->asNumber(); -		(*outerCallback)(RequestStorageInfoPair(-1, StorageInfo(uid, name, email, quotaNormal+quotaShared, quotaAllocated))); +		(*outerCallback)(StorageInfoResponse(nullptr, StorageInfo(uid, name, email, quotaNormal+quotaShared, quotaAllocated)));  		delete outerCallback;  	}  	delete json;  } -void DropboxStorage::infoMethodCallback(RequestStorageInfoPair pair) { +void DropboxStorage::infoMethodCallback(StorageInfoResponse pair) {  	debug("\nStorage info:");  	debug("User name: %s", pair.value.name().c_str());  	debug("Email: %s", pair.value.email().c_str()); @@ -216,7 +217,7 @@ void DropboxStorage::authThroughConsole() {  }  void DropboxStorage::getAccessToken(Common::String code) { -	Networking::JsonCallback callback = new Common::GlobalFunctionCallback<Networking::RequestJsonPair>(saveAccessTokenCallback); +	Networking::JsonCallback callback = new Common::GlobalFunctionCallback<Networking::JsonResponse>(saveAccessTokenCallback);  	Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, "https://api.dropboxapi.com/1/oauth2/token");  	request->addPostField("code=" + code);  	request->addPostField("grant_type=authorization_code"); diff --git a/backends/cloud/dropbox/dropboxstorage.h b/backends/cloud/dropbox/dropboxstorage.h index dd082b25f1..f95d0c9812 100644 --- a/backends/cloud/dropbox/dropboxstorage.h +++ b/backends/cloud/dropbox/dropboxstorage.h @@ -41,7 +41,7 @@ class DropboxStorage: public Cloud::Storage {  	static void getAccessToken(Common::String code);  	/** Constructs StorageInfo based on JSON response from cloud. */ -	void infoInnerCallback(StorageInfoCallback outerCallback, Networking::RequestJsonPair json); +	void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json);  	void printFiles(Common::Array<StorageFile> files); @@ -65,34 +65,34 @@ public:  	/** Public Cloud API comes down there. */  	/** Returns Common::Array<StorageFile>. */ -	virtual int32 listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false); +	virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false);  	/** Calls the callback when finished. */ -	virtual int32 upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) { return -1; } //TODO +	virtual Networking::Request *upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) { return nullptr; } //TODO  	/** Returns pointer to Networking::NetworkReadStream. */ -	virtual int32 streamFile(Common::String path, ReadStreamCallback callback); +	virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback);  	/** Calls the callback when finished. */ -	virtual int32 download(Common::String remotePath, Common::String localPath, BoolCallback callback); +	virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback);  	/** Calls the callback when finished. */ -	virtual int32 remove(Common::String path, BoolCallback callback) { return -1; } //TODO +	virtual Networking::Request *remove(Common::String path, BoolCallback callback) { return nullptr; } //TODO  	/** Calls the callback when finished. */ -	virtual int32 syncSaves(BoolCallback callback); +	virtual Networking::Request *syncSaves(BoolCallback callback);  	/** Calls the callback when finished. */ -	virtual int32 createDirectory(Common::String path, BoolCallback callback) { return -1; } //TODO +	virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback) { return nullptr; } //TODO  	/** Calls the callback when finished. */ -	virtual int32 touch(Common::String path, BoolCallback callback) { return -1; } //TODO +	virtual Networking::Request *touch(Common::String path, BoolCallback callback) { return nullptr; } //TODO  	/** Returns the StorageInfo struct. */ -	virtual int32 info(StorageInfoCallback callback); +	virtual Networking::Request *info(StorageInfoCallback callback);  	/** This method is passed into info(). (Temporary) */ -	void infoMethodCallback(RequestStorageInfoPair pair); +	void infoMethodCallback(StorageInfoResponse pair);  	/** Returns whether saves sync process is running. */  	virtual bool isSyncing() { return false; } //TODO diff --git a/backends/cloud/onedrive/onedrivestorage.cpp b/backends/cloud/onedrive/onedrivestorage.cpp index 237557df59..e181fecabb 100644 --- a/backends/cloud/onedrive/onedrivestorage.cpp +++ b/backends/cloud/onedrive/onedrivestorage.cpp @@ -44,7 +44,7 @@ OneDriveStorage::OneDriveStorage(Common::String accessToken, Common::String user  	_token(accessToken), _uid(userId), _refreshToken(refreshToken) {}  OneDriveStorage::OneDriveStorage(Common::String code) { -	getAccessToken(new Common::Callback<OneDriveStorage, RequestBoolPair>(this, &OneDriveStorage::codeFlowComplete), code); +	getAccessToken(new Common::Callback<OneDriveStorage, BoolResponse>(this, &OneDriveStorage::codeFlowComplete), code);  }  OneDriveStorage::~OneDriveStorage() {} @@ -54,11 +54,11 @@ void OneDriveStorage::getAccessToken(BoolCallback callback, Common::String code)  	if (!codeFlow && _refreshToken == "") {  		warning("OneDriveStorage: no refresh token available to get new access token."); -		if (callback) (*callback)(RequestBoolPair(-1, false)); +		if (callback) (*callback)(BoolResponse(nullptr, false));  		return;  	} -	Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, RequestBoolPair, Networking::RequestJsonPair>(this, &OneDriveStorage::tokenRefreshed, callback); +	Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, BoolResponse, Networking::JsonResponse>(this, &OneDriveStorage::tokenRefreshed, callback);  	Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, "https://login.live.com/oauth20_token.srf");  	if (codeFlow) {  		request->addPostField("code=" + code); @@ -73,11 +73,11 @@ void OneDriveStorage::getAccessToken(BoolCallback callback, Common::String code)  	ConnMan.addRequest(request);  } -void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::RequestJsonPair pair) { +void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse pair) {  	Common::JSONValue *json = pair.value;  	if (!json) {  		warning("OneDriveStorage: got NULL instead of JSON"); -		if (callback) (*callback)(RequestBoolPair(-1, false)); +		if (callback) (*callback)(BoolResponse(nullptr, false));  		return;  	} @@ -85,18 +85,18 @@ void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::RequestJ  	if (!result.contains("access_token") || !result.contains("user_id") || !result.contains("refresh_token")) {  		warning("Bad response, no token or user_id passed");  		debug("%s", json->stringify().c_str()); -		if (callback) (*callback)(RequestBoolPair(-1, false)); +		if (callback) (*callback)(BoolResponse(nullptr, false));  	} else {  		_token = result.getVal("access_token")->asString();  		_uid = result.getVal("user_id")->asString();  		_refreshToken = result.getVal("refresh_token")->asString();  		g_system->getCloudManager()->save(); //ask CloudManager to save our new refreshToken -		if (callback) (*callback)(RequestBoolPair(-1, true)); +		if (callback) (*callback)(BoolResponse(nullptr, true));  	}  	delete json;  } -void OneDriveStorage::codeFlowComplete(RequestBoolPair pair) { +void OneDriveStorage::codeFlowComplete(BoolResponse pair) {  	if (!pair.value) {  		warning("OneDriveStorage: failed to get access token through code flow");  		return; @@ -115,7 +115,7 @@ void OneDriveStorage::saveConfig(Common::String keyPrefix) {  	ConfMan.set(keyPrefix + "refresh_token", _refreshToken, "cloud");  } -void OneDriveStorage::printJson(Networking::RequestJsonPair pair) { +void OneDriveStorage::printJson(Networking::JsonResponse pair) {  	Common::JSONValue *json = pair.value;  	if (!json) {  		warning("printJson: NULL"); @@ -126,10 +126,10 @@ void OneDriveStorage::printJson(Networking::RequestJsonPair pair) {  	delete json;  } -void OneDriveStorage::fileInfoCallback(ReadStreamCallback outerCallback, Networking::RequestJsonPair pair) { +void OneDriveStorage::fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse pair) {  	if (!pair.value) {  		warning("fileInfoCallback: NULL"); -		if (outerCallback) (*outerCallback)(RequestReadStreamPair(pair.id, 0)); +		if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(pair.request, 0));  		return;  	} @@ -137,44 +137,44 @@ void OneDriveStorage::fileInfoCallback(ReadStreamCallback outerCallback, Network  	if (result.contains("@content.downloadUrl")) {  		const char *url = result.getVal("@content.downloadUrl")->asString().c_str();  		if (outerCallback) -			(*outerCallback)(RequestReadStreamPair( -				pair.id, +			(*outerCallback)(Networking::NetworkReadStreamResponse( +				pair.request,  				new Networking::NetworkReadStream(url, 0, "")  			));  	} else {  		warning("downloadUrl not found in passed JSON");  		debug("%s", pair.value->stringify().c_str()); -		if (outerCallback) (*outerCallback)(RequestReadStreamPair(pair.id, 0)); +		if (outerCallback) (*outerCallback)(Networking::NetworkReadStreamResponse(pair.request, 0));  	}  	delete pair.value;  } -int32 OneDriveStorage::streamFile(Common::String path, ReadStreamCallback outerCallback) { -	Common::String url = "https://api.onedrive.com/v1.0/drive/special/approot:/" + path + ":/";	 -	Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, RequestReadStreamPair, Networking::RequestJsonPair>(this, &OneDriveStorage::fileInfoCallback, outerCallback); +Networking::Request *OneDriveStorage::streamFile(Common::String path, Networking::NetworkReadStreamCallback outerCallback) { +	Common::String url = "https://api.onedrive.com/v1.0/drive/special/approot:/" + path; +	Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, Networking::NetworkReadStreamResponse, Networking::JsonResponse>(this, &OneDriveStorage::fileInfoCallback, outerCallback);  	Networking::CurlJsonRequest *request = new OneDriveTokenRefresher(this, innerCallback, url.c_str());  	request->addHeader("Authorization: Bearer " + _token);  	return ConnMan.addRequest(request);  } -int32 OneDriveStorage::download(Common::String remotePath, Common::String localPath, BoolCallback callback) { +Networking::Request *OneDriveStorage::download(Common::String remotePath, Common::String localPath, BoolCallback callback) {  	Common::DumpFile *f = new Common::DumpFile();  	if (!f->open(localPath, true)) {  		warning("OneDriveStorage: unable to open file to download into"); -		if (callback) (*callback)(RequestBoolPair(-1, false)); +		if (callback) (*callback)(BoolResponse(nullptr, false));  		delete f; -		return -1; +		return nullptr;  	}  	return ConnMan.addRequest(new DownloadRequest(this, callback, remotePath, f));  } -void OneDriveStorage::fileDownloaded(RequestBoolPair pair) { +void OneDriveStorage::fileDownloaded(BoolResponse pair) {  	if (pair.value) debug("file downloaded!");  	else debug("download failed!");  } -int32 OneDriveStorage::syncSaves(BoolCallback callback) { +Networking::Request *OneDriveStorage::syncSaves(BoolCallback callback) {  	//this is not the real syncSaves() implementation  	/*  	Networking::JsonCallback innerCallback = new Common::Callback<OneDriveStorage, Networking::RequestJsonPair>(this, &OneDriveStorage::printJson); @@ -182,7 +182,7 @@ int32 OneDriveStorage::syncSaves(BoolCallback callback) {  	request->addHeader("Authorization: bearer " + _token);  	return ConnMan.addRequest(request);  	*/ -	return download("pic.jpg", "local/onedrive/2/doom.jpg", new Common::Callback<OneDriveStorage, RequestBoolPair>(this, &OneDriveStorage::fileDownloaded)); +	return download("pic.jpg", "local/onedrive/2/doom.jpg", new Common::Callback<OneDriveStorage, BoolResponse>(this, &OneDriveStorage::fileDownloaded));  }  OneDriveStorage *OneDriveStorage::loadFromConfig(Common::String keyPrefix) { diff --git a/backends/cloud/onedrive/onedrivestorage.h b/backends/cloud/onedrive/onedrivestorage.h index be2bcdf04c..858af6c9bf 100644 --- a/backends/cloud/onedrive/onedrivestorage.h +++ b/backends/cloud/onedrive/onedrivestorage.h @@ -44,13 +44,13 @@ class OneDriveStorage: public Cloud::Storage {  	*/  	OneDriveStorage(Common::String code); -	void tokenRefreshed(BoolCallback callback, Networking::RequestJsonPair pair); -	void codeFlowComplete(RequestBoolPair pair); +	void tokenRefreshed(BoolCallback callback, Networking::JsonResponse pair); +	void codeFlowComplete(BoolResponse pair); -	void printJson(Networking::RequestJsonPair pair); -	void fileDownloaded(RequestBoolPair pair); +	void printJson(Networking::JsonResponse pair); +	void fileDownloaded(BoolResponse pair); -	void fileInfoCallback(ReadStreamCallback outerCallback, Networking::RequestJsonPair pair); +	void fileInfoCallback(Networking::NetworkReadStreamCallback outerCallback, Networking::JsonResponse pair);  public:	  	virtual ~OneDriveStorage(); @@ -71,31 +71,31 @@ public:  	/** Public Cloud API comes down there. */  	/** Returns Common::Array<StorageFile>. */ -	virtual int32 listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false) { return -1; } //TODO +	virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false) { return nullptr; } //TODO  	/** Calls the callback when finished. */ -	virtual int32 upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) { return -1; } //TODO +	virtual Networking::Request *upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) { return nullptr; } //TODO  	/** Returns pointer to Networking::NetworkReadStream. */ -	virtual int32 streamFile(Common::String path, ReadStreamCallback callback); +	virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback);  	/** Calls the callback when finished. */ -	virtual int32 download(Common::String remotePath, Common::String localPath, BoolCallback callback); +	virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback);  	/** Calls the callback when finished. */ -	virtual int32 remove(Common::String path, BoolCallback callback) { return -1; } //TODO +	virtual Networking::Request *remove(Common::String path, BoolCallback callback) { return nullptr; } //TODO  	/** Calls the callback when finished. */ -	virtual int32 syncSaves(BoolCallback callback); +	virtual Networking::Request *syncSaves(BoolCallback callback);  	/** Calls the callback when finished. */ -	virtual int32 createDirectory(Common::String path, BoolCallback callback) { return -1; } //TODO +	virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback) { return nullptr; } //TODO  	/** Calls the callback when finished. */ -	virtual int32 touch(Common::String path, BoolCallback callback) { return -1; } //TODO +	virtual Networking::Request *touch(Common::String path, BoolCallback callback) { return nullptr; } //TODO  	/** Returns the StorageInfo struct. */ -	virtual int32 info(StorageInfoCallback callback) { return -1; } //TODO +	virtual Networking::Request *info(StorageInfoCallback callback) { return nullptr; } //TODO  	/** Returns whether saves sync process is running. */  	virtual bool isSyncing() { return false; } //TODO diff --git a/backends/cloud/onedrive/onedrivetokenrefresher.cpp b/backends/cloud/onedrive/onedrivetokenrefresher.cpp index d3ec0cc668..6943d89297 100644 --- a/backends/cloud/onedrive/onedrivetokenrefresher.cpp +++ b/backends/cloud/onedrive/onedrivetokenrefresher.cpp @@ -38,50 +38,45 @@ OneDriveTokenRefresher::OneDriveTokenRefresher(OneDriveStorage *parent, Networki  	_parentStorage(parent),  	_innerRequest(  		new CurlJsonRequest( -			new Common::Callback<OneDriveTokenRefresher, Networking::RequestJsonPair>(this, &OneDriveTokenRefresher::innerRequestCallback), +			new Common::Callback<OneDriveTokenRefresher, Networking::JsonResponse>(this, &OneDriveTokenRefresher::innerRequestCallback),  			url  		) -	), _jsonCallback(callback), _retryId(-1), _started(false) {} +	), _jsonCallback(callback), _retryRequest(nullptr), _started(false) {}  OneDriveTokenRefresher::~OneDriveTokenRefresher() {} -void OneDriveTokenRefresher::innerRequestCallback(Networking::RequestJsonPair pair) { +void OneDriveTokenRefresher::innerRequestCallback(Networking::JsonResponse pair) {  	if (!pair.value) {  		//notify user of failure  		warning("OneDriveTokenRefresher: got NULL instead of JSON"); -		ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -		if (_jsonCallback) (*_jsonCallback)(Networking::RequestJsonPair(_id, 0)); +		finish();  		return;  	}  	Common::JSONObject result = pair.value->asObject();  	if (result.contains("error")) {  		//new token needed => request token & then retry original request		 -		ConnMan.getRequestInfo(pair.id).state = Networking::PAUSED; -		_retryId = pair.id;	 +		if (pair.request) pair.request->pause(); +		_retryRequest = pair.request;  		delete pair.value; -		_parentStorage->getAccessToken(new Common::Callback<OneDriveTokenRefresher, Storage::RequestBoolPair>(this, &OneDriveTokenRefresher::tokenRefreshed)); +		_parentStorage->getAccessToken(new Common::Callback<OneDriveTokenRefresher, Storage::BoolResponse>(this, &OneDriveTokenRefresher::tokenRefreshed));  		return;  	}  	//notify user of success	 -	ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -	if (_jsonCallback) (*_jsonCallback)(Networking::RequestJsonPair(_id, pair.value)); +	finishJson(pair.value);  } -void OneDriveTokenRefresher::tokenRefreshed(Storage::RequestBoolPair pair) { +void OneDriveTokenRefresher::tokenRefreshed(Storage::BoolResponse pair) {  	if (!pair.value) {  		//failed to refresh token, notify user with NULL in original callback  		warning("OneDriveTokenRefresher: failed to refresh token"); -		ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -		if (_jsonCallback) (*_jsonCallback)(Networking::RequestJsonPair(_id, 0)); +		finish();  		return;  	}  	//successfully received refreshed token, can restart the original request now	 -	Networking::RequestInfo &info = ConnMan.getRequestInfo(_retryId); -	info.state = Networking::RETRY; -	info.retryInSeconds = 1; +	if (_retryRequest) _retryRequest->retry(1);  	//update headers: first change header with token, then pass those to request  	for (uint32 i = 0; i < _headers.size(); ++i) { @@ -89,7 +84,7 @@ void OneDriveTokenRefresher::tokenRefreshed(Storage::RequestBoolPair pair) {  			_headers[i] = "Authorization: bearer " + _parentStorage->accessToken();  		}  	} -	CurlJsonRequest *retryRequest = (CurlJsonRequest *)info.request; +	CurlJsonRequest *retryRequest = (CurlJsonRequest *)_retryRequest;  	if (retryRequest) retryRequest->setHeaders(_headers);  } @@ -105,11 +100,19 @@ void OneDriveTokenRefresher::handle() {  void OneDriveTokenRefresher::restart() {  	//can't restart as all headers were passed to _innerRequest which is probably dead now  	warning("OneDriveTokenRefresher: cannot be restarted"); -	ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -	if (_jsonCallback) (*_jsonCallback)(Networking::RequestJsonPair(_id, 0)); +	finish();  } -Cloud::Storage::RequestReadStreamPair OneDriveTokenRefresher::execute() { +void OneDriveTokenRefresher::finish() { +	finishJson(0); +} + +void OneDriveTokenRefresher::finishJson(Common::JSONValue *json) { +	Request::finish(); +	if (_jsonCallback) (*_jsonCallback)(Networking::JsonResponse(this, json)); +} + +Networking::NetworkReadStreamResponse OneDriveTokenRefresher::execute() {  	if (!_started) {  		for (uint32 i = 0; i < _headers.size(); ++i)  			_innerRequest->addHeader(_headers[i]); diff --git a/backends/cloud/onedrive/onedrivetokenrefresher.h b/backends/cloud/onedrive/onedrivetokenrefresher.h index 58b7dcedb4..c09879feed 100644 --- a/backends/cloud/onedrive/onedrivetokenrefresher.h +++ b/backends/cloud/onedrive/onedrivetokenrefresher.h @@ -35,24 +35,27 @@ class OneDriveStorage;  class OneDriveTokenRefresher: public Networking::CurlJsonRequest {  	OneDriveStorage *_parentStorage;  	Common::Array<Common::String> _headers; -	Networking::CurlJsonRequest *_innerRequest; +	CurlJsonRequest *_innerRequest;  	Networking::JsonCallback _jsonCallback; -	int32 _retryId; +	Request *_retryRequest;  	bool _started; -	void innerRequestCallback(Networking::RequestJsonPair pair); -	void tokenRefreshed(Storage::RequestBoolPair pair); +	void innerRequestCallback(Networking::JsonResponse pair); +	void tokenRefreshed(Storage::BoolResponse pair); + +	virtual void finishJson(Common::JSONValue *json);  public:	  	OneDriveTokenRefresher(OneDriveStorage *parent, Networking::JsonCallback callback, const char *url);  	virtual ~OneDriveTokenRefresher();  	virtual void handle();  	virtual void restart(); +	virtual void finish();  	virtual void setHeaders(Common::Array<Common::String> &headers) { _headers = headers; }  	virtual void addHeader(Common::String header) { _headers.push_back(header); }  	virtual void addPostField(Common::String field) { _innerRequest->addPostField(field); } -	virtual Cloud::Storage::RequestReadStreamPair execute(); +	virtual Networking::NetworkReadStreamResponse execute();  };  } //end of namespace OneDrive diff --git a/backends/cloud/storage.h b/backends/cloud/storage.h index 0114b46dee..8ae5308a1c 100644 --- a/backends/cloud/storage.h +++ b/backends/cloud/storage.h @@ -23,28 +23,26 @@  #ifndef BACKENDS_CLOUD_STORAGE_H  #define BACKENDS_CLOUD_STORAGE_H +#include "backends/cloud/storagefile.h" +#include "backends/cloud/storageinfo.h" +#include "backends/networking/curl/request.h" +#include "backends/networking/curl/curlrequest.h"  #include "common/array.h"  #include "common/stream.h"  #include "common/str.h"  #include "common/callback.h" -#include "backends/cloud/storagefile.h" -#include "backends/cloud/storageinfo.h" -#include "backends/networking/curl/networkreadstream.h" -#include <backends/networking/curl/request.h>  namespace Cloud {  class Storage {  public: -	typedef Networking::RequestIdPair<Common::Array<StorageFile>&> RequestFileArrayPair; -	typedef Networking::RequestIdPair<Networking::NetworkReadStream *> RequestReadStreamPair; -	typedef Networking::RequestIdPair<StorageInfo> RequestStorageInfoPair; -	typedef Networking::RequestIdPair<bool> RequestBoolPair;	 +	typedef Networking::Response<Common::Array<StorageFile>&> FileArrayResponse; +	typedef Networking::Response<StorageInfo> StorageInfoResponse; +	typedef Networking::Response<bool> BoolResponse; -	typedef Common::BaseCallback<RequestFileArrayPair> *FileArrayCallback; -	typedef Common::BaseCallback<RequestReadStreamPair> *ReadStreamCallback; -	typedef Common::BaseCallback<RequestStorageInfoPair> *StorageInfoCallback; -	typedef Common::BaseCallback<RequestBoolPair> *BoolCallback; +	typedef Common::BaseCallback<FileArrayResponse> *FileArrayCallback; +	typedef Common::BaseCallback<StorageInfoResponse> *StorageInfoCallback; +	typedef Common::BaseCallback<BoolResponse> *BoolCallback;  	Storage() {}  	virtual ~Storage() {} @@ -66,37 +64,37 @@ public:  	/**  	 * Public Cloud API comes down there.  	 * -	 * All Cloud API methods return int32 request id, which might be used to access -	 * request through ConnectionManager. All methods also accept a callback, which -	 * would be called, when request is complete. +	 * All Cloud API methods return Networking::Request *, which +	 * might be used to control request. All methods also accept +	 * a callback, which is called, when request is complete.  	 */  	/** Returns Common::Array<StorageFile>. */ -	virtual int32 listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false) = 0; +	virtual Networking::Request *listDirectory(Common::String path, FileArrayCallback callback, bool recursive = false) = 0;  	/** Calls the callback when finished. */ -	virtual int32 upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) = 0; +	virtual Networking::Request *upload(Common::String path, Common::ReadStream *contents, BoolCallback callback) = 0;  	/** Returns pointer to Networking::NetworkReadStream. */ -	virtual int32 streamFile(Common::String path, ReadStreamCallback callback) = 0; +	virtual Networking::Request *streamFile(Common::String path, Networking::NetworkReadStreamCallback callback) = 0;  	/** Calls the callback when finished. */ -	virtual int32 download(Common::String remotePath, Common::String localPath, BoolCallback callback) = 0; +	virtual Networking::Request *download(Common::String remotePath, Common::String localPath, BoolCallback callback) = 0;  	/** Calls the callback when finished. */ -	virtual int32 remove(Common::String path, BoolCallback callback) = 0; +	virtual Networking::Request *remove(Common::String path, BoolCallback callback) = 0;  	/** Calls the callback when finished. */ -	virtual int32 syncSaves(BoolCallback callback) = 0; +	virtual Networking::Request *syncSaves(BoolCallback callback) = 0;  	/** Calls the callback when finished. */ -	virtual int32 createDirectory(Common::String path, BoolCallback callback) = 0; +	virtual Networking::Request *createDirectory(Common::String path, BoolCallback callback) = 0;  	/** Calls the callback when finished. */ -	virtual int32 touch(Common::String path, BoolCallback callback) = 0; +	virtual Networking::Request *touch(Common::String path, BoolCallback callback) = 0;  	/** Returns the StorageInfo struct. */ -	virtual int32 info(StorageInfoCallback callback) = 0; +	virtual Networking::Request *info(StorageInfoCallback callback) = 0;  	/** Returns whether saves sync process is running. */  	virtual bool isSyncing() = 0; diff --git a/backends/networking/curl/connectionmanager.cpp b/backends/networking/curl/connectionmanager.cpp index 9d88c59b25..ef2afc2655 100644 --- a/backends/networking/curl/connectionmanager.cpp +++ b/backends/networking/curl/connectionmanager.cpp @@ -34,7 +34,7 @@ DECLARE_SINGLETON(Networking::ConnectionManager);  namespace Networking { -ConnectionManager::ConnectionManager(): _multi(0), _timerStarted(false), _nextId(0) { +ConnectionManager::ConnectionManager(): _multi(0), _timerStarted(false) {  	curl_global_init(CURL_GLOBAL_ALL);  	_multi = curl_multi_init();  } @@ -48,16 +48,10 @@ void ConnectionManager::registerEasyHandle(CURL *easy) {  	curl_multi_add_handle(_multi, easy);  } -int32 ConnectionManager::addRequest(Request *request) { -	int32 newId = _nextId++; -	_requests[newId] = RequestInfo(newId, request); -	request->setId(newId); +Request *ConnectionManager::addRequest(Request *request) { +	_requests.push_back(request);  	if (!_timerStarted) startTimer(); -	return newId; -} - -RequestInfo &ConnectionManager::getRequestInfo(int32 id) { -	return _requests[id]; +	return request;  }  //private goes here: @@ -91,36 +85,22 @@ void ConnectionManager::handle() {  void ConnectionManager::interateRequests() {  	//call handle() of all running requests (so they can do their work) -	debug("handling %d request(s)", _requests.size()); -	Common::Array<int32> idsToRemove; -	for (Common::HashMap<int32, RequestInfo>::iterator i = _requests.begin(); i != _requests.end(); ++i) { -		RequestInfo &info = _requests[i->_key]; +	debug("handling %d request(s)", _requests.size());	 +	for (Common::Array<Request *>::iterator i = _requests.begin(); i != _requests.end();) { +		Request *request = *i; +		if (!request || request->state() == FINISHED) { +			delete (*i); +			_requests.erase(i); +			continue; +		} -		switch(info.state) { -		case FINISHED: -			delete info.request; -			info.request = 0; -			idsToRemove.push_back(info.id); -			break; - -		case PROCESSING: -			info.request->handle(); -			break; - -		case RETRY: -			if (info.retryInSeconds > 0) --info.retryInSeconds; -			else { -				info.state = PROCESSING; -				info.request->restart(); -				debug("request restarted"); -			} - -		default: -			; //nothing to do +		if (request) { +			if (request->state() == PROCESSING) request->handle(); +			else if (request->state() == RETRY) request->handleRetry();  		} + +		++i;		  	} -	for (uint32 i = 0; i < idsToRemove.size(); ++i) -		_requests.erase(idsToRemove[i]);  	if (_requests.empty()) stopTimer();  } diff --git a/backends/networking/curl/connectionmanager.h b/backends/networking/curl/connectionmanager.h index 15327a28b2..2d37c0595c 100644 --- a/backends/networking/curl/connectionmanager.h +++ b/backends/networking/curl/connectionmanager.h @@ -36,30 +36,12 @@ namespace Networking {  class NetworkReadStream; -enum RequestState { -	PROCESSING, -	PAUSED, -	RETRY, -	FINISHED -}; - -struct RequestInfo { -	int32 id; -	Request *request; -	RequestState state;	 -	uint32 retryInSeconds; - -	RequestInfo() : id(-1), request(0), state(FINISHED), retryInSeconds(0) {} -	RequestInfo(int32 rqId, Request *rq) : id(rqId), request(rq), state(PROCESSING), retryInSeconds(0) {} -}; -  class ConnectionManager : public Common::Singleton<ConnectionManager> {  	friend void connectionsThread(void *); //calls handle()  	CURLM *_multi;	  	bool _timerStarted; -	Common::HashMap<int32, RequestInfo> _requests; -	int32 _nextId; +	Common::Array<Request *> _requests;	  	void startTimer(int interval = 1000000); //1 second is the default interval  	void stopTimer(); @@ -81,15 +63,15 @@ public:  	/**  	* Use this method to add new Request into manager's queue.  	* Manager will periodically call handle() method of these -	* Requests until they return true. +	* Requests until they set their state to FINISHED. +	* +	* If Request's state is RETRY, handleRetry() is called instead.  	*  	* @note This method starts the timer if it's not started yet.  	* -	* @return generated Request's id, which might be used to get its status +	* @return the same Request pointer, just as a shortcut  	*/ -	int32 addRequest(Request *request);	 - -	RequestInfo &getRequestInfo(int32 id); +	Request *addRequest(Request *request);  };  /** Shortcut for accessing the connection manager. */ diff --git a/backends/networking/curl/curljsonrequest.cpp b/backends/networking/curl/curljsonrequest.cpp index 326d8e27a0..3c598d7f18 100644 --- a/backends/networking/curl/curljsonrequest.cpp +++ b/backends/networking/curl/curljsonrequest.cpp @@ -69,14 +69,11 @@ void CurlJsonRequest::handle() {  			if (_stream->httpResponseCode() != 200)  				warning("HTTP response code is not 200 OK (it's %ld)", _stream->httpResponseCode()); -			ConnMan.getRequestInfo(_id).state = Networking::FINISHED; -			if (_jsonCallback) { -				char *contents = getPreparedContents(); -				if (_stream->httpResponseCode() != 200) -					debug("%s", contents); -				Common::JSONValue *json = Common::JSON::parse(contents); -				(*_jsonCallback)(RequestJsonPair(_id, json)); //potential memory leak, free it in your callbacks! -			} +			char *contents = getPreparedContents(); +			if (_stream->httpResponseCode() != 200) +				debug("%s", contents); +			Common::JSONValue *json = Common::JSON::parse(contents); +			finishJson(json);  		}  	}  } @@ -88,4 +85,14 @@ void CurlJsonRequest::restart() {  	//with no stream available next handle() will create another one  } +void CurlJsonRequest::finishJson(Common::JSONValue *json) { +	Request::finish(); +	if (_jsonCallback) (*_jsonCallback)(JsonResponse(this, json)); //potential memory leak, free it in your callbacks! +	else delete json; +} + +void CurlJsonRequest::finish() { +	finishJson(0); +} +  } //end of namespace Networking diff --git a/backends/networking/curl/curljsonrequest.h b/backends/networking/curl/curljsonrequest.h index 5e78bd1965..0a560f93f4 100644 --- a/backends/networking/curl/curljsonrequest.h +++ b/backends/networking/curl/curljsonrequest.h @@ -29,10 +29,8 @@  namespace Networking { -class NetworkReadStream; - -typedef RequestIdPair<Common::JSONValue*> RequestJsonPair; -typedef Common::BaseCallback<RequestJsonPair> *JsonCallback; +typedef Response<Common::JSONValue *> JsonResponse; +typedef Common::BaseCallback<JsonResponse> *JsonCallback;  class CurlJsonRequest: public CurlRequest {  	JsonCallback _jsonCallback; @@ -41,12 +39,17 @@ class CurlJsonRequest: public CurlRequest {  	/** Prepares raw bytes from _contentsStream to be parsed with Common::JSON::parse(). */  	char *getPreparedContents(); +protected: +	/** Sets FINISHED state and passes the JSONValue * into user's callback in JsonResponse. */ +	virtual void finishJson(Common::JSONValue *json); +  public:  	CurlJsonRequest(JsonCallback cb, Common::String url);  	virtual ~CurlJsonRequest();  	virtual void handle();   	virtual void restart(); +	virtual void finish();  };  }  //end of namespace Networking diff --git a/backends/networking/curl/curlrequest.cpp b/backends/networking/curl/curlrequest.cpp index f01a430b87..a8eb425412 100644 --- a/backends/networking/curl/curlrequest.cpp +++ b/backends/networking/curl/curlrequest.cpp @@ -40,10 +40,10 @@ CurlRequest::~CurlRequest() {  void CurlRequest::handle() {  	if (!_stream) _stream = new NetworkReadStream(_url.c_str(), _headersList, _postFields);	 -	if (_stream && _stream->eos()) {		 +	if (_stream && _stream->eos()) {  		if (_stream->httpResponseCode() != 200)  			warning("HTTP response code is not 200 OK (it's %ld)", _stream->httpResponseCode()); -		ConnMan.getRequestInfo(_id).state = Networking::FINISHED;		 +		finish();  	}  } @@ -71,13 +71,13 @@ void CurlRequest::addPostField(Common::String keyValuePair) {  		_postFields += "&" + keyValuePair;  } -Cloud::Storage::RequestReadStreamPair CurlRequest::execute() { +NetworkReadStreamResponse CurlRequest::execute() {  	if (!_stream) {  		_stream = new NetworkReadStream(_url.c_str(), _headersList, _postFields);  		ConnMan.addRequest(this);  	} -	return Cloud::Storage::RequestReadStreamPair(_id, _stream); +	return NetworkReadStreamResponse(this, _stream);  }  } //end of namespace Networking diff --git a/backends/networking/curl/curlrequest.h b/backends/networking/curl/curlrequest.h index 18a41a1c06..5677720b1d 100644 --- a/backends/networking/curl/curlrequest.h +++ b/backends/networking/curl/curlrequest.h @@ -24,7 +24,6 @@  #define BACKENDS_NETWORKING_CURL_CURLREQUEST_H  #include "backends/networking/curl/request.h" -#include "backends/cloud/storage.h"  #include "common/str.h"  #include "common/array.h" @@ -34,6 +33,9 @@ namespace Networking {  class NetworkReadStream; +typedef Response<NetworkReadStream *> NetworkReadStreamResponse; +typedef Common::BaseCallback<NetworkReadStreamResponse> *NetworkReadStreamCallback; +  class CurlRequest: public Request {  protected:  	Common::String _url; @@ -48,12 +50,20 @@ public:  	virtual void handle();  	virtual void restart(); +	/** Replaces all headers with the passed array of headers. */  	virtual void setHeaders(Common::Array<Common::String> &headers); + +	/** Adds a header into headers list. */  	virtual void addHeader(Common::String header); + +	/** Adds a post field (key=value pair). */  	virtual void addPostField(Common::String field); -	/** Start this Request with ConnMan. Returns its ReadStream and request id. */ -	virtual Cloud::Storage::RequestReadStreamPair execute(); +	/** +	* Starts this Request with ConnMan. +	* @return its NetworkReadStream in NetworkReadStreamResponse. +	*/ +	virtual NetworkReadStreamResponse execute();  };  }  //end of namespace Networking diff --git a/backends/networking/curl/networkreadstream.h b/backends/networking/curl/networkreadstream.h index 6431a01fee..a0c87460cb 100644 --- a/backends/networking/curl/networkreadstream.h +++ b/backends/networking/curl/networkreadstream.h @@ -83,6 +83,6 @@ public:  	long httpResponseCode();  }; -} //end of namespace Cloud +} //end of namespace Networking  #endif diff --git a/backends/networking/curl/request.h b/backends/networking/curl/request.h index d81fe903b8..ff919e02f1 100644 --- a/backends/networking/curl/request.h +++ b/backends/networking/curl/request.h @@ -28,40 +28,124 @@  namespace Networking { -template<typename T> struct RequestIdPair { -	int32 id; +class Request; + +/** +* Response<T> is a struct to be returned from Request +* to user's callbacks. It's a type safe way to indicate +* which "return value" Request has and user awaits. +* +* It just keeps a Request pointer together with +* some T value (which might be a pointer, a reference +* or a plain type (copied by value)). +* +* To make it more convenient, typedefs are used. +* For example, Response<void *> is called DataResponse +* and corresponding callback pointer is DataCallback. +*/ + +template<typename T> struct Response { +	Request *request;  	T value; -	RequestIdPair(int32 rid, T v) : id(rid), value(v) {} +	Response(Request *rq, T v) : request(rq), value(v) {}  }; -typedef RequestIdPair<void *> RequestDataPair; -typedef Common::BaseCallback<RequestDataPair> *DataCallback; +typedef Response<void *> DataReponse; +typedef Common::BaseCallback<DataReponse> *DataCallback; + +/** +* RequestState is used to indicate current Request state. +* ConnectionManager uses it to decide what to do with the Request. +* +* PROCESSING state indicates that Request is working. +* ConnectionManager calls handle() method of Requests in that state. +* +* PAUSED state indicates that Request is not working. +* ConnectionManager keeps Requests in that state and doesn't call any methods of those. +* +* RETRY state indicates that Request must restart after a few seconds. +* ConnectionManager calls handleRetry() method of Requests in that state. +* Default handleRetry() implementation decreases _retryInSeconds value +* until it reaches zero. When it does, Request's restart() method is called. +* +* FINISHED state indicates that Request did the work and might be deleted. +* ConnectionManager deletes Requests in that state. +* After this state is set, but before ConnectionManager deletes the Request, +* Request calls user's callback. User can ask Request to change its state +* by calling retry() or pause() methods and Request won't be deleted. +*/ + +enum RequestState { +	PROCESSING, +	PAUSED, +	RETRY, +	FINISHED +};  class Request {  protected:  	/** -	* Callback, which should be called before Request returns true in handle(). +	* Callback, which should be called when Request is finished.  	* That's the way Requests pass the result to the code which asked to create this request. +	* +	* @note some Requests use their own callbacks to return something but void *. +	* @note callback must be called in finish() or similar method.  	*/  	DataCallback _callback; -	int32 _id; +	/** +	* Request state, which is used by ConnectionManager to determine +	* whether request might be deleted or it's still working. +	* +	* State might be changed from outside with finish(), pause() or +	* retry() methods. Override these if you want to react to these +	* changes correctly. +	*/ + +	RequestState _state; + +	/** In RETRY state this indicates whether it's time to call restart(). */ +	uint32 _retryInSeconds;  public: -	Request(DataCallback cb): _callback(cb), _id(-1) {} +	Request(DataCallback cb): _callback(cb), _state(PROCESSING), _retryInSeconds(0) {}  	virtual ~Request() { delete _callback; } -	/** -	* Method, which does actual work. Depends on what this Request is doing. -	*/ - +	/** Method, which does actual work. Depends on what this Request is doing. */  	virtual void handle() = 0; +	/** Method, which is called by ConnectionManager when Request's state is RETRY.	 */ +	virtual void handleRetry() { +		if (_retryInSeconds > 0) --_retryInSeconds; +		else { +			_state = PROCESSING; +			restart(); +		} +	} + +	/** Method, which is used to restart the Request. */  	virtual void restart() = 0; -	void setId(int32 id) { _id = id; } +	/** Method, which is called to pause the Request. */ +	virtual void pause() { _state = PAUSED; } + +	/** +	* Method, which is called to *interrupt* the Request. +	* When it's called, Request must stop its work and +	* call the callback to notify user of failure. +	*/ +	virtual void finish() { _state = FINISHED; } + +	/** Method, which is called to retry the Request. */ +	virtual void retry(uint32 seconds) {		 +		_state = RETRY; +		_retryInSeconds = seconds; +	} + +	/** Returns Request's current state. */ +	RequestState state() const { return _state; }  };  } //end of namespace Cloud | 
