handling change feed. some good news about trashed documents

pull/40/head
Nestal Wan 2012-06-05 00:32:12 +08:00
parent a09ba40dbc
commit 935ac608ff
9 changed files with 96 additions and 75 deletions

View File

@ -76,7 +76,7 @@ Drive::Drive( OAuth2& auth, const Json& options ) :
std::atoi(xrsp.Response()["docs:largestChangestamp"]["@value"].front().Value().c_str()) ) ;
SyncFolders( &http ) ;
Log( "Reading remote server file list", log::info ) ;
http.Get( feed_base + "?showfolders=true&showroot=true", &xrsp, m_http_hdr ) ;
xml::Node resp = xrsp.Response() ;
@ -84,84 +84,60 @@ Drive::Drive( OAuth2& auth, const Json& options ) :
m_resume_link = resp["link"].
Find( "@rel", "http://schemas.google.com/g/2005#resumable-create-media" )["@href"] ;
// bool has_next = false ;
Feed feed( resp ) ;
do
{
// xml::NodeSet entries = resp["entry"] ;
for ( Feed::iterator i = feed.begin() ; i != feed.end() ; ++i )
{
// if ( (*i)["content"] == "" )
// continue ;
Entry entry( *i ) ;
if ( entry.Kind() != "folder" )
{
Resource *parent = m_state.FindByHref( entry.ParentHref() ) ;
std::string fn = entry.Filename() ;
if ( fn.empty() )
Log( "file \"%1%\" is a google document, ignored", entry.Title(), log::verbose ) ;
else if ( fn.find('/') != fn.npos )
Log( "file \"%1%\" contains a slash in its name, ignored", entry.Title(), log::verbose ) ;
else if ( parent == 0 || !parent->IsInRootTree() )
Log( "file \"%1%\" parent doesn't exist, ignored", entry.Title(), log::verbose ) ;
else if ( parent != 0 && !parent->IsFolder() )
Log( "warning: entry %1% has parent %2% which is not a folder, ignored",
entry.Title(), parent->Name(), log::verbose ) ;
else
m_state.FromRemote( entry ) ;
}
}
// xml::NodeSet nss = resp["link"].Find( "@rel", "next" ) ;
// has_next = !nss.empty() ;
// std::string next_uri = feed.Next() ;
// if ( !next_uri.empty() )
// {
// http.Get( next_uri, &xrsp, m_http_hdr ) ;
// resp = xrsp.Response() ;
// }
std::for_each( feed.begin(), feed.end(), boost::bind( &Drive::FromRemote, this, _1 ) ) ;
} while ( feed.GetNext( &http, m_http_hdr ) ) ;
// pull the changes feed
boost::format changes_uri( "https://docs.google.com/feeds/default/private/changes?start-index=%1%" ) ;
http::ResponseLog log2( "changes-", ".xml", &xrsp ) ;
http.Get( (changes_uri%(prev_stamp+1)).str(), &log2, m_http_hdr ) ;
xml::NodeSet centries = xrsp.Response()["entry"] ;
for ( xml::NodeSet::iterator i = centries.begin() ; i != centries.end() ; ++i )
{
if ( (*i)["content"] == "" )
continue ;
Feed changes( xrsp.Response() ) ;
std::for_each( changes.begin(), changes.end(), boost::bind( &Drive::FromChange, this, _1 ) ) ;
}
Entry entry( *i ) ;
if ( entry.Kind() != "folder" )
{
Resource *parent = m_state.FindByHref( entry.ParentHref() ) ;
std::string fn = entry.Filename() ;
if ( fn.empty() )
Log( "file \"%1%\" is a google document, ignored", entry.Title(), log::verbose ) ;
else if ( fn.find('/') != fn.npos )
Log( "file \"%1%\" contains a slash in its name, ignored", entry.Title(), log::verbose ) ;
else if ( parent == 0 || !parent->IsInRootTree() )
Log( "file \"%1%\" parent doesn't exist, ignored", entry.Title(), log::verbose ) ;
else if ( parent != 0 && !parent->IsFolder() )
Log( "warning: entry %1% has parent %2% which is not a folder, ignored",
entry.Title(), parent->Name(), log::verbose ) ;
else
m_state.FromRemote( entry ) ;
}
void Drive::FromRemote( const Entry& entry )
{
if ( entry.Kind() != "folder" && !entry.ContentSrc().empty() )
{
Resource *parent = m_state.FindByHref( entry.ParentHref() ) ;
std::string fn = entry.Filename() ;
if ( fn.empty() )
Log( "file \"%1%\" is a google document, ignored", entry.Title(), log::verbose ) ;
else if ( fn.find('/') != fn.npos )
Log( "file \"%1%\" contains a slash in its name, ignored", entry.Title(), log::verbose ) ;
else if ( parent == 0 || !parent->IsInRootTree() )
Log( "file \"%1%\" parent doesn't exist, ignored", entry.Title(), log::verbose ) ;
else if ( parent != 0 && !parent->IsFolder() )
Log( "warning: entry %1% has parent %2% which is not a folder, ignored",
entry.Title(), parent->Name(), log::verbose ) ;
else
m_state.FromRemote( entry ) ;
}
}
void Drive::FromChange( const Entry& entry )
{
std::string fn = entry.Filename() ;
if ( entry.IsRemoved() )
Log( "file \"%1%\" represents a deletion, ignored", entry.Title(), log::verbose ) ;
else if ( fn.empty() )
Log( "file \"%1%\" is a google document, ignored", entry.Title(), log::verbose ) ;
else if ( !entry.ContentSrc().empty() )
{
Log( "changed entry: %1% %2%", entry.Filename(), entry.ContentSrc() ) ;
m_state.FromChange( entry ) ;
}
}

View File

