mirror of https://github.com/vitalif/grive2
added state to drive
parent
6dd505f8a6
commit
57fb6d3b0e
|
@ -114,7 +114,7 @@ int main( int argc, char **argv )
|
|||
try
|
||||
{
|
||||
OAuth2 token( refresh_token, client_id, client_secret ) ;
|
||||
Drive drive( token, config.Get() ) ;
|
||||
Drive drive( token ) ;
|
||||
|
||||
drive.Update() ;
|
||||
|
||||
|
|
|
@ -49,17 +49,18 @@
|
|||
|
||||
namespace gr {
|
||||
|
||||
Drive::Drive( OAuth2& auth, const Json& state ) :
|
||||
namespace
|
||||
{
|
||||
const std::string state_file = ".grive_state" ;
|
||||
}
|
||||
|
||||
Drive::Drive( OAuth2& auth ) :
|
||||
m_auth( auth ),
|
||||
m_state( state )
|
||||
m_state( state_file )
|
||||
{
|
||||
m_http_hdr.push_back( "Authorization: Bearer " + m_auth.AccessToken() ) ;
|
||||
m_http_hdr.push_back( "GData-Version: 3.0" ) ;
|
||||
|
||||
std::string prev_change_stamp ;
|
||||
if ( m_state.Has( "change_stamp" ) )
|
||||
prev_change_stamp = m_state["change_stamp"].Str() ;
|
||||
|
||||
http::Agent http ;
|
||||
http::XmlResponse xrsp ;
|
||||
http.Get( feed_metadata, &xrsp, m_http_hdr ) ;
|
||||
|
@ -67,7 +68,8 @@ Drive::Drive( OAuth2& auth, const Json& state ) :
|
|||
std::string change_stamp = xrsp.Response()["docs:largestChangestamp"]["@value"] ;
|
||||
Trace( "change stamp is %1%", change_stamp ) ;
|
||||
|
||||
m_state.Add( "change_stamp", Json( change_stamp ) ) ;
|
||||
m_state.ChangeStamp( change_stamp ) ;
|
||||
m_state.Sync( "." ) ;
|
||||
|
||||
ConstructDirTree( &http ) ;
|
||||
|
||||
|
@ -122,6 +124,8 @@ Drive::Drive( OAuth2& auth, const Json& state ) :
|
|||
resp = xrsp.Response() ;
|
||||
}
|
||||
} while ( has_next ) ;
|
||||
|
||||
m_state.Write( state_file ) ;
|
||||
}
|
||||
|
||||
Drive::~Drive( )
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Collection.hh"
|
||||
#include "State.hh"
|
||||
|
||||
#include "protocol/Json.hh"
|
||||
#include "util/Exception.hh"
|
||||
|
@ -48,14 +49,12 @@ public :
|
|||
typedef std::vector<Collection>::iterator FolderListIterator ;
|
||||
|
||||
public :
|
||||
Drive( OAuth2& auth, const Json& state ) ;
|
||||
Drive( OAuth2& auth ) ;
|
||||
~Drive( ) ;
|
||||
|
||||
void Update() ;
|
||||
void Sync() ;
|
||||
|
||||
Json State() const ;
|
||||
|
||||
struct Error : virtual Exception {} ;
|
||||
|
||||
private :
|
||||
|
@ -75,7 +74,7 @@ private :
|
|||
FolderList m_coll ;
|
||||
std::vector<File*> m_files ;
|
||||
|
||||
Json m_state ;
|
||||
State m_state ;
|
||||
} ;
|
||||
|
||||
} // end of namespace
|
||||
|
|
|
@ -23,13 +23,110 @@
|
|||
#include "util/Log.hh"
|
||||
#include "protocol/Json.hh"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/identity.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace gr {
|
||||
|
||||
namespace fs = boost::filesystem ;
|
||||
|
||||
State::State( const std::string& filename ) :
|
||||
m_db( filename )
|
||||
namespace
|
||||
{
|
||||
struct Resource
|
||||
{
|
||||
std::string id ;
|
||||
fs::path path ;
|
||||
std::string md5sum ;
|
||||
std::time_t mtime ;
|
||||
|
||||
explicit Resource( const fs::path& p ) :
|
||||
path( p ),
|
||||
md5sum( crypt::MD5( p ) ),
|
||||
mtime( fs::last_write_time( p ) )
|
||||
{
|
||||
}
|
||||
|
||||
explicit Resource( const Json& json ) :
|
||||
id( json["id"].Str() ),
|
||||
path( json["path"].Str() ),
|
||||
md5sum( json["md5"].Str() ),
|
||||
mtime( json["mtime"].Int() )
|
||||
{
|
||||
}
|
||||
|
||||
Json Get() const
|
||||
{
|
||||
Json entry ;
|
||||
entry.Add( "id", Json( id ) ) ;
|
||||
entry.Add( "path", Json( path.string() ) ) ;
|
||||
entry.Add( "md5", Json( md5sum ) ) ;
|
||||
entry.Add( "mtime", Json( mtime ) ) ;
|
||||
return entry ;
|
||||
}
|
||||
} ;
|
||||
|
||||
struct PathHash
|
||||
{
|
||||
std::size_t operator()( const fs::path& p ) const
|
||||
{
|
||||
return boost::hash_value( p.string() ) ;
|
||||
}
|
||||
} ;
|
||||
|
||||
using namespace boost::multi_index ;
|
||||
|
||||
struct ById {} ;
|
||||
struct ByPath {} ;
|
||||
|
||||
typedef multi_index_container<
|
||||
Resource,
|
||||
indexed_by<
|
||||
hashed_non_unique< tag<ById>, member<Resource, std::string, &Resource::id> >,
|
||||
hashed_unique< tag<ByPath>,member<Resource, fs::path, &Resource::path>, PathHash >
|
||||
>
|
||||
> ResourceSet ;
|
||||
|
||||
typedef ResourceSet::index<ById>::type IdIdx ;
|
||||
typedef ResourceSet::index<ByPath>::type PathIdx ;
|
||||
}
|
||||
|
||||
struct State::Impl
|
||||
{
|
||||
ResourceSet rs ;
|
||||
std::string change_stamp ;
|
||||
} ;
|
||||
|
||||
State::State( const fs::path& filename ) :
|
||||
m_impl( new Impl )
|
||||
{
|
||||
if ( fs::exists( filename ) )
|
||||
Read( filename );
|
||||
}
|
||||
|
||||
void State::Read( const fs::path& filename )
|
||||
{
|
||||
Trace( "reading %1%", filename ) ;
|
||||
Json json = Json::ParseFile( filename.string() ) ;
|
||||
std::vector<Json> res = json["resources"].AsArray() ;
|
||||
|
||||
for ( std::vector<Json>::iterator i = res.begin() ; i != res.end() ; ++i )
|
||||
m_impl->rs.insert( Resource( *i ) ) ;
|
||||
|
||||
m_impl->change_stamp = json["change_stamp"].Str() ;
|
||||
}
|
||||
|
||||
std::string State::ChangeStamp() const
|
||||
{
|
||||
return m_impl->change_stamp ;
|
||||
}
|
||||
|
||||
void State::ChangeStamp( const std::string& cs )
|
||||
{
|
||||
m_impl->change_stamp = cs ;
|
||||
}
|
||||
|
||||
void State::Sync( const fs::path& p )
|
||||
|
@ -37,27 +134,33 @@ void State::Sync( const fs::path& p )
|
|||
for ( fs::directory_iterator i( p ) ; i != fs::directory_iterator() ; ++i )
|
||||
{
|
||||
Trace( "file found = %1%", i->path() ) ;
|
||||
|
||||
std::string json = m_db.Get( i->path().string() ) ;
|
||||
if ( json.empty() )
|
||||
{
|
||||
Trace( "create new entry" ) ;
|
||||
json = FileInfo(p).Str() ;
|
||||
}
|
||||
else
|
||||
{
|
||||
Json j = Json::Parse( json ) ;
|
||||
if ( j["mtime"].Int() != fs::last_write_time(p) )
|
||||
{
|
||||
Trace( "file changed" ) ;
|
||||
json = FileInfo(p).Str() ;
|
||||
}
|
||||
}
|
||||
|
||||
m_db.Set( i->path().string(), json ) ;
|
||||
if ( fs::is_directory( i->path() ) )
|
||||
Sync( *i ) ;
|
||||
else if ( i->path().filename().string()[0] != '.' )
|
||||
m_impl->rs.insert( Resource( i->path() ) ) ;
|
||||
}
|
||||
}
|
||||
|
||||
void State::Write( const fs::path& filename ) const
|
||||
{
|
||||
Json result ;
|
||||
result.Add( "change_stamp", Json( m_impl->change_stamp ) ) ;
|
||||
|
||||
IdIdx& idx = m_impl->rs.get<ById>() ;
|
||||
|
||||
std::vector<Json> res ;
|
||||
std::transform( idx.begin(), idx.end(),
|
||||
std::back_inserter(res),
|
||||
boost::bind( &Resource::Get, _1 ) ) ;
|
||||
|
||||
result.Add( "resources", Json(res) ) ;
|
||||
|
||||
Trace( "%1%", result ) ;
|
||||
|
||||
std::ofstream fs( filename.string().c_str() ) ;
|
||||
fs << result ;
|
||||
}
|
||||
|
||||
Json State::FileInfo( const boost::filesystem::path& p )
|
||||
{
|
||||
Json info ;
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "util/Gdbm.hh"
|
||||
#include "util/FileSystem.hh"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace gr {
|
||||
|
||||
|
@ -30,15 +30,22 @@ class Json ;
|
|||
class State
|
||||
{
|
||||
public :
|
||||
explicit State( const std::string& filename ) ;
|
||||
explicit State( const fs::path& filename ) ;
|
||||
|
||||
void Sync( const boost::filesystem::path& p ) ;
|
||||
void Sync( const fs::path& p ) ;
|
||||
|
||||
void Read( const fs::path& filename ) ;
|
||||
void Write( const fs::path& filename ) const ;
|
||||
|
||||
private :
|
||||
static Json FileInfo( const boost::filesystem::path& p ) ;
|
||||
std::string ChangeStamp() const ;
|
||||
void ChangeStamp( const std::string& cs ) ;
|
||||
|
||||
private :
|
||||
Gdbm m_db ;
|
||||
static Json FileInfo( const fs::path& p ) ;
|
||||
|
||||
private :
|
||||
struct Impl ;
|
||||
std::auto_ptr<Impl> m_impl ;
|
||||
} ;
|
||||
|
||||
} // end of namespace
|
||||
|
|
|
@ -64,6 +64,17 @@ Json::Json( const long& l ) :
|
|||
throw Error() << expt::ErrMsg( "cannot create json int" ) ;
|
||||
}
|
||||
|
||||
template <>
|
||||
Json::Json( const std::vector<Json>& arr ) :
|
||||
m_json( ::json_object_new_array( ) )
|
||||
{
|
||||
if ( m_json == 0 )
|
||||
throw Error() << expt::ErrMsg( "cannot create json int" ) ;
|
||||
|
||||
for ( std::vector<Json>::const_iterator i = arr.begin() ; i != arr.end() ; ++i )
|
||||
Add( *i ) ;
|
||||
}
|
||||
|
||||
Json Json::Parse( const std::string& str )
|
||||
{
|
||||
struct json_object *json = ::json_tokener_parse( str.c_str() ) ;
|
||||
|
@ -176,6 +187,15 @@ void Json::Add( const std::string& key, const Json& json )
|
|||
::json_object_object_add( m_json, key.c_str(), json.m_json ) ;
|
||||
}
|
||||
|
||||
void Json::Add( const Json& json )
|
||||
{
|
||||
assert( m_json != 0 ) ;
|
||||
assert( json.m_json != 0 ) ;
|
||||
|
||||
::json_object_get( json.m_json ) ;
|
||||
::json_object_array_add( m_json, json.m_json ) ;
|
||||
}
|
||||
|
||||
bool Json::Bool() const
|
||||
{
|
||||
assert( m_json != 0 ) ;
|
||||
|
|
|
@ -66,6 +66,7 @@ public :
|
|||
|
||||
bool Has( const std::string& key ) const ;
|
||||
void Add( const std::string& key, const Json& json ) ;
|
||||
void Add( const Json& json ) ;
|
||||
Json FindInArray( const std::string& key, const std::string& value ) const ;
|
||||
bool FindInArray( const std::string& key, const std::string& value, Json& result ) const ;
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
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 <boost/filesystem.hpp>
|
||||
|
||||
namespace gr
|
||||
{
|
||||
namespace fs = boost::filesystem ;
|
||||
}
|
|
@ -37,6 +37,7 @@ void StateTest::TestSync( )
|
|||
{
|
||||
State s( ".grive_state" ) ;
|
||||
s.Sync( TEST_DATA ) ;
|
||||
s.Write( "" ) ;
|
||||
}
|
||||
|
||||
} // end of namespace grut
|
||||
|
|
Loading…
Reference in New Issue