update20140630
This commit is contained in:
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user