Files
scandocs/uni/masterarbeit/source/moversight/mob/sync/cloud/provider/DropBoxProvider.cc
2014-06-30 13:58:10 +02:00

478 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* File: DropBoxProvider.cc
* Author: jgaebler
*
* Created on April 26, 2012, 3:27 PM
*/
#include "DropBoxProvider.h"
#include "Dispatcher.h"
#include "common/container/PeerIDList.h"
#include "common/time/GenericTime.h"
#include "mob/sync/cloud/transfer/TransferContainer.h"
#include "mob/sync/cloud/transfer/TransferMessage.h"
#include "mob/sync/cloud/transfer/TransferSerializer.h"
#include "common/util/StringUtil.h"
#include "common/container/StringList.h"
#if OMNETPP
#include "../../opt/json-c-0.10/include/json/json.h"
#include <oauth.h>
#include <curl/curl.h>
#endif
#include "Moversight.h"
#include <ctime>
#include <stdlib.h>
#undef DEBUG
#define DEBUG(msg) if (module.isPrintDebugDIS()) MOV_DEBUG << "DBP@" << dispatcher.getMembershipService().getLocalID()<< " "<<msg<<endl;
namespace ubeeme {
namespace moversight {
//Dropbox API and OAuth-Keys
const std::string DropBoxProvider::APP_KEY = "bv3uv5q2t9qbqse";
const std::string DropBoxProvider::APP_SECRET = "wbo2ieyzvvejrpz";
// oauth_token and oauth_token_secret created by the scripted gettoken.py
const std::string DropBoxProvider::OAUTH_TOKEN_SECRET = "negr39cwhxsuc4z";
const std::string DropBoxProvider::OAUTH_TOKEN = "jhht95nex1gpapz";
const std::string DropBoxProvider::META_DATA_FILE_NAME_PREFIX = "globalmetadata";
const std::string DropBoxProvider::FILE_TYPE = "dat";
/**
* @brief Constructor
* @param dis A reference to the dispatcher
* @param mov A reference to the moversight module
*/
DropBoxProvider::DropBoxProvider(Dispatcher & dis, Moversight & mov) : CloudProvider(dis, mov), counter(0) {
}
/**
* @brief Destructor
*/
DropBoxProvider::~DropBoxProvider() {
}
/**
* @brief Puts the given data into the cloud.
* @param uploadData The data to upload.
* @param uPID The id of the uploading peer.
* @param fileName The name of the file that stores the data.
*/
void
DropBoxProvider::upload(ByteArray & uploadData, PeerID uPID, std::string fileName) {
#if OMNETPP
if (uploadData.size() > 0) {
//std::cerr<< "upload - file name " << fileName<<endl;
std::string url = buildUploadUrl(uPID, fileName);
//@TOOD find a better solution
const char * postData = reinterpret_cast<const char*> (&uploadData[0]);
char * reply;
reply = oauth_post_data(url.c_str(),
postData,
uploadData.size(),
"Content-Type: application/json");
//@TODO check reply for errors and propaged it
//std::cout << "reply: " << reply << std::endl;
if (reply) free(reply);
}//End if
#endif
}
/**
* @brief Creates the url for the file upload to dropbox
* @param id The id of the peer which has created the first folder in the dropbox.
* @param fileName The name of the file to store
* @return The build url.
*/
std::string
DropBoxProvider::buildUploadUrl(PeerID id, std::string fileName) {
std::string s_time = StringUtil::int2String(std::time(NULL));
std::string folder = StringUtil::int2String(id);
#if OMNETPP
char * nonce = oauth_gen_nonce();
// Building Upload url
std::string url = "https://api-content.dropbox.com/1/files_put/sandbox/" + folder;
url += "/" + fileName + "." + FILE_TYPE;
std::string a(url);
a += "?oauth_nonce=" + std::string(nonce) + "?overwrite=false";
a += "&oauth_timestamp=" + s_time + "&oauth_consumer_key=" + APP_KEY;
a += "&oauth_signature_method=PLAINTEXT&oauth_version=1.0&oauth_token=" + OAUTH_TOKEN;
a += "&oauth_signature=" + APP_SECRET + "%26" + OAUTH_TOKEN_SECRET; // + "&overwrite=False";
if (nonce) free(nonce);
//char* signedUrl = oauth_sign_url2(url.c_str(), //request url
// NULL, //post arguments
// OA_HMAC, //oauth method OA_HMAC
// NULL, //http method (GET or POST), if NULL - auto detection
// APP_KEY.c_str(), //c_key
// APP_SECRET.c_str(), //c_secret
// OAUTH_TOKEN.c_str(), // t_key
// OAUTH_TOKEN_SECRET.c_str()); //t_secret
//std::cout << "UPLOAD URL: " << url << std::endl;
//std::cout << "SIGNED URL: " << signedUrl << std::endl;
//std::cout << "EXPECTED URL: "<< a <<std::endl;
//std::string t(signedUrl);
//free(signedUrl);
return a;
#else
return folder;
#endif
}
TransferContainerList
DropBoxProvider::downloadMessagesFromPeer(PeerID id) {
std::stringstream buf;
buf << "downloadMessagesFromPeer - peer " << id;
DEBUG(buf.str().c_str());
std::string metaDataUrl = buildMetaDataUrl(id);
TransferContainerList tcl;
#if OMNETPP
char * metaReply = oauth_http_get(metaDataUrl.c_str(), NULL);
if (metaReply != NULL) {
//extract the fileList from the reply
StringList filePathList;
StringList fileSizeList;
const std::string pathKey("path");
const std::string sizeKey("bytes");
json_object * jobj = json_tokener_parse(metaReply);
jsonParse(jobj, false, filePathList, pathKey.c_str());
jsonParse(jobj, false, fileSizeList, sizeKey.c_str());
//free the reply
free(metaReply);
//check, if the size of both lists equal
if (filePathList.size() != fileSizeList.size()) {
DEBUG("downloadMessagesFromPeer - error: the size of the retrieved path and file size lists are not consistent");
filePathList.clear();
}//End if
//retrieve the files
//skip paths, which consists only of the peer folder itself (the first entry)
//TODO FIX DOWNLOAD LIMIT (TO AVOID LONG DOWNLOADS)
std::cerr<<"DropBoxProvider: limit download to 4 files"<<endl;
for (size_t i = 1; i < filePathList.size() && i < 5; i++) {
DEBUG("retrieve from cloud: " + filePathList.get(i));
std::string fileUrl = buildDownloadUrl(filePathList.get(i));
struct MemoryStruct ms = performCurlDownload(fileUrl);
if (ms.size > 0) {
ByteArray loadedFile(ms.memory, ms.memory + ms.size);
TransferContainer tc;
tc.setPeerID(id);
if (TransferSerializer::deserialize(loadedFile, tc)) {
tcl.add(tc);
}//End if
else {
DEBUG("downloadMessagesFromPeer - error: de-serialize retrieved data failed.");
}//End else
//clean up
free(ms.memory);
}//End if
else {
DEBUG("downloadMessagesFromPeer - error: download failed.");
}//End else
}//End for
}//End if metaReply
#endif
return tcl;
}
/**
* @brief Determine the peers, which have stored messages in the cloud.
* @return The list of peers that have stored messages in the cloud.
*/
PeerIDList
DropBoxProvider::determineStoringPeers() {
// the dropbox api response with an json array
// the array is parsed with the json parser
// create the url for the metadata download
std::string mdurl = buildMetaDataUrl();
PeerIDList idList;
#if OMNETPP
char * reply = oauth_http_get(mdurl.c_str(), NULL);
if (reply != NULL) {
//list of peers which have stored messages in the cloud, filled by the json parser
StringList peerList;
std::string pathKey("path");
json_object * jobj = json_tokener_parse(reply);
//false
jsonParse(jobj, true, peerList, pathKey.c_str());
//have a peer messages stored in the cloud?
for (size_t i = 0; i < peerList.size(); i++) {
//we have at least one peer, which have stored messages in the cloud
//load the string of the peer ID
std::string client = peerList.get(i);
if (client != "") {
//convert the ID and store it in the list
idList.add(PeerID(atoi(client.c_str())));
}//End if
}//end while
free(jobj);
free(reply);
}//End if
#endif
return idList;
}
/*
* @brief The json array parser
* @note See joysofprogramming.com/json-c-libjson-tutorial/ for the
* source of the original code
*/
void
DropBoxProvider::jsonParseArray(json_object *jobj, char *key, bool parse, StringList & list, const char * param /* = "path" */) {
#if OMNETPP
enum json_type type;
//Simply get the array
json_object *jarray = jobj;
if (key) {
//Getting the array if it is a key value pair
jarray = json_object_object_get(jobj, key);
}
//Getting the length of the array
int arraylen = json_object_array_length(jarray);
int i;
json_object * jvalue;
for (i = 0; i < arraylen; i++) {
//Getting the array element at position i
jvalue = json_object_array_get_idx(jarray, i);
type = json_object_get_type(jvalue);
if (type == json_type_array) {
jsonParseArray(jvalue, NULL, false, list, param);
}
else {
jsonParse(jvalue, parse, list, param);
}
}
#endif
}
/*
* @brief The json object parser
* @note base on joysofprogramming.com/json-c-libjson-tutorial/
*
* @param jobj The object to parse
* @param parse Enable parsing
* @param param The parameter to parse
* @param list The list of the resulting tokens, with match to the key
* "path" within the JSON response
*/
void
DropBoxProvider::jsonParse(json_object * jobj, bool /* parse */, StringList & list, const char * param /* = "path" */) {
#if OMNETPP
enum json_type type;
//Passing through every array element
json_object_object_foreach(jobj, key, val) {
type = json_object_get_type(val);
switch (type) {
case json_type_string:
if (strcmp(key, param) == 0) {
std::string client = json_object_get_string(val);
list.add(client.substr(1));
}
break;
case json_type_array:
if (strcmp(key, "contents") == 0) {
jsonParseArray(jobj, key, true, list, param);
}
break;
case json_type_int:
if (strcmp(key, param) == 0) {
int intVal = json_object_get_int(val);
list.add(StringUtil::int2String(intVal));
}
default:
{
//json_type_boolean
//json_type_double
//json_type_object
}
}
}
#endif
}
/*
* @brief Creates the url for requesting the meta data for the path "path"
* @return The build url.
*/
std::string
DropBoxProvider::buildMetaDataUrl() {
return buildMetaDataUrl(UNDEFINED_PEER_ID);
}
/*
* @brief Creates the url for requesting the meta data for the given peer
* ID. If the id equals to UNDEFINED_PEER_ID, the path is set to empty;
* @param id The id of the uploading peer.
* @return The build url.
*/
std::string
DropBoxProvider::buildMetaDataUrl(PeerID id) {
std::string path;
if (id != UNDEFINED_PEER_ID) {
path = path + StringUtil::int2String(id) + "/";
}
return buildMetaDataUrl(path);
}
/*
* @brief Creates the url for requesting the meta data for the path.
* @param path The path to set
* @return The build url.
*/
std::string
DropBoxProvider::buildMetaDataUrl(std::string path) {
#if OMNETPP
char * nonce = oauth_gen_nonce();
std::string url = "https://api.dropbox.com/1/metadata/sandbox/" + path + "?oauth_nonce="
+ std::string(nonce) + "&oauth_timestamp=" + StringUtil::int2String(std::time(NULL)) + "&file_limit=10000&list=true"
+ "&oauth_consumer_key=" + APP_KEY + "&oauth_signature_method=PLAINTEXT&include_deleted=False&oauth_version=1.0&"
+ "&oauth_token=" + OAUTH_TOKEN + "&oauth_signature=" + APP_SECRET + "%26" + OAUTH_TOKEN_SECRET;
free(nonce);
return url;
#else
return "https://no.url.com";
#endif
}
/**
* @brief Creates the url for the file download from the dropbox.
* @param path The path to the file to download.
* @return The build url.
*/
std::string
DropBoxProvider::buildDownloadUrl(std::string path) {
int random = (rand() % 99999999 + 1) + 10000000;
std::string url = "https://api-content.dropbox.com/1/files/sandbox/" + path + "?oauth_nonce="
+ StringUtil::int2String(random) + "&oauth_timestamp=" + StringUtil::int2String(std::time(NULL))
+ "&oauth_consumer_key=" + APP_KEY + "&oauth_signature_method=PLAINTEXT&oauth_version=1.0&"
+ "&oauth_token=" + OAUTH_TOKEN + "&oauth_signature=" + APP_SECRET + "%26" + OAUTH_TOKEN_SECRET;
return url;
}
/**
* @brief Retrieves a curl fetch operation and returns a chunk of memory,
* which stores the retrieved file.
* @param url The url of the message to fetch
* @return The memory struct, which stores the retrieved file content.
* @note The memory of the MemoryStruct chunk have to be cleaned by the caller
* @see http://curl.haxx.se/libcurl/c/getinmemory.html
*/
struct MemoryStruct
DropBoxProvider::performCurlDownload(std::string url) {
//init the memory area to store the meta data
MemoryStruct chunk;
chunk.memory = (char*) malloc(1);
chunk.size = 0;
#if OMNETPP
//build the curl request for the metadata upload
//and perform the request
CURL* curl_handle;
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeMemoryCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &chunk);
curl_easy_perform(curl_handle);
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
#endif
return chunk;
}
/**
* @brief Callback for the curl library downloads
* @param contents The content to store
* @param size the size of the fetched content
* @param nmemb the size of the allocated memory
* @param userp the destination to store
* @return the value of the allocated memory
* @see http://curl.haxx.se/libcurl/c/getinmemory.html
*/
size_t
DropBoxProvider::writeMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
MemoryStruct *mem = (MemoryStruct *) userp;
mem->memory = (char*) realloc(mem->memory, mem->size + realsize + 1);
if (mem->memory == NULL) {
// out of memory!
std::cerr << "not enough memory (realloc returned NULL)" << std::endl;
exit(EXIT_FAILURE);
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
}
}