Permalink
Browse files

Merge branch 'master' of github.com:massix/grive

  • Loading branch information...
Massimo Gengarelli
Massimo Gengarelli committed Apr 28, 2012
2 parents 867d1c3 + f4ee21f commit 93e2a9df2f5d28b47abf101d799def7b9f19feec
View
@@ -16,6 +16,7 @@ add_executable( grive
src/protocol/HTTP.cc
src/protocol/Json.cc
src/protocol/OAuth2.cc
+ src/util/Crypt.cc
src/util/DateTime.cc
src/util/OS.cc
)
@@ -30,6 +31,7 @@ add_executable( unittest
test/UnitTest.cc
src/util/DateTime.cc
test/util/DateTimeTest.cc
+ test/util/FunctionTest.cc
)
target_link_libraries( unittest
View
@@ -82,6 +82,11 @@ void Collection::AddChild( Collection *child )
m_child.push_back( child ) ;
}
+void Collection::AddLeaf( const std::string& filename )
+{
+ m_leaves.push_back( filename ) ;
+}
+
bool Collection::IsCollection( const Json& entry )
{
Json node ;
@@ -96,12 +101,12 @@ void Collection::Swap( Collection& coll )
m_href.swap( coll.m_href ) ;
std::swap( m_parent, coll.m_parent ) ;
m_child.swap( coll.m_child ) ;
+ m_leaves.swap( coll.m_leaves ) ;
}
void Collection::CreateSubDir( const std::string& prefix )
{
std::string dir = prefix + m_title ;
-// mkdir( dir.c_str(), 0700 ) ;
os::MakeDir( dir ) ;
for ( std::vector<Collection*>::iterator i = m_child.begin() ; i != m_child.end() ; ++i )
@@ -111,6 +116,12 @@ void Collection::CreateSubDir( const std::string& prefix )
}
}
+void Collection::ForEachFile(
+ Function<void(const std::string&)> callback,
+ const std::string& prefix )
+{
+}
+
std::string Collection::Path() const
{
assert( m_parent != this ) ;
View
@@ -19,6 +19,8 @@
#pragma once
+#include "util/Function.hh"
+
#include <string>
#include <vector>
@@ -44,10 +46,15 @@ public :
std::string Path() const ;
void AddChild( Collection *child ) ;
+ void AddLeaf( const std::string& filename ) ;
void Swap( Collection& coll ) ;
- void CreateSubDir( const std::string& prefix ) ;
+ // traversing the tree
+ void CreateSubDir( const std::string& prefix = "." ) ;
+ void ForEachFile(
+ Function<void(const std::string&)> callback,
+ const std::string& prefix = "." ) ;
private :
std::string m_title ;
@@ -56,6 +63,8 @@ private :
// not owned
Collection *m_parent ;
std::vector<Collection*> m_child ;
+
+ std::vector<std::string> m_leaves ;
} ;
} // end of namespace
View
@@ -22,19 +22,15 @@
#include "protocol/HTTP.hh"
#include "protocol/Json.hh"
#include "protocol/OAuth2.hh"
+#include "util/Crypt.hh"
#include "util/DateTime.hh"
#include "util/OS.hh"
-// dependent libraries
-#include <openssl/evp.h>
-
// standard C++ library
#include <algorithm>
#include <cassert>
#include <fstream>
-#include <iomanip>
#include <map>
-#include <sstream>
// for debugging only
#include <iostream>
@@ -43,30 +39,6 @@ namespace gr {
const std::string root_url = "https://docs.google.com/feeds/default/private/full" ;
-std::string MD5( std::streambuf *file )
-{
- char buf[64 * 1024] ;
- EVP_MD_CTX md ;
- EVP_MD_CTX_init( &md );
- EVP_DigestInit_ex( &md, EVP_md5(), 0 ) ;
-
- std::size_t count = 0 ;
- while ( (count = file->sgetn( buf, sizeof(buf) )) > 0 )
- {
- EVP_DigestUpdate( &md, buf, count ) ;
- }
-
- unsigned int md5_size = EVP_MAX_MD_SIZE ;
- unsigned char md5[EVP_MAX_MD_SIZE] ;
- EVP_DigestFinal_ex( &md, md5, &md5_size ) ;
-
- std::ostringstream ss ;
- for ( unsigned int i = 0 ; i < md5_size ; i++ )
- ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(md5[i]) ;
-
- return ss.str() ;
-}
-
Drive::Drive( OAuth2& auth ) :
m_auth( auth ),
m_root( ".", "https://docs.google.com/feeds/default/private/full/folder%3Aroot" )
@@ -75,7 +47,7 @@ Drive::Drive( OAuth2& auth ) :
m_http_hdr.push_back( "GData-Version: 3.0" ) ;
- Json resp = Json::Parse(HttpGet( root_url + "?alt=json&showfolders=true", m_http_hdr )) ;
+ Json resp = Json::Parse( http::Get( root_url + "?alt=json&showfolders=true", m_http_hdr )) ;
Json::Array entries = resp["feed"]["entry"].As<Json::Array>() ;
ConstructDirTree( entries ) ;
@@ -182,11 +154,9 @@ void Drive::UpdateFile( const Json& entry )
if ( entry.Has( "docs$filename" ) )
{
// use title as the filename
- std::string filename = entry["docs$filename"]["$t"].As() ;
- std::string url = entry["content"]["src"].As() ;
+ std::string filename = entry["docs$filename"]["$t"].Get() ;
+ std::string url = entry["content"]["src"].Get() ;
std::string parent_href = Parent( entry ) ;
-
- DateTime remote( entry["updated"]["$t"].As<std::string>() ) ;
bool changed = true ;
std::string path = "./" + filename ;
@@ -198,31 +168,54 @@ void Drive::UpdateFile( const Json& entry )
if ( pit != m_coll.end() )
path = pit->Path() + "/" + filename ;
}
- DateTime local = os::FileMTime( path ) ;
- std::cout << "file time: " << entry["updated"]["$t"].As<std::string>() << " " << remote << " " << local << std::endl ;
+// std::cout << "file time: " << entry["updated"]["$t"].As<std::string>() << " " << remote << " " << local << std::endl ;
// compare checksum first if file exists
std::ifstream ifile( path.c_str(), std::ios::binary | std::ios::out ) ;
if ( ifile && entry.Has("docs$md5Checksum") )
{
- os::SetFileTime( path, remote ) ;
-
std::string remote_md5 = entry["docs$md5Checksum"]["$t"].As<std::string>() ;
- std::string local_md5 = MD5( ifile.rdbuf() ) ;
+ std::string local_md5 = crypt::MD5( ifile.rdbuf() ) ;
std::transform( remote_md5.begin(), remote_md5.end(), remote_md5.begin(), tolower ) ;
if ( local_md5 == remote_md5 )
changed = false ;
}
- // if the checksum is different, file is changed and we need to download
+ // if the checksum is different, file is changed and we need to update
if ( changed )
{
+ DateTime remote( entry["updated"]["$t"].As<std::string>() ) ;
+ DateTime local = ifile ? os::FileMTime( path ) : DateTime() ;
+
+ // remote file is newer, download file
+ if ( remote > local )
+ {
std::cout << "downloading " << path << std::endl ;
- HttpGetFile( url, path, m_http_hdr ) ;
+ http::GetFile( url, path, m_http_hdr ) ;
+ os::SetFileTime( path, remote ) ;
+ }
+ else
+ {
+std::cout << "local " << filename << " is newer" << std::endl ;
+ UploadFile( entry ) ;
+ }
}
}
}
+void Drive::UploadFile( const Json& entry )
+{
+// std::cout << "entry:\n" << entry << std::endl ;
+
+ Json resume_link = entry["link"].FindInArray( "rel",
+ "http://schemas.google.com/g/2005#resumable-edit-media" )["href"] ;
+ std::cout << resume_link.As<std::string>() << std::endl ;
+
+ std::string resp = http::Put( resume_link.Get(), "", m_http_hdr ) ;
+
+ std::cout << "resp " << resp ;
+}
+
} // end of namespace
View
@@ -41,6 +41,7 @@ public :
private :
void UpdateFile( const Json& entry ) ;
+ void UploadFile( const Json& entry ) ;
std::string Parent( const Json& entry ) ;
void ConstructDirTree( const std::vector<Json>& entries ) ;
View
@@ -24,24 +24,16 @@
// dependent libraries
#include <curl/curl.h>
+#include <algorithm>
#include <cassert>
+#include <cstring>
#include <iostream>
#include <sstream>
#include <streambuf>
-namespace gr {
+namespace {
-HttpException::HttpException( int curl_code, int http_code, const char *err_buf )
- : runtime_error( Format( curl_code, http_code, err_buf ) )
-{
-}
-
-std::string HttpException::Format( int curl_code, int http_code, const char *err_buf )
-{
- std::ostringstream ss ;
- ss << "CURL code = " << curl_code << " HTTP code = " << http_code << " (" << err_buf << ")" ;
- return ss.str() ;
-}
+using namespace gr::http ;
// libcurl callback to append to a string
std::size_t WriteCallback( char *data, size_t size, size_t nmemb, std::string *resp )
@@ -54,6 +46,20 @@ std::size_t WriteCallback( char *data, size_t size, size_t nmemb, std::string *r
return count ;
}
+size_t ReadCallback( void *ptr, std::size_t size, std::size_t nmemb, std::string *data )
+{
+ assert( ptr != 0 ) ;
+ assert( data != 0 ) ;
+
+ std::size_t count = std::min( size * nmemb, data->size() ) ;
+ if ( count > 0 )
+ {
+ std::memcpy( &(*data)[0], ptr, count ) ;
+ data->erase( 0, count ) ;
+ }
+ return count ;
+}
+
CURL* InitCurl( const std::string& url, std::string *resp, const Headers& hdr )
{
CURL *curl = curl_easy_init();
@@ -93,16 +99,32 @@ void DoCurl( CURL *curl )
if ( curl_code != CURLE_OK )
{
- throw HttpException( curl_code, http_code, error_buf ) ;
+ throw Exception( curl_code, http_code, error_buf ) ;
}
else if (http_code >= 400 )
{
std::cout << "http error " << http_code << std::endl ;
- throw HttpException( curl_code, http_code, error_buf ) ;
+ throw Exception( curl_code, http_code, error_buf ) ;
}
}
-std::string HttpGet( const std::string& url, const Headers& hdr )
+} // end of local namespace
+
+namespace gr { namespace http {
+
+Exception::Exception( int curl_code, int http_code, const char *err_buf )
+ : runtime_error( Format( curl_code, http_code, err_buf ) )
+{
+}
+
+std::string Exception::Format( int curl_code, int http_code, const char *err_buf )
+{
+ std::ostringstream ss ;
+ ss << "CURL code = " << curl_code << " HTTP code = " << http_code << " (" << err_buf << ")" ;
+ return ss.str() ;
+}
+
+std::string Get( const std::string& url, const Headers& hdr )
{
std::string resp ;
CURL *curl = InitCurl( url, &resp, hdr ) ;
@@ -111,7 +133,7 @@ std::string HttpGet( const std::string& url, const Headers& hdr )
return resp;
}
-void HttpGetFile(
+void GetFile(
const std::string& url,
const std::string& filename,
const Headers& hdr )
@@ -125,15 +147,15 @@ void HttpGetFile(
DoCurl( curl ) ;
}
-void HttpGetFile(
+void GetFile(
const std::string& url,
const std::string& filename,
std::string& md5sum,
const Headers& hdr )
{
}
-std::string HttpPostData( const std::string& url, const std::string& data, const Headers& hdr )
+std::string PostData( const std::string& url, const std::string& data, const Headers& hdr )
{
std::string resp ;
CURL *curl = InitCurl( url, &resp, hdr ) ;
@@ -148,9 +170,28 @@ std::string HttpPostData( const std::string& url, const std::string& data, const
return resp;
}
-std::string HttpPostFile( const std::string& url, const std::string& filename, const Headers& hdr )
+std::string PostFile( const std::string& url, const std::string& filename, const Headers& hdr )
+{
+ std::string resp ;
+ return resp;
+}
+
+std::string Put(
+ const std::string& url,
+ const std::string& data,
+ const Headers& hdr )
{
std::string resp ;
+ CURL *curl = InitCurl( url, &resp, hdr ) ;
+
+ std::string put_data = data ;
+
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, &ReadCallback ) ;
+ curl_easy_setopt(curl, CURLOPT_READDATA , &put_data ) ;
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, put_data.size() ) ;
+
+ DoCurl( curl ) ;
return resp;
}
@@ -181,4 +222,4 @@ std::string Unescape( const std::string& str )
return result ;
}
-}
+} } // end of namespace
Oops, something went wrong.

0 comments on commit 93e2a9d

Please sign in to comment.