From 862fca035af0b1f953bfd57abc21c8479d91b8b3 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Sun, 17 May 2015 16:54:04 +0300 Subject: [PATCH] Move all protocol interaction into Syncers out of the base code --- grive/src/main.cc | 6 +- libgrive/src/{drive => base}/Drive.cc | 77 ++++++--------- libgrive/src/{drive => base}/Drive.hh | 16 ++- libgrive/src/base/Feed.cc | 51 ++++++++++ libgrive/src/{drive => base}/Feed.hh | 31 +++--- libgrive/src/base/Resource.cc | 5 +- libgrive/src/{drive => base}/ResourceTree.cc | 9 +- libgrive/src/{drive => base}/ResourceTree.hh | 6 +- libgrive/src/{drive => base}/State.cc | 15 ++- libgrive/src/{drive => base}/State.hh | 4 +- libgrive/src/base/Syncer.cc | 5 + libgrive/src/base/Syncer.hh | 9 ++ libgrive/src/drive/CommonUri.hh | 2 - libgrive/src/drive/Entry1.cc | 7 +- libgrive/src/drive/{Feed.cc => Feed1.cc} | 50 +++------- libgrive/src/drive/{CommonUri.cc => Feed1.hh} | 23 +++-- libgrive/src/drive/Syncer1.cc | 31 ++++++ libgrive/src/drive/Syncer1.hh | 7 ++ libgrive/src/drive2/CommonUri.hh | 6 +- libgrive/src/drive2/Entry2.cc | 4 +- libgrive/src/drive2/{Feed.cc => Feed2.cc} | 46 ++++----- libgrive/src/drive2/{Feed.hh => Feed2.hh} | 22 +---- libgrive/src/drive2/Syncer2.cc | 97 +++++++++++++++++++ libgrive/src/drive2/Syncer2.hh | 51 ++++++++++ 24 files changed, 387 insertions(+), 193 deletions(-) rename libgrive/src/{drive => base}/Drive.cc (70%) rename libgrive/src/{drive => base}/Drive.hh (86%) create mode 100644 libgrive/src/base/Feed.cc rename libgrive/src/{drive => base}/Feed.hh (71%) rename libgrive/src/{drive => base}/ResourceTree.cc (95%) rename libgrive/src/{drive => base}/ResourceTree.hh (97%) rename libgrive/src/{drive => base}/State.cc (96%) rename libgrive/src/{drive => base}/State.hh (97%) rename libgrive/src/drive/{Feed.cc => Feed1.cc} (69%) rename libgrive/src/drive/{CommonUri.cc => Feed1.hh} (74%) rename libgrive/src/drive2/{Feed.cc => Feed2.cc} (60%) rename libgrive/src/drive2/{Feed.hh => Feed2.hh} (81%) create mode 100644 libgrive/src/drive2/Syncer2.cc create mode 100644 libgrive/src/drive2/Syncer2.hh diff --git a/grive/src/main.cc b/grive/src/main.cc index b172f40..b323c05 100644 --- a/grive/src/main.cc +++ b/grive/src/main.cc @@ -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( new http::CurlAgent ) ) ; + Syncer1 syncer( &agent ); - Drive drive( &agent, config.GetAll() ) ; + Drive drive( &syncer, config.GetAll() ) ; drive.DetectChanges() ; if ( vm.count( "dry-run" ) == 0 ) diff --git a/libgrive/src/drive/Drive.cc b/libgrive/src/base/Drive.cc similarity index 70% rename from libgrive/src/drive/Drive.cc rename to libgrive/src/base/Drive.cc index ea46654..10a194b 100644 --- a/libgrive/src/drive/Drive.cc +++ b/libgrive/src/base/Drive.cc @@ -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 @@ -45,20 +40,20 @@ // for debugging only #include -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 = 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 = 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 diff --git a/libgrive/src/drive/Drive.hh b/libgrive/src/base/Drive.hh similarity index 86% rename from libgrive/src/drive/Drive.hh rename to libgrive/src/base/Drive.hh index c11a744..7a63999 100644 --- a/libgrive/src/drive/Drive.hh +++ b/libgrive/src/base/Drive.hh @@ -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 diff --git a/libgrive/src/base/Feed.cc b/libgrive/src/base/Feed.cc new file mode 100644 index 0000000..7ff3850 --- /dev/null +++ b/libgrive/src/base/Feed.cc @@ -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 diff --git a/libgrive/src/drive/Feed.hh b/libgrive/src/base/Feed.hh similarity index 71% rename from libgrive/src/drive/Feed.hh rename to libgrive/src/base/Feed.hh index db27137..8be1e55 100644 --- a/libgrive/src/drive/Feed.hh +++ b/libgrive/src/base/Feed.hh @@ -21,9 +21,6 @@ #include "base/Entry.hh" -#include "xml/Node.hh" -#include "xml/NodeSet.hh" - #include #include @@ -35,8 +32,6 @@ namespace http class Agent ; } -namespace v1 { - class Feed { public : @@ -44,24 +39,22 @@ public : typedef std::vector::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 m_log ; - - xml::Node m_root ; - Entries m_entries ; + std::auto_ptr m_log ; + Entries m_entries ; + std::string m_next ; } ; -} } // end of namespace gr::v1 +} // end of namespace gr diff --git a/libgrive/src/base/Resource.cc b/libgrive/src/base/Resource.cc index ef995ab..889e070 100644 --- a/libgrive/src/base/Resource.cc +++ b/libgrive/src/base/Resource.cc @@ -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 ; } diff --git a/libgrive/src/drive/ResourceTree.cc b/libgrive/src/base/ResourceTree.cc similarity index 95% rename from libgrive/src/drive/ResourceTree.cc rename to libgrive/src/base/ResourceTree.cc index fa8af7e..3aa8d55 100644 --- a/libgrive/src/drive/ResourceTree.cc +++ b/libgrive/src/base/ResourceTree.cc @@ -18,7 +18,6 @@ */ #include "ResourceTree.hh" -#include "CommonUri.hh" #include "util/Destroy.hh" #include "util/log/Log.hh" @@ -26,12 +25,12 @@ #include #include -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().end() ; } -} } // end of namespace gr::v1 +} // end of namespace gr diff --git a/libgrive/src/drive/ResourceTree.hh b/libgrive/src/base/ResourceTree.hh similarity index 97% rename from libgrive/src/drive/ResourceTree.hh rename to libgrive/src/base/ResourceTree.hh index 1c34172..b74d9f1 100644 --- a/libgrive/src/drive/ResourceTree.hh +++ b/libgrive/src/base/ResourceTree.hh @@ -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 diff --git a/libgrive/src/drive/State.cc b/libgrive/src/base/State.cc similarity index 96% rename from libgrive/src/drive/State.cc rename to libgrive/src/base/State.cc index a74d414..d0525f2 100644 --- a/libgrive/src/drive/State.cc +++ b/libgrive/src/base/State.cc @@ -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 -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 diff --git a/libgrive/src/drive/State.hh b/libgrive/src/base/State.hh similarity index 97% rename from libgrive/src/drive/State.hh rename to libgrive/src/base/State.hh index 3fe68ce..c870cae 100644 --- a/libgrive/src/drive/State.hh +++ b/libgrive/src/base/State.hh @@ -36,8 +36,6 @@ class Syncer ; class Resource ; -namespace v1 { - class State { public : @@ -82,4 +80,4 @@ private : std::vector m_unresolved ; } ; -} } // end of namespace gr::v1 +} // end of namespace gr diff --git a/libgrive/src/base/Syncer.cc b/libgrive/src/base/Syncer.cc index ef6d7de..98d2aca 100644 --- a/libgrive/src/base/Syncer.cc +++ b/libgrive/src/base/Syncer.cc @@ -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 ); diff --git a/libgrive/src/base/Syncer.hh b/libgrive/src/base/Syncer.hh index 6665e5c..efe04bc 100644 --- a/libgrive/src/base/Syncer.hh +++ b/libgrive/src/base/Syncer.hh @@ -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 GetFolders() = 0; + virtual std::auto_ptr GetAll() = 0; + virtual std::auto_ptr GetChanges( long min_cstamp ) = 0; + virtual long GetChangeStamp( long min_cstamp ) = 0; + protected: http::Agent *m_http; diff --git a/libgrive/src/drive/CommonUri.hh b/libgrive/src/drive/CommonUri.hh index b0e06f7..98cc959 100644 --- a/libgrive/src/drive/CommonUri.hh +++ b/libgrive/src/drive/CommonUri.hh @@ -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 ) ; } } diff --git a/libgrive/src/drive/Entry1.cc b/libgrive/src/drive/Entry1.cc index 2d1d61a..d44b421 100644 --- a/libgrive/src/drive/Entry1.cc +++ b/libgrive/src/drive/Entry1.cc @@ -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 ) ; diff --git a/libgrive/src/drive/Feed.cc b/libgrive/src/drive/Feed1.cc similarity index 69% rename from libgrive/src/drive/Feed.cc rename to libgrive/src/drive/Feed1.cc index 087defd..05093aa 100644 --- a/libgrive/src/drive/Feed.cc +++ b/libgrive/src/drive/Feed1.cc @@ -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 diff --git a/libgrive/src/drive/CommonUri.cc b/libgrive/src/drive/Feed1.hh similarity index 74% rename from libgrive/src/drive/CommonUri.cc rename to libgrive/src/drive/Feed1.hh index a69b02b..8446693 100644 --- a/libgrive/src/drive/CommonUri.cc +++ b/libgrive/src/drive/Feed1.hh @@ -17,15 +17,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "CommonUri.hh" -#include +#pragma once + +#include "base/Feed.hh" + +#include "xml/Node.hh" +#include "xml/NodeSet.hh" + +#include + +#include 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 diff --git a/libgrive/src/drive/Syncer1.cc b/libgrive/src/drive/Syncer1.cc index 816572f..3cde417 100644 --- a/libgrive/src/drive/Syncer1.cc +++ b/libgrive/src/drive/Syncer1.cc @@ -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 Syncer1::GetFolders() +{ + return std::auto_ptr( new Feed1( feed_base + "/-/folder?max-results=50&showroot=true" ) ); +} + +std::auto_ptr Syncer1::GetAll() +{ + return std::auto_ptr( 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 Syncer1::GetChanges( long min_cstamp ) +{ + return std::auto_ptr( 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 diff --git a/libgrive/src/drive/Syncer1.hh b/libgrive/src/drive/Syncer1.hh index 7f3d1cc..b45e71c 100644 --- a/libgrive/src/drive/Syncer1.hh +++ b/libgrive/src/drive/Syncer1.hh @@ -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 GetFolders(); + std::auto_ptr GetAll(); + std::auto_ptr GetChanges( long min_cstamp ); + long GetChangeStamp( long min_cstamp ); + private : bool Upload( Resource *res, const std::string& link, bool post); diff --git a/libgrive/src/drive2/CommonUri.hh b/libgrive/src/drive2/CommonUri.hh index 8f5304c..34c6f04 100644 --- a/libgrive/src/drive2/CommonUri.hh +++ b/libgrive/src/drive2/CommonUri.hh @@ -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 diff --git a/libgrive/src/drive2/Entry2.cc b/libgrive/src/drive2/Entry2.cc index 1479523..321539f 100644 --- a/libgrive/src/drive2/Entry2.cc +++ b/libgrive/src/drive2/Entry2.cc @@ -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 ) ; diff --git a/libgrive/src/drive2/Feed.cc b/libgrive/src/drive2/Feed2.cc similarity index 60% rename from libgrive/src/drive2/Feed.cc rename to libgrive/src/drive2/Feed2.cc index 03fcea4..bb5abc4 100644 --- a/libgrive/src/drive2/Feed.cc +++ b/libgrive/src/drive2/Feed2.cc @@ -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 +#include 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 diff --git a/libgrive/src/drive2/Feed.hh b/libgrive/src/drive2/Feed2.hh similarity index 81% rename from libgrive/src/drive2/Feed.hh rename to libgrive/src/drive2/Feed2.hh index 7191750..7948d20 100644 --- a/libgrive/src/drive2/Feed.hh +++ b/libgrive/src/drive2/Feed2.hh @@ -19,31 +19,19 @@ #pragma once -#include "json/Val.hh" +#include "base/Feed.hh" + #include "util/Exception.hh" #include -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 diff --git a/libgrive/src/drive2/Syncer2.cc b/libgrive/src/drive2/Syncer2.cc new file mode 100644 index 0000000..1855e1c --- /dev/null +++ b/libgrive/src/drive2/Syncer2.cc @@ -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 + +#include + +// for debugging +#include + +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 Syncer2::GetFolders() +{ + return std::auto_ptr( new Feed2( feeds::files + "?maxResults=1000&q=%27me%27+in+readers+and+mimeType%3d%27" + mime_types::folder + "%27" ) ); +} + +std::auto_ptr Syncer2::GetAll() +{ + return std::auto_ptr( 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 Syncer2::GetChanges( long min_cstamp ) +{ + return std::auto_ptr( 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 diff --git a/libgrive/src/drive2/Syncer2.hh b/libgrive/src/drive2/Syncer2.hh new file mode 100644 index 0000000..35142a9 --- /dev/null +++ b/libgrive/src/drive2/Syncer2.hh @@ -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 GetFolders(); + std::auto_ptr GetAll(); + std::auto_ptr GetChanges( long min_cstamp ); + long GetChangeStamp( long min_cstamp ); + +private : + +} ; + +} } // end of namespace gr::v2