mirror of https://github.com/vitalif/grive2
Move all protocol interaction into Syncers out of the base code
parent
717a6a4793
commit
862fca035a
|
@ -19,7 +19,8 @@
|
|||
|
||||
#include "util/Config.hh"
|
||||
|
||||
#include "drive/Drive.hh"
|
||||
#include "base/Drive.hh"
|
||||
#include "drive/Syncer1.hh"
|
||||
|
||||
#include "http/CurlAgent.hh"
|
||||
#include "protocol/AuthAgent.hh"
|
||||
|
@ -185,8 +186,9 @@ int Main( int argc, char **argv )
|
|||
|
||||
OAuth2 token( refresh_token, client_id, client_secret ) ;
|
||||
AuthAgent agent( token, std::auto_ptr<http::Agent>( new http::CurlAgent ) ) ;
|
||||
Syncer1 syncer( &agent );
|
||||
|
||||
Drive drive( &agent, config.GetAll() ) ;
|
||||
Drive drive( &syncer, config.GetAll() ) ;
|
||||
drive.DetectChanges() ;
|
||||
|
||||
if ( vm.count( "dry-run" ) == 0 )
|
||||
|
|
|
@ -19,18 +19,13 @@
|
|||
|
||||
#include "Drive.hh"
|
||||
|
||||
#include "CommonUri.hh"
|
||||
#include "base/Entry.hh"
|
||||
#include "Entry.hh"
|
||||
#include "Feed.hh"
|
||||
#include "Syncer1.hh"
|
||||
#include "Syncer.hh"
|
||||
|
||||
#include "http/Agent.hh"
|
||||
#include "http/ResponseLog.hh"
|
||||
#include "http/XmlResponse.hh"
|
||||
#include "util/Destroy.hh"
|
||||
#include "util/log/Log.hh"
|
||||
#include "xml/Node.hh"
|
||||
#include "xml/NodeSet.hh"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
|
@ -45,20 +40,20 @@
|
|||
// for debugging only
|
||||
#include <iostream>
|
||||
|
||||
namespace gr { namespace v1 {
|
||||
namespace gr {
|
||||
|
||||
namespace
|
||||
{
|
||||
const std::string state_file = ".grive_state" ;
|
||||
}
|
||||
|
||||
Drive::Drive( http::Agent *agent, const Val& options ) :
|
||||
m_http ( agent ),
|
||||
Drive::Drive( Syncer *syncer, const Val& options ) :
|
||||
m_syncer ( syncer ),
|
||||
m_root ( options["path"].Str() ),
|
||||
m_state ( m_root / state_file, options ),
|
||||
m_options ( options )
|
||||
{
|
||||
assert( m_http != 0 ) ;
|
||||
assert( m_syncer ) ;
|
||||
}
|
||||
|
||||
void Drive::FromRemote( const Entry& entry )
|
||||
|
@ -95,16 +90,13 @@ void Drive::SaveState()
|
|||
|
||||
void Drive::SyncFolders( )
|
||||
{
|
||||
assert( m_http != 0 ) ;
|
||||
|
||||
Log( "Synchronizing folders", log::info ) ;
|
||||
|
||||
Feed feed ;
|
||||
feed.Start( m_http, feed_base + "/-/folder?max-results=50&showroot=true" ) ;
|
||||
do
|
||||
std::auto_ptr<Feed> feed = m_syncer->GetFolders() ;
|
||||
while ( feed->GetNext( m_syncer->Agent() ) )
|
||||
{
|
||||
// first, get all collections from the query result
|
||||
for ( Feed::iterator i = feed.begin() ; i != feed.end() ; ++i )
|
||||
for ( Feed::iterator i = feed->begin() ; i != feed->end() ; ++i )
|
||||
{
|
||||
const Entry &e = *i ;
|
||||
if ( e.IsDir() )
|
||||
|
@ -119,7 +111,7 @@ void Drive::SyncFolders( )
|
|||
m_state.FromRemote( e ) ;
|
||||
}
|
||||
}
|
||||
} while ( feed.GetNext( m_http ) ) ;
|
||||
}
|
||||
|
||||
m_state.ResolveEntry() ;
|
||||
}
|
||||
|
@ -135,42 +127,38 @@ void Drive::DetectChanges()
|
|||
SyncFolders( ) ;
|
||||
|
||||
Log( "Reading remote server file list", log::info ) ;
|
||||
Feed feed ;
|
||||
std::auto_ptr<Feed> feed = m_syncer->GetAll() ;
|
||||
|
||||
if ( m_options["log-xml"].Bool() )
|
||||
feed.EnableLog( "/tmp/file", ".xml" ) ;
|
||||
feed->EnableLog( "/tmp/file", ".xml" ) ;
|
||||
|
||||
feed.Start( m_http, feed_base + "?showfolders=true&showroot=true" ) ;
|
||||
|
||||
do
|
||||
while ( feed->GetNext( m_syncer->Agent() ) )
|
||||
{
|
||||
std::for_each(
|
||||
feed.begin(), feed.end(),
|
||||
feed->begin(), feed->end(),
|
||||
boost::bind( &Drive::FromRemote, this, _1 ) ) ;
|
||||
|
||||
} while ( feed.GetNext( m_http ) ) ;
|
||||
}
|
||||
|
||||
// pull the changes feed
|
||||
if ( prev_stamp != -1 )
|
||||
{
|
||||
Log( "Detecting changes from last sync", log::info ) ;
|
||||
Feed changes ;
|
||||
feed = m_syncer->GetChanges( prev_stamp+1 ) ;
|
||||
if ( m_options["log-xml"].Bool() )
|
||||
feed.EnableLog( "/tmp/changes", ".xml" ) ;
|
||||
|
||||
feed.Start( m_http, ChangesFeed(prev_stamp+1) ) ;
|
||||
|
||||
std::for_each(
|
||||
changes.begin(), changes.end(),
|
||||
boost::bind( &Drive::FromChange, this, _1 ) ) ;
|
||||
feed->EnableLog( "/tmp/changes", ".xml" ) ;
|
||||
while ( feed->GetNext( m_syncer->Agent() ) )
|
||||
{
|
||||
std::for_each(
|
||||
feed->begin(), feed->end(),
|
||||
boost::bind( &Drive::FromChange, this, _1 ) ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Drive::Update()
|
||||
{
|
||||
Syncer1 syncer( m_http );
|
||||
|
||||
Log( "Synchronizing files", log::info ) ;
|
||||
m_state.Sync( &syncer, m_options ) ;
|
||||
m_state.Sync( m_syncer, m_options ) ;
|
||||
|
||||
UpdateChangeStamp( ) ;
|
||||
}
|
||||
|
@ -178,21 +166,14 @@ void Drive::Update()
|
|||
void Drive::DryRun()
|
||||
{
|
||||
Log( "Synchronizing files (dry-run)", log::info ) ;
|
||||
m_state.Sync( 0, m_options ) ;
|
||||
m_state.Sync( NULL, m_options ) ;
|
||||
}
|
||||
|
||||
void Drive::UpdateChangeStamp( )
|
||||
{
|
||||
assert( m_http != 0 ) ;
|
||||
|
||||
// get changed feed
|
||||
http::XmlResponse xrsp ;
|
||||
m_http->Get( ChangesFeed(m_state.ChangeStamp()+1), &xrsp, http::Header() ) ;
|
||||
|
||||
// we should go through the changes to see if it was really Grive to made that change
|
||||
// FIXME: we should go through the changes to see if it was really Grive to made that change
|
||||
// maybe by recording the updated timestamp and compare it?
|
||||
m_state.ChangeStamp(
|
||||
std::atoi(xrsp.Response()["docs:largestChangestamp"]["@value"].front().Value().c_str()) ) ;
|
||||
m_state.ChangeStamp( m_syncer->GetChangeStamp( m_state.ChangeStamp()+1 ) );
|
||||
}
|
||||
|
||||
} } // end of namespace gr::v1
|
||||
} // end of namespace gr
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "State.hh"
|
||||
#include "base/State.hh"
|
||||
|
||||
#include "http/Header.hh"
|
||||
#include "json/Val.hh"
|
||||
#include "util/Exception.hh"
|
||||
|
||||
|
@ -30,19 +29,16 @@
|
|||
|
||||
namespace gr {
|
||||
|
||||
namespace http
|
||||
{
|
||||
class Agent ;
|
||||
}
|
||||
class Syncer ;
|
||||
|
||||
class Entry ;
|
||||
|
||||
namespace v1 {
|
||||
class State ;
|
||||
|
||||
class Drive
|
||||
{
|
||||
public :
|
||||
Drive( http::Agent *agent, const Val& options ) ;
|
||||
Drive( Syncer *syncer, const Val& options ) ;
|
||||
|
||||
void DetectChanges() ;
|
||||
void Update() ;
|
||||
|
@ -58,10 +54,10 @@ private :
|
|||
void UpdateChangeStamp( ) ;
|
||||
|
||||
private :
|
||||
http::Agent *m_http ;
|
||||
Syncer *m_syncer ;
|
||||
fs::path m_root ;
|
||||
State m_state ;
|
||||
Val m_options ;
|
||||
} ;
|
||||
|
||||
} } // end of namespace
|
||||
} // end of namespace gr
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
grive: an GPL program to sync a local directory with Google Drive
|
||||
Copyright (C) 2012 Wan Wai Ho
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation version 2
|
||||
of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "Feed.hh"
|
||||
|
||||
#include "Entry.hh"
|
||||
|
||||
#include "http/Agent.hh"
|
||||
|
||||
namespace gr {
|
||||
|
||||
Feed::Feed( const std::string &url ):
|
||||
m_next( url )
|
||||
{
|
||||
}
|
||||
|
||||
Feed::iterator Feed::begin() const
|
||||
{
|
||||
return m_entries.begin() ;
|
||||
}
|
||||
|
||||
Feed::iterator Feed::end() const
|
||||
{
|
||||
return m_entries.end() ;
|
||||
}
|
||||
|
||||
void Feed::EnableLog( const std::string& prefix, const std::string& suffix )
|
||||
{
|
||||
m_log.reset( new LogInfo ) ;
|
||||
m_log->prefix = prefix ;
|
||||
m_log->suffix = suffix ;
|
||||
m_log->sequence = 0 ;
|
||||
}
|
||||
|
||||
} // end of namespace gr::v1
|
|
@ -21,9 +21,6 @@
|
|||
|
||||
#include "base/Entry.hh"
|
||||
|
||||
#include "xml/Node.hh"
|
||||
#include "xml/NodeSet.hh"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <string>
|
||||
|
@ -35,8 +32,6 @@ namespace http
|
|||
class Agent ;
|
||||
}
|
||||
|
||||
namespace v1 {
|
||||
|
||||
class Feed
|
||||
{
|
||||
public :
|
||||
|
@ -44,24 +39,22 @@ public :
|
|||
typedef std::vector<Entry>::const_iterator iterator;
|
||||
|
||||
public :
|
||||
Feed( ) ;
|
||||
void Start( http::Agent *http, const std::string& url ) ;
|
||||
bool GetNext( http::Agent *http ) ;
|
||||
Feed( const std::string& url );
|
||||
virtual bool GetNext( http::Agent *http ) = 0 ;
|
||||
iterator begin() const ;
|
||||
iterator end() const ;
|
||||
|
||||
void EnableLog( const std::string& prefix, const std::string& suffix ) ;
|
||||
private :
|
||||
virtual void EnableLog( const std::string& prefix, const std::string& suffix ) ;
|
||||
|
||||
protected :
|
||||
struct LogInfo
|
||||
{
|
||||
std::string prefix ;
|
||||
std::string suffix ;
|
||||
std::size_t sequence ;
|
||||
std::string prefix ;
|
||||
std::string suffix ;
|
||||
std::size_t sequence ;
|
||||
} ;
|
||||
std::auto_ptr<LogInfo> m_log ;
|
||||
|
||||
xml::Node m_root ;
|
||||
Entries m_entries ;
|
||||
std::auto_ptr<LogInfo> m_log ;
|
||||
Entries m_entries ;
|
||||
std::string m_next ;
|
||||
} ;
|
||||
|
||||
} } // end of namespace gr::v1
|
||||
} // end of namespace gr
|
|
@ -38,7 +38,7 @@
|
|||
namespace gr {
|
||||
|
||||
/// default constructor creates the root folder
|
||||
Resource::Resource(const fs::path& root_folder) :
|
||||
Resource::Resource( const fs::path& root_folder ) :
|
||||
m_name ( root_folder.string() ),
|
||||
m_kind ( "folder" ),
|
||||
m_id ( "folder:root" ),
|
||||
|
@ -339,7 +339,7 @@ fs::path Resource::Path() const
|
|||
bool Resource::IsInRootTree() const
|
||||
{
|
||||
assert( m_parent == 0 || m_parent->IsFolder() ) ;
|
||||
return m_parent == 0 ? SelfHref().empty() : m_parent->IsInRootTree() ;
|
||||
return m_parent == 0 ? IsRoot() : m_parent->IsInRootTree() ;
|
||||
}
|
||||
|
||||
Resource* Resource::FindChild( const std::string& name )
|
||||
|
@ -507,6 +507,7 @@ std::string Resource::MD5() const
|
|||
|
||||
bool Resource::IsRoot() const
|
||||
{
|
||||
// Root entry does not show up in file feeds, so we check for empty parent (and self-href)
|
||||
return m_parent == 0 ;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#include "ResourceTree.hh"
|
||||
#include "CommonUri.hh"
|
||||
|
||||
#include "util/Destroy.hh"
|
||||
#include "util/log/Log.hh"
|
||||
|
@ -26,12 +25,12 @@
|
|||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace gr { namespace v1 {
|
||||
namespace gr {
|
||||
|
||||
using namespace details ;
|
||||
|
||||
ResourceTree::ResourceTree( const fs::path& rootFolder ) :
|
||||
m_root(new Resource(rootFolder))
|
||||
m_root( new Resource( rootFolder ) )
|
||||
{
|
||||
m_set.insert( m_root ) ;
|
||||
}
|
||||
|
@ -43,7 +42,7 @@ ResourceTree::ResourceTree( const ResourceTree& fs ) :
|
|||
for ( Set::const_iterator i = s.begin() ; i != s.end() ; ++i )
|
||||
{
|
||||
Resource *c = new Resource( **i ) ;
|
||||
if ( c->SelfHref() == root_href )
|
||||
if ( c->IsRoot() )
|
||||
m_root = c ;
|
||||
|
||||
m_set.insert( c ) ;
|
||||
|
@ -142,4 +141,4 @@ ResourceTree::iterator ResourceTree::end()
|
|||
return m_set.get<ByIdentity>().end() ;
|
||||
}
|
||||
|
||||
} } // end of namespace gr::v1
|
||||
} // end of namespace gr
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "base/Resource.hh"
|
||||
#include "Resource.hh"
|
||||
|
||||
#include "util/FileSystem.hh"
|
||||
|
||||
|
@ -30,8 +30,6 @@
|
|||
|
||||
namespace gr {
|
||||
|
||||
namespace v1 {
|
||||
|
||||
namespace details
|
||||
{
|
||||
using namespace boost::multi_index ;
|
||||
|
@ -93,4 +91,4 @@ private :
|
|||
Resource* m_root ;
|
||||
} ;
|
||||
|
||||
} } // end of namespace gr::v1
|
||||
} // end of namespace gr
|
|
@ -19,10 +19,9 @@
|
|||
|
||||
#include "State.hh"
|
||||
|
||||
#include "base/Entry.hh"
|
||||
#include "base/Resource.hh"
|
||||
#include "base/Syncer.hh"
|
||||
#include "CommonUri.hh"
|
||||
#include "Entry.hh"
|
||||
#include "Resource.hh"
|
||||
#include "Syncer.hh"
|
||||
|
||||
#include "util/Crypt.hh"
|
||||
#include "util/File.hh"
|
||||
|
@ -32,11 +31,11 @@
|
|||
|
||||
#include <fstream>
|
||||
|
||||
namespace gr { namespace v1 {
|
||||
namespace gr {
|
||||
|
||||
State::State( const fs::path& filename, const Val& options ) :
|
||||
m_res ( options["path"].Str() ),
|
||||
m_dir ( options["dir"].Str() ),
|
||||
m_res ( options["path"].Str() ),
|
||||
m_dir ( options["dir"].Str() ),
|
||||
m_cstamp ( -1 )
|
||||
{
|
||||
Read( filename ) ;
|
||||
|
@ -308,4 +307,4 @@ void State::ChangeStamp( long cstamp )
|
|||
m_cstamp = cstamp ;
|
||||
}
|
||||
|
||||
} } // end of namespace gr::v1
|
||||
} // end of namespace gr
|
|
@ -36,8 +36,6 @@ class Syncer ;
|
|||
|
||||
class Resource ;
|
||||
|
||||
namespace v1 {
|
||||
|
||||
class State
|
||||
{
|
||||
public :
|
||||
|
@ -82,4 +80,4 @@ private :
|
|||
std::vector<Entry> m_unresolved ;
|
||||
} ;
|
||||
|
||||
} } // end of namespace gr::v1
|
||||
} // end of namespace gr
|
|
@ -29,6 +29,11 @@ Syncer::Syncer( http::Agent *http ):
|
|||
{
|
||||
}
|
||||
|
||||
http::Agent* Syncer::Agent() const
|
||||
{
|
||||
return m_http;
|
||||
}
|
||||
|
||||
void Syncer::AssignIDs( Resource *res, const Entry& remote )
|
||||
{
|
||||
res->AssignIDs( remote );
|
||||
|
|
|
@ -38,6 +38,8 @@ class Resource ;
|
|||
|
||||
class Entry ;
|
||||
|
||||
class Feed ;
|
||||
|
||||
/*! \brief A Syncer incapsulates all resource-related upload/download/edit methods */
|
||||
class Syncer
|
||||
{
|
||||
|
@ -45,11 +47,18 @@ public :
|
|||
|
||||
Syncer( http::Agent *http );
|
||||
|
||||
http::Agent* Agent() const;
|
||||
|
||||
virtual void DeleteRemote( Resource *res ) = 0;
|
||||
virtual void Download( Resource *res, const fs::path& file ) = 0;
|
||||
virtual bool EditContent( Resource *res, bool new_rev ) = 0;
|
||||
virtual bool Create( Resource *res ) = 0;
|
||||
|
||||
virtual std::auto_ptr<Feed> GetFolders() = 0;
|
||||
virtual std::auto_ptr<Feed> GetAll() = 0;
|
||||
virtual std::auto_ptr<Feed> GetChanges( long min_cstamp ) = 0;
|
||||
virtual long GetChangeStamp( long min_cstamp ) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
http::Agent *m_http;
|
||||
|
|
|
@ -31,6 +31,4 @@ namespace gr { namespace v1
|
|||
"https://docs.google.com/feeds/default/private/full/folder%3Aroot" ;
|
||||
const std::string root_create =
|
||||
"https://docs.google.com/feeds/upload/create-session/default/private/full" ;
|
||||
|
||||
std::string ChangesFeed( int changestamp ) ;
|
||||
} }
|
||||
|
|
|
@ -70,7 +70,12 @@ void Entry1::Update( const xml::Node& n )
|
|||
m_parent_hrefs.clear( ) ;
|
||||
xml::NodeSet parents = n["link"].Find( "@rel", "http://schemas.google.com/docs/2007#parent" ) ;
|
||||
for ( xml::NodeSet::iterator i = parents.begin() ; i != parents.end() ; ++i )
|
||||
m_parent_hrefs.push_back( (*i)["@href"] ) ;
|
||||
{
|
||||
std::string href = (*i)["@href"];
|
||||
if ( href == root_href ) // API-independent root href is empty!
|
||||
href = "";
|
||||
m_parent_hrefs.push_back( href ) ;
|
||||
}
|
||||
|
||||
// convert to lower case for easy comparison
|
||||
std::transform( m_md5.begin(), m_md5.end(), m_md5.begin(), tolower ) ;
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "Feed.hh"
|
||||
#include "CommonUri.hh"
|
||||
#include "Feed1.hh"
|
||||
|
||||
#include "Entry1.hh"
|
||||
|
||||
|
@ -33,62 +34,39 @@
|
|||
|
||||
namespace gr { namespace v1 {
|
||||
|
||||
Feed::Feed( )
|
||||
Feed1::Feed1( const std::string &url ):
|
||||
Feed( url )
|
||||
{
|
||||
}
|
||||
|
||||
Feed::iterator Feed::begin() const
|
||||
{
|
||||
return m_entries.begin() ;
|
||||
}
|
||||
|
||||
Feed::iterator Feed::end() const
|
||||
{
|
||||
return m_entries.end() ;
|
||||
}
|
||||
|
||||
void Feed::Start( http::Agent *http, const std::string& url )
|
||||
bool Feed1::GetNext( http::Agent *http )
|
||||
{
|
||||
http::XmlResponse xrsp ;
|
||||
http::ResponseLog log( &xrsp ) ;
|
||||
|
||||
if ( m_next.empty() )
|
||||
return false;
|
||||
|
||||
if ( m_log.get() != 0 )
|
||||
log.Reset(
|
||||
m_log->prefix,
|
||||
(boost::format( "-#%1%%2%" ) % m_log->sequence++ % m_log->suffix ).str(),
|
||||
&xrsp ) ;
|
||||
|
||||
http->Get( url, &log, http::Header() ) ;
|
||||
http->Get( m_next, &log, http::Header() ) ;
|
||||
|
||||
m_root = xrsp.Response() ;
|
||||
xml::Node m_root = xrsp.Response() ;
|
||||
xml::NodeSet xe = m_root["entry"] ;
|
||||
m_entries.clear() ;
|
||||
for ( xml::NodeSet::iterator i = xe.begin() ; i != xe.end() ; ++i )
|
||||
{
|
||||
m_entries.push_back( Entry1( *i ) );
|
||||
}
|
||||
}
|
||||
|
||||
bool Feed::GetNext( http::Agent *http )
|
||||
{
|
||||
assert( http != 0 ) ;
|
||||
|
||||
|
||||
xml::NodeSet nss = m_root["link"].Find( "@rel", "next" ) ;
|
||||
if ( !nss.empty() )
|
||||
{
|
||||
Start( http, nss["@href"] ) ;
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
return false ;
|
||||
}
|
||||
|
||||
void Feed::EnableLog( const std::string& prefix, const std::string& suffix )
|
||||
{
|
||||
m_log.reset( new LogInfo ) ;
|
||||
m_log->prefix = prefix ;
|
||||
m_log->suffix = suffix ;
|
||||
m_log->sequence = 0 ;
|
||||
m_next = nss.empty() ? std::string( "" ) : nss["@href"];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} } // end of namespace gr::v1
|
|
@ -17,15 +17,24 @@
|
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "CommonUri.hh"
|
||||
#include <boost/format.hpp>
|
||||
#pragma once
|
||||
|
||||
#include "base/Feed.hh"
|
||||
|
||||
#include "xml/Node.hh"
|
||||
#include "xml/NodeSet.hh"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gr { namespace v1 {
|
||||
|
||||
std::string ChangesFeed( int changestamp )
|
||||
class Feed1: public Feed
|
||||
{
|
||||
boost::format feed( feed_changes + "?start-index=%1%" ) ;
|
||||
return changestamp > 0 ? (feed%changestamp).str() : feed_changes ;
|
||||
}
|
||||
public :
|
||||
Feed1( const std::string& url ) ;
|
||||
bool GetNext( http::Agent *http ) ;
|
||||
} ;
|
||||
|
||||
} }
|
||||
} } // end of namespace gr::v1
|
|
@ -20,6 +20,7 @@
|
|||
#include "base/Resource.hh"
|
||||
#include "CommonUri.hh"
|
||||
#include "Entry1.hh"
|
||||
#include "Feed1.hh"
|
||||
#include "Syncer1.hh"
|
||||
|
||||
#include "http/Agent.hh"
|
||||
|
@ -58,6 +59,7 @@ const std::string xml_meta =
|
|||
Syncer1::Syncer1( http::Agent *http ):
|
||||
Syncer( http )
|
||||
{
|
||||
assert( http != 0 ) ;
|
||||
}
|
||||
|
||||
void Syncer1::DeleteRemote( Resource *res )
|
||||
|
@ -252,4 +254,33 @@ bool Syncer1::Upload( Resource *res,
|
|||
return true ;
|
||||
}
|
||||
|
||||
std::auto_ptr<Feed> Syncer1::GetFolders()
|
||||
{
|
||||
return std::auto_ptr<Feed>( new Feed1( feed_base + "/-/folder?max-results=50&showroot=true" ) );
|
||||
}
|
||||
|
||||
std::auto_ptr<Feed> Syncer1::GetAll()
|
||||
{
|
||||
return std::auto_ptr<Feed>( new Feed1( feed_base + "?showfolders=true&showroot=true" ) );
|
||||
}
|
||||
|
||||
std::string ChangesFeed( int changestamp )
|
||||
{
|
||||
boost::format feed( feed_changes + "?start-index=%1%" ) ;
|
||||
return changestamp > 0 ? ( feed % changestamp ).str() : feed_changes ;
|
||||
}
|
||||
|
||||
std::auto_ptr<Feed> Syncer1::GetChanges( long min_cstamp )
|
||||
{
|
||||
return std::auto_ptr<Feed>( new Feed1( ChangesFeed( min_cstamp ) ) );
|
||||
}
|
||||
|
||||
long Syncer1::GetChangeStamp( long min_cstamp )
|
||||
{
|
||||
http::XmlResponse xrsp ;
|
||||
m_http->Get( ChangesFeed( min_cstamp ), &xrsp, http::Header() ) ;
|
||||
|
||||
return std::atoi( xrsp.Response()["docs:largestChangestamp"]["@value"].front().Value().c_str() );
|
||||
}
|
||||
|
||||
} } // end of namespace gr::v1
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
namespace gr {
|
||||
|
||||
class Feed;
|
||||
|
||||
namespace v1 {
|
||||
|
||||
class Syncer1: public Syncer
|
||||
|
@ -37,6 +39,11 @@ public :
|
|||
bool EditContent( Resource *res, bool new_rev );
|
||||
bool Create( Resource *res );
|
||||
|
||||
std::auto_ptr<Feed> GetFolders();
|
||||
std::auto_ptr<Feed> GetAll();
|
||||
std::auto_ptr<Feed> GetChanges( long min_cstamp );
|
||||
long GetChangeStamp( long min_cstamp );
|
||||
|
||||
private :
|
||||
|
||||
bool Upload( Resource *res, const std::string& link, bool post);
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace gr { namespace v2 {
|
|||
namespace feeds
|
||||
{
|
||||
const std::string files = "https://www.googleapis.com/drive/v2/files" ;
|
||||
const std::string changes = "https://www.googleapis.com/drive/v2/changes" ;
|
||||
}
|
||||
|
||||
namespace mime_types
|
||||
|
@ -33,9 +34,4 @@ namespace mime_types
|
|||
const std::string folder = "application/vnd.google-apps.folder" ;
|
||||
}
|
||||
|
||||
namespace kinds
|
||||
{
|
||||
const std::string parent = "drive#parentReference" ;
|
||||
}
|
||||
|
||||
} } // end of namespace gr::v2
|
||||
|
|
|
@ -69,7 +69,9 @@ void Entry2::Update( const Val& item )
|
|||
|
||||
Val::Array parents = file["parents"].AsArray() ;
|
||||
for ( Val::Array::iterator i = parents.begin() ; i != parents.end() ; ++i )
|
||||
m_parent_hrefs.push_back( (*i)["parentLink"] ) ; // maybe .id?
|
||||
{
|
||||
m_parent_hrefs.push_back( (*i)["isRoot"].Bool() ? std::string() : (*i)["parentLink"] ) ; // maybe .id?
|
||||
}
|
||||
|
||||
// convert to lower case for easy comparison
|
||||
std::transform( m_md5.begin(), m_md5.end(), m_md5.begin(), tolower ) ;
|
||||
|
|
|
@ -17,42 +17,42 @@
|
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "Feed.hh"
|
||||
#include "CommonUri.hh"
|
||||
#include "Feed2.hh"
|
||||
#include "Entry2.hh"
|
||||
|
||||
#include "http/Agent.hh"
|
||||
#include "http/Header.hh"
|
||||
#include "json/Val.hh"
|
||||
#include "json/ValResponse.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace gr { namespace v2 {
|
||||
|
||||
Feed::Feed( )
|
||||
Feed2::Feed2( const std::string& url ):
|
||||
Feed( url )
|
||||
{
|
||||
}
|
||||
|
||||
// for example to find dirs: '?q=mimeType%3d%27' + mime_types::folder + '%27'
|
||||
void Feed::Start( http::Agent *http, const std::string& url )
|
||||
bool Feed2::GetNext( http::Agent *http )
|
||||
{
|
||||
http::ValResponse out ;
|
||||
|
||||
http->Get( url, &out, http::Header() ) ;
|
||||
|
||||
m_content = out.Response() ;
|
||||
}
|
||||
|
||||
bool Feed::GetNext( http::Agent *http )
|
||||
{
|
||||
assert( http != 0 ) ;
|
||||
|
||||
Val url ;
|
||||
if ( m_content.Get( "nextLink", url ) )
|
||||
{
|
||||
Start( http, url ) ;
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
if ( m_next.empty() )
|
||||
return false ;
|
||||
|
||||
http::ValResponse out ;
|
||||
http->Get( m_next, &out, http::Header() ) ;
|
||||
Val m_content = out.Response() ;
|
||||
|
||||
Val::Array items = m_content["items"].AsArray() ;
|
||||
m_entries.clear() ;
|
||||
for ( Val::Array::iterator i = items.begin() ; i != items.end() ; ++i )
|
||||
m_entries.push_back( Entry2( *i ) );
|
||||
|
||||
Val url ;
|
||||
m_next = m_content.Get( "nextLink", url ) ? url : std::string( "" ) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
} } // end of namespace
|
||||
} } // end of namespace gr::v2
|
|
@ -19,31 +19,19 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "json/Val.hh"
|
||||
#include "base/Feed.hh"
|
||||
|
||||
#include "util/Exception.hh"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
class Agent ;
|
||||
}
|
||||
namespace gr { namespace v2 {
|
||||
|
||||
class Val ;
|
||||
|
||||
namespace v2 {
|
||||
|
||||
class Feed
|
||||
class Feed2: public Feed
|
||||
{
|
||||
public :
|
||||
Feed( ) ;
|
||||
void Start( http::Agent *http, const std::string& url ) ;
|
||||
Feed2( const std::string& url ) ;
|
||||
bool GetNext( http::Agent *http ) ;
|
||||
|
||||
private :
|
||||
Val m_content ;
|
||||
} ;
|
||||
|
||||
} } // end of namespace gr::v2
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
grive: an GPL program to sync a local directory with Google Drive
|
||||
Copyright (C) 2012 Wan Wai Ho
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation version 2
|
||||
of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "base/Resource.hh"
|
||||
#include "CommonUri.hh"
|
||||
#include "Entry2.hh"
|
||||
#include "Feed2.hh"
|
||||
#include "Syncer2.hh"
|
||||
|
||||
#include "http/Agent.hh"
|
||||
#include "http/Download.hh"
|
||||
#include "http/Header.hh"
|
||||
//#include "http/ResponseLog.hh"
|
||||
#include "json/ValResponse.hh"
|
||||
|
||||
#include "util/OS.hh"
|
||||
#include "util/log/Log.hh"
|
||||
|
||||
#include <boost/exception/all.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// for debugging
|
||||
#include <iostream>
|
||||
|
||||
namespace gr { namespace v2 {
|
||||
|
||||
Syncer2::Syncer2( http::Agent *http ):
|
||||
Syncer( http )
|
||||
{
|
||||
assert( http != 0 ) ;
|
||||
}
|
||||
|
||||
void Syncer2::DeleteRemote( Resource *res )
|
||||
{
|
||||
}
|
||||
|
||||
void Syncer2::Download( Resource *res, const fs::path& file )
|
||||
{
|
||||
}
|
||||
|
||||
bool Syncer2::EditContent( Resource *res, bool new_rev )
|
||||
{
|
||||
return false ;
|
||||
}
|
||||
|
||||
bool Syncer2::Create( Resource *res )
|
||||
{
|
||||
return false ;
|
||||
}
|
||||
|
||||
std::auto_ptr<Feed> Syncer2::GetFolders()
|
||||
{
|
||||
return std::auto_ptr<Feed>( new Feed2( feeds::files + "?maxResults=1000&q=%27me%27+in+readers+and+mimeType%3d%27" + mime_types::folder + "%27" ) );
|
||||
}
|
||||
|
||||
std::auto_ptr<Feed> Syncer2::GetAll()
|
||||
{
|
||||
return std::auto_ptr<Feed>( new Feed2( feeds::files + "?maxResults=1000&q=%27me%27+in+readers" ) );
|
||||
}
|
||||
|
||||
std::string ChangesFeed( long changestamp, int maxResults = 1000 )
|
||||
{
|
||||
boost::format feed( feeds::changes + "?maxResults=%1%&includeSubscribed=false" + ( changestamp > 0 ? "&startChangeId=%2%" : "" ) ) ;
|
||||
return ( changestamp > 0 ? feed % maxResults % changestamp : feed % maxResults ).str() ;
|
||||
}
|
||||
|
||||
std::auto_ptr<Feed> Syncer2::GetChanges( long min_cstamp )
|
||||
{
|
||||
return std::auto_ptr<Feed>( new Feed2( ChangesFeed( min_cstamp ) ) );
|
||||
}
|
||||
|
||||
long Syncer2::GetChangeStamp( long min_cstamp )
|
||||
{
|
||||
http::ValResponse res ;
|
||||
m_http->Get( ChangesFeed( min_cstamp, 1 ), &res, http::Header() ) ;
|
||||
|
||||
return std::atoi( res.Response()["largestChangeId"].Str().c_str() );
|
||||
}
|
||||
|
||||
} } // end of namespace gr::v1
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
grive: an GPL program to sync a local directory with Google Drive
|
||||
Copyright (C) 2012 Wan Wai Ho
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation version 2
|
||||
of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Syncer.hh"
|
||||
|
||||
namespace gr {
|
||||
|
||||
class Feed;
|
||||
|
||||
namespace v2 {
|
||||
|
||||
class Syncer2: public Syncer
|
||||
{
|
||||
|
||||
public :
|
||||
|
||||
Syncer2( http::Agent *http );
|
||||
|
||||
void DeleteRemote( Resource *res );
|
||||
void Download( Resource *res, const fs::path& file );
|
||||
bool EditContent( Resource *res, bool new_rev );
|
||||
bool Create( Resource *res );
|
||||
|
||||
std::auto_ptr<Feed> GetFolders();
|
||||
std::auto_ptr<Feed> GetAll();
|
||||
std::auto_ptr<Feed> GetChanges( long min_cstamp );
|
||||
long GetChangeStamp( long min_cstamp );
|
||||
|
||||
private :
|
||||
|
||||
} ;
|
||||
|
||||
} } // end of namespace gr::v2
|
Loading…
Reference in New Issue