diff --git a/libgrive/src/drive/Entry.cc b/libgrive/src/drive/Entry.cc index 843e58f..9496633 100644 --- a/libgrive/src/drive/Entry.cc +++ b/libgrive/src/drive/Entry.cc @@ -51,24 +51,6 @@ Entry::Entry( const xml::Node& n ) : Update( n ) ; } -/// construct an entry from a file or folder in local directory -Entry::Entry( const std::string& name, const std::string& kind ) : - m_title ( name ), - m_filename ( name ), - m_kind ( kind ), - m_change_stamp( -1 ) -{ -} - -void Entry::FromLocal( const fs::path& path ) -{ - m_title = path.filename().string() ; - m_filename = path.filename().string() ; - m_kind = fs::is_directory(path) ? "folder" : "file" ; - m_md5 = fs::is_directory(path) ? "" : crypt::MD5::Get( path ) ; - m_mtime = fs::exists(path) ? os::FileCTime( path ) : DateTime() ; -} - void Entry::Update( const xml::Node& n ) { m_title = n["title"] ; @@ -104,24 +86,6 @@ const std::vector& Entry::ParentHrefs() const return m_parent_hrefs ; } -/// only assign the key members -void Entry::AssignID( const Entry& entry ) -{ - m_self_href = entry.m_self_href ; - m_content_src = entry.m_content_src ; - m_resource_id = entry.m_resource_id ; - m_parent_hrefs = entry.m_parent_hrefs ; - m_edit_link = entry.m_edit_link ; - m_create_link = entry.m_create_link ; - m_etag = entry.m_etag ; -} - -void Entry::Update( const std::string& md5, const DateTime& mtime ) -{ - m_mtime = mtime ; - m_md5 = md5 ; -} - std::string Entry::Title() const { return m_title ; diff --git a/libgrive/src/drive/Entry.hh b/libgrive/src/drive/Entry.hh index 3fa5ae7..5cd9e07 100644 --- a/libgrive/src/drive/Entry.hh +++ b/libgrive/src/drive/Entry.hh @@ -43,18 +43,16 @@ class Entry { public : Entry( ) ; - Entry( const std::string& name, const std::string& kind ) ; explicit Entry( const xml::Node& n ) ; - void AssignID( const Entry& entry ) ; - void FromLocal( const fs::path& path ) ; - std::string Title() const ; std::string Filename() const ; std::string Kind() const ; std::string MD5() const ; DateTime MTime() const ; + std::string Name() const ; + std::string ResourceID() const ; std::string ETag() const ; @@ -72,9 +70,6 @@ public : void Swap( Entry& e ) ; void Update( const xml::Node& entry ) ; - void Update( const std::string& md5, const DateTime& mtime ) ; - - std::string Name() const ; private : std::string m_title ; diff --git a/libgrive/src/drive/Resource.cc b/libgrive/src/drive/Resource.cc index b3ad663..ef6c891 100644 --- a/libgrive/src/drive/Resource.cc +++ b/libgrive/src/drive/Resource.cc @@ -19,6 +19,7 @@ #include "Resource.hh" #include "CommonUri.hh" +#include "Entry.hh" #include "http/Agent.hh" #include "http/Download.hh" @@ -56,15 +57,21 @@ const std::string xml_meta = /// default constructor creates the root folder Resource::Resource() : - m_parent( 0 ), - m_state ( sync ) + m_name ( "." ), + m_kind ( "folder" ), + m_id ( "folder:root" ), + m_href ( root_href ), + m_create ( root_create ), + m_parent ( 0 ), + m_state ( sync ) { } Resource::Resource( const std::string& name, const std::string& kind ) : - m_entry ( name, kind ), - m_parent( 0 ), - m_state ( unknown ) + m_name ( name ), + m_kind ( kind ), + m_parent ( 0 ), + m_state ( unknown ) { } @@ -125,11 +132,25 @@ void Resource::FromRemote( const Entry& remote, const DateTime& last_sync ) else FromRemoteFile( remote, last_sync ) ; - m_entry.AssignID( remote ) ; + AssignIDs( remote ) ; + assert( m_state != unknown ) ; if ( m_state == remote_new || m_state == remote_changed ) - m_entry.Update( remote.MD5(), remote.MTime() ) ; + { + m_md5 = remote.MD5() ; + m_mtime = remote.MTime() ; + } +} + +void Resource::AssignIDs( const Entry& remote ) +{ + m_id = remote.ResourceID() ; + m_href = remote.SelfHref() ; + m_edit = remote.EditLink() ; + m_create = remote.CreateLink() ; + m_content = remote.ContentSrc() ; + m_etag = remote.ETag() ; } void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) @@ -170,7 +191,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) } // if checksum is equal, no need to compare the mtime - else if ( remote.MD5() == m_entry.MD5() ) + else if ( remote.MD5() == m_md5 ) { Log( "file %1% is already in sync", Path(), log::verbose ) ; m_state = sync ; @@ -182,7 +203,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync ) assert( m_state == local_new || m_state == local_changed || m_state == remote_deleted ) ; // if remote is modified - if ( remote.MTime() > m_entry.MTime() ) + if ( remote.MTime() > m_mtime ) { Log( "file %1% is changed in remote", path, log::verbose ) ; m_state = remote_changed ; @@ -195,7 +216,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%", m_name, m_state ) ; } } @@ -212,10 +233,13 @@ void Resource::FromLocal( const DateTime& last_sync ) // if the file is not created after last sync, assume file is // remote_deleted first, it will be updated to sync/remote_changed // in FromRemote() - DateTime mtime = os::FileCTime( path ) ; - m_state = ( mtime > last_sync ? local_new : remote_deleted ) ; + m_mtime = os::FileCTime( path ) ; + m_state = ( m_mtime > last_sync ? local_new : remote_deleted ) ; - m_entry.FromLocal( path ) ; +// m_entry.FromLocal( path ) ; + m_name = path.filename().string() ; + m_kind = fs::is_directory(path) ? "folder" : "file" ; + m_md5 = fs::is_directory(path) ? "" : crypt::MD5::Get( path ) ; } assert( m_state != unknown ) ; @@ -223,17 +247,17 @@ void Resource::FromLocal( const DateTime& last_sync ) std::string Resource::SelfHref() const { - return m_entry.SelfHref() ; + return m_href ; } std::string Resource::Name() const { - return m_entry.Name() ; + return m_name ; } std::string Resource::ResourceID() const { - return m_entry.ResourceID() ; + return m_id ; } const Resource* Resource::Parent() const @@ -260,7 +284,19 @@ void Resource::AddChild( Resource *child ) void Resource::Swap( Resource& coll ) { - m_entry.Swap( coll.m_entry ) ; + m_name.swap( coll.m_name ) ; + m_kind.swap( coll.m_kind ) ; + m_md5.swap( coll.m_md5 ) ; + m_etag.swap( coll.m_etag ) ; + m_id.swap( coll.m_id ) ; + + m_href.swap( coll.m_href ) ; + m_content.swap( coll.m_content ) ; + m_edit.swap( coll.m_edit ) ; + m_create.swap( coll.m_create ) ; + + m_mtime.Swap( coll.m_mtime ) ; + std::swap( m_parent, coll.m_parent ) ; m_child.swap( coll.m_child ) ; std::swap( m_state, coll.m_state ) ; @@ -268,7 +304,7 @@ void Resource::Swap( Resource& coll ) bool Resource::IsFolder() const { - return m_entry.Kind() == "folder" ; + return m_kind == "folder" ; } fs::path Resource::Path() const @@ -276,7 +312,7 @@ fs::path Resource::Path() const assert( m_parent != this ) ; assert( m_parent == 0 || m_parent->IsFolder() ) ; - return m_parent != 0 ? (m_parent->Path() / Name()) : "." ; + return m_parent != 0 ? (m_parent->Path() / m_name) : "." ; } bool Resource::IsInRootTree() const @@ -290,7 +326,7 @@ Resource* Resource::FindChild( const std::string& name ) for ( std::vector::iterator i = m_child.begin() ; i != m_child.end() ; ++i ) { assert( (*i)->m_parent == this ) ; - if ( (*i)->Name() == name ) + if ( (*i)->m_name == name ) return *i ; } return 0 ; @@ -389,14 +425,14 @@ void Resource::DeleteRemote( http::Agent *http, const http::Header& auth ) try { http::Header hdr( auth ) ; - hdr.Add( "If-Match: " + m_entry.ETag() ) ; + hdr.Add( "If-Match: " + m_etag ) ; // doesn't know why, but an update before deleting seems to work always http::XmlResponse xml ; - http->Get( m_entry.SelfHref(), &xml, hdr ) ; - m_entry.Update( xml.Response() ) ; + http->Get( m_href, &xml, hdr ) ; + AssignIDs( Entry( xml.Response() ) ) ; - http->Custom( "DELETE", m_entry.SelfHref(), &str, hdr ) ; + http->Custom( "DELETE", m_href, &str, hdr ) ; } catch ( Exception& e ) { @@ -412,11 +448,11 @@ void Resource::DeleteRemote( http::Agent *http, const http::Header& auth ) void Resource::Download( http::Agent* http, const fs::path& file, const http::Header& auth ) const { http::Download dl( file.string(), http::Download::NoChecksum() ) ; - long r = http->Get( m_entry.ContentSrc(), &dl, auth ) ; + long r = http->Get( m_content, &dl, auth ) ; if ( r <= 400 ) { - assert( m_entry.MTime() != DateTime() ) ; - os::SetFileTime( file, m_entry.MTime() ) ; + assert( m_mtime != DateTime() ) ; + os::SetFileTime( file, m_mtime ) ; } } @@ -429,13 +465,13 @@ bool Resource::EditContent( http::Agent* http, const http::Header& auth ) m_parent->Sync( http, auth ) ; // upload link missing means that file is read only - if ( m_entry.EditLink().empty() ) + if ( m_edit.empty() ) { - Log( "Cannot upload %1%: file read-only. %2%", m_entry.Title(), m_state, log::warning ) ; + Log( "Cannot upload %1%: file read-only. %2%", m_name, m_state, log::warning ) ; return false ; } - return Upload( http, m_entry.EditLink(), auth, false ) ; + return Upload( http, m_edit, auth, false ) ; } bool Resource::Create( http::Agent* http, const http::Header& auth ) @@ -451,7 +487,7 @@ bool Resource::Create( http::Agent* http, const http::Header& auth ) { std::string uri = feed_base ; if ( !m_parent->IsRoot() ) - uri += ("/" + http->Escape(m_parent->ResourceID()) + "/contents") ; + uri += ("/" + http->Escape(m_parent->m_id) + "/contents") ; std::string meta = (boost::format(xml_meta) % "folder" % Name() ).str() ; @@ -461,17 +497,17 @@ bool Resource::Create( http::Agent* http, const http::Header& auth ) http::XmlResponse xml ; // http::ResponseLog log( "create", ".xml", &xml ) ; http->Post( uri, meta, &xml, hdr ) ; - m_entry.Update( xml.Response() ) ; + AssignIDs( Entry( xml.Response() ) ) ; return true ; } - else if ( !m_parent->m_entry.CreateLink().empty() ) + else if ( !m_parent->m_create.empty() ) { - return Upload( http, m_parent->m_entry.CreateLink() + "?convert=false", auth, true ) ; + return Upload( http, m_parent->m_create + "?convert=false", auth, true ) ; } else { - Log( "parent of %1% does not exist: cannot upload", Name() ) ; + Log( "parent of %1% does not exist: cannot upload", Name(), log::warning ) ; return false ; } } @@ -494,12 +530,12 @@ bool Resource::Upload( http::Agent* http, const std::string& link, const http::H hdr.Add( "Content-Type: application/atom+xml" ) ; hdr.Add( "X-Upload-Content-Type: application/octet-stream" ) ; hdr.Add( xcontent_len.str() ) ; - hdr.Add( "If-Match: " + m_entry.ETag() ) ; + hdr.Add( "If-Match: " + m_etag ) ; hdr.Add( "Expect:" ) ; std::string meta = (boost::format( xml_meta ) - % m_entry.Kind() - % xml::Escape(Name()) + % m_kind + % xml::Escape(m_name) ).str() ; http::StringResponse str ; @@ -517,36 +553,11 @@ bool Resource::Upload( http::Agent* http, const std::string& link, const http::H http::XmlResponse xml ; http->Put( uplink, data, &xml, uphdr ) ; - m_entry.Update( xml.Response() ) ; + AssignIDs( Entry( xml.Response() ) ) ; return true ; } -Json Resource::Serialize() const -{ - Json result ; - result.Add( "name", Json(Name()) ) ; - result.Add( "id", Json(ResourceID()) ) ; - result.Add( "href", Json(SelfHref()) ) ; - result.Add( "md5", Json(m_entry.MD5()) ) ; - result.Add( "kind", Json(m_entry.Kind()) ) ; - - Json mtime ; - mtime.Add( "sec", Json(m_entry.MTime().Sec() ) ); - mtime.Add( "nsec", Json(m_entry.MTime().NanoSec() ) ); - - result.Add( "mtime",mtime ) ; - - std::vector array ; - for ( std::vector::const_iterator i = m_child.begin() ; i != m_child.end() ; ++i ) - array.push_back( (*i)->Serialize() ) ; - - result.Add( "child", Json(array) ) ; - - return result ; - -} - Resource::iterator Resource::begin() const { return m_child.begin() ; @@ -587,7 +598,7 @@ bool Resource::IsRoot() const bool Resource::HasID() const { - return !m_entry.SelfHref().empty() && !m_entry.ResourceID().empty() ; + return !m_href.empty() && !m_id.empty() ; } } // end of namespace diff --git a/libgrive/src/drive/Resource.hh b/libgrive/src/drive/Resource.hh index 91a0d01..3668cc6 100644 --- a/libgrive/src/drive/Resource.hh +++ b/libgrive/src/drive/Resource.hh @@ -19,7 +19,7 @@ #pragma once -#include "Entry.hh" +#include "util/DateTime.hh" #include "util/Exception.hh" #include "util/FileSystem.hh" @@ -35,7 +35,7 @@ namespace http class Header ; } -class Json ; +class Entry ; /*! \brief A resource can be a file or a folder in the google drive @@ -78,8 +78,6 @@ public : void Sync( gr::http::Agent* http, const http::Header& auth ) ; - Json Serialize() const ; - // children access iterator begin() const ; iterator end() const ; @@ -134,9 +132,21 @@ private : void DeleteLocal() ; void DeleteRemote( http::Agent* http, const http::Header& auth ) ; -private : - Entry m_entry ; + void AssignIDs( const Entry& remote ) ; +private : + std::string m_name ; + std::string m_kind ; + std::string m_md5 ; + DateTime m_mtime ; + + std::string m_id ; + std::string m_href ; + std::string m_edit ; + std::string m_create ; + std::string m_content ; + std::string m_etag ; + // not owned Resource *m_parent ; std::vector m_child ; diff --git a/libgrive/src/drive/State.cc b/libgrive/src/drive/State.cc index 33b1fee..1de13ae 100644 --- a/libgrive/src/drive/State.cc +++ b/libgrive/src/drive/State.cc @@ -19,6 +19,7 @@ #include "State.hh" +#include "Entry.hh" #include "Resource.hh" #include "CommonUri.hh" @@ -52,6 +53,10 @@ State::State( const fs::path& filename, const Json& options ) : Log( "last sync time: %1%", m_last_sync, log::verbose ) ; } +State::~State() +{ +} + /// Synchronize local directory. Build up the resource tree from files and folders /// of local directory. void State::FromLocal( const fs::path& p ) diff --git a/libgrive/src/drive/State.hh b/libgrive/src/drive/State.hh index 1be9cde..6001f20 100644 --- a/libgrive/src/drive/State.hh +++ b/libgrive/src/drive/State.hh @@ -45,6 +45,7 @@ public : public : explicit State( const fs::path& filename, const Json& options ) ; + ~State() ; void FromLocal( const fs::path& p ) ; void FromRemote( const Entry& e ) ;