@ -34,6 +34,7 @@ namespace http
class Agent ;
}
class Entry ;
class OAuth2 ;
class Json ;
@ -51,6 +52,8 @@ public :
private :
void SyncFolders( http::Agent *http ) ;
void file();
void FromRemote( const Entry& entry ) ;
void FromChange( const Entry& entry ) ;
private :
OAuth2& m_auth ;

View File

@ -38,13 +38,15 @@ Entry::Entry( ) :
m_resource_id ( "folder:root" ),
m_self_href ( root_href ),
m_create_link ( root_create ),
m_change_stamp ( -1 )
m_change_stamp ( -1 ),
m_is_removed ( false )
{
}
/// construct an entry for remote
Entry::Entry( const xml::Node& n ) :
m_change_stamp( -1 )
m_change_stamp( -1 ),
m_is_removed( false )
{
Update( n ) ;
}
@ -74,6 +76,7 @@ void Entry::Update( const xml::Node& n )
m_filename = n["docs:suggestedFilename"] ;
m_content_src = n["content"]["@src"] ;
m_self_href = n["link"].Find( "@rel", "self" )["@href"] ;
m_alt_self = n["link"].Find( "@rel", "http://schemas.google.com/docs/2007#alt-self" )["@href"] ;
m_mtime = DateTime( n["updated"] ) ;
m_resource_id = n["gd:resourceId"] ;
@ -92,6 +95,8 @@ void Entry::Update( const xml::Node& n )
// convert to lower case for easy comparison
std::transform( m_md5.begin(), m_md5.end(), m_md5.begin(), tolower ) ;
m_is_removed = !n["gd:deleted"].empty() || !n["docs:removed"].empty() ;
}
const std::vector<std::string>& Entry::ParentHrefs() const
@ -147,6 +152,11 @@ std::string Entry::SelfHref() const
return m_self_href ;
}
std::string Entry::AltSelf() const
{
return m_alt_self ;
}
std::string Entry::ParentHref() const
{
return m_parent_hrefs.empty() ? "" : m_parent_hrefs.front() ;
@ -189,6 +199,7 @@ void Entry::Swap( Entry& e )
m_parent_hrefs.swap( e.m_parent_hrefs ) ;
m_self_href.swap( e.m_self_href ) ;
m_alt_self.swap( e.m_alt_self ) ;
m_content_src.swap( e.m_content_src ) ;
m_edit_link.swap( e.m_edit_link ) ;
m_create_link.swap( e.m_create_link ) ;
@ -196,6 +207,7 @@ void Entry::Swap( Entry& e )
m_mtime.Swap( e.m_mtime ) ;
std::swap( m_change_stamp, e.m_change_stamp ) ;
std::swap( m_is_removed, e.m_is_removed ) ;
}
long Entry::ChangeStamp() const
@ -203,4 +215,9 @@ long Entry::ChangeStamp() const
return m_change_stamp ;
}
bool Entry::IsRemoved() const
{
return m_is_removed ;
}
} // end of namespace

View File

@ -59,6 +59,7 @@ public :
std::string ETag() const ;
std::string SelfHref() const ;
std::string AltSelf() const ;
std::string ParentHref() const ;
std::string ContentSrc() const ;
std::string EditLink() const ;
@ -73,6 +74,8 @@ public :
long ChangeStamp() const ;
bool IsRemoved() const ;
private :
std::string m_title ;
std::string m_filename ;
@ -84,6 +87,7 @@ private :
std::vector<std::string> m_parent_hrefs ;
std::string m_self_href ;
std::string m_alt_self ;
std::string m_content_src ;
std::string m_edit_link ;
std::string m_create_link ;
@ -91,6 +95,7 @@ private :
long m_change_stamp ;
DateTime m_mtime ;
bool m_is_removed ;
} ;
} // end of namespace

View File

@ -33,6 +33,12 @@ Feed::Feed( const xml::Node& root ) :
{
}
void Feed::Assign( const xml::Node& root )
{
m_root = root ;
m_entries = m_root["entry"] ;
}
Feed::iterator Feed::begin() const
{
return iterator( m_entries.begin() ) ;

View File

@ -43,13 +43,14 @@ public :
public :
explicit Feed( const xml::Node& root ) ;
void Assign( const xml::Node& root ) ;
iterator begin() const ;
iterator end() const ;
std::string Next() const ;
bool GetNext( http::Agent *http, const http::Header& auth ) ;
private :
xml::Node m_root ;
xml::NodeSet m_entries ;

View File

@ -192,7 +192,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync )
m_state = local_changed ;
}
else
Trace( "file 1% state is %2%", Name(), m_state ) ;
Trace( "file %1% state is %2%", Name(), m_state ) ;
}
}

View File

@ -130,6 +130,19 @@ std::size_t State::TryResolveEntry()
return count ;
}
void State::FromChange( const Entry& e )
{
// entries in the change feed is always treated as remote newer,
// so we override the last sync time to 0
if ( Resource *res = m_res.FindByHref( e.AltSelf() ) )
{
Log( "found %1% in change %2%", res->Name(), e.ChangeStamp() ) ;
m_res.Update( res, e, DateTime() ) ;
}
else
Log( "can't found %1% %2%", e.Filename(), e.SelfHref() ) ;
}
bool State::Update( const Entry& e )
{
assert( !e.ParentHref().empty() ) ;
@ -181,7 +194,6 @@ Resource* State::Find( const fs::path& path )
return m_res.FindByPath( path ) ;
}
State::iterator State::begin()
{
return m_res.begin() ;

View File

@ -48,6 +48,7 @@ public :
void FromLocal( const fs::path& p ) ;
void FromRemote( const Entry& e ) ;
void FromChange( const Entry& e ) ;
void ResolveEntry() ;
void Read( const fs::path& filename ) ;