mirror of https://github.com/vitalif/grive2
merged the File class to Resource
parent
50e3091b2a
commit
7882198293
|
@ -30,7 +30,6 @@
|
|||
#include "protocol/OAuth2.hh"
|
||||
#include "util/Destroy.hh"
|
||||
#include "util/Log.hh"
|
||||
//#include "util/Path.hh"
|
||||
#include "xml/Node.hh"
|
||||
#include "xml/NodeSet.hh"
|
||||
|
||||
|
@ -229,11 +228,11 @@ void Drive::UpdateFile( Entry& entry, Resource& parent, http::Agent *http )
|
|||
// only handle uploaded files
|
||||
if ( !entry.Filename().empty() )
|
||||
{
|
||||
File *file = new File( entry, &parent ) ;
|
||||
Resource *file = new Resource( entry, &parent ) ;
|
||||
m_files.push_back( file ) ;
|
||||
parent.AddLeaf( file ) ;
|
||||
|
||||
// Trace( "%1% ID = %2%", file->Path(), file->ResourceID() ) ;
|
||||
Trace( "%1% ID = %2%", file->Path(), file->ResourceID() ) ;
|
||||
|
||||
// m_state.SetId( file->Path(), file->ResourceID() ) ;
|
||||
|
||||
|
@ -247,9 +246,11 @@ void Drive::UpdateFile( Entry& entry, Resource& parent, http::Agent *http )
|
|||
|
||||
void Drive::Update()
|
||||
{
|
||||
Trace( "updating %1% files", m_files.size() ) ;
|
||||
|
||||
http::Agent http ;
|
||||
std::for_each( m_files.begin(), m_files.end(),
|
||||
boost::bind( &File::Update, _1, &http, m_http_hdr ) ) ;
|
||||
boost::bind( &Resource::Update, _1, &http, m_http_hdr ) ) ;
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
|
|
@ -72,7 +72,7 @@ private :
|
|||
std::string m_resume_link ;
|
||||
|
||||
FolderList m_coll ;
|
||||
std::vector<File*> m_files ;
|
||||
std::vector<Resource*> m_files ;
|
||||
|
||||
State m_state ;
|
||||
} ;
|
||||
|
|
|
@ -48,7 +48,7 @@ void File::Update( http::Agent *http, const http::Headers& auth )
|
|||
assert( m_parent != 0 ) ;
|
||||
|
||||
bool changed = true ;
|
||||
fs::path path = m_parent->Dir() / m_entry.Filename() ;
|
||||
fs::path path = Path() ;
|
||||
|
||||
// compare checksum first if file exists
|
||||
std::ifstream ifile( path.string().c_str(), std::ios::binary | std::ios::in ) ;
|
||||
|
@ -149,7 +149,7 @@ bool File::Upload( http::Agent* http, std::streambuf *file, const http::Headers&
|
|||
fs::path File::Path() const
|
||||
{
|
||||
assert( m_parent != 0 ) ;
|
||||
return m_parent->Dir() / m_entry.Filename() ;
|
||||
return m_parent->Path() / m_entry.Filename() ;
|
||||
}
|
||||
|
||||
std::string File::ResourceID() const
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "util/Destroy.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace gr {
|
||||
|
||||
|
@ -34,7 +35,8 @@ FolderSet::FolderSet( ) :
|
|||
m_set.insert( m_root ) ;
|
||||
}
|
||||
|
||||
FolderSet::FolderSet( const FolderSet& fs )
|
||||
FolderSet::FolderSet( const FolderSet& fs ) :
|
||||
m_root( 0 )
|
||||
{
|
||||
const Set& s = fs.m_set.get<ByIdentity>() ;
|
||||
for ( Set::const_iterator i = s.begin() ; i != s.end() ; ++i )
|
||||
|
@ -45,6 +47,8 @@ FolderSet::FolderSet( const FolderSet& fs )
|
|||
|
||||
m_set.insert( c ) ;
|
||||
}
|
||||
|
||||
assert( m_root != 0 ) ;
|
||||
}
|
||||
|
||||
FolderSet::~FolderSet( )
|
||||
|
@ -56,11 +60,13 @@ FolderSet::~FolderSet( )
|
|||
|
||||
Resource* FolderSet::Root()
|
||||
{
|
||||
assert( m_root != 0 ) ;
|
||||
return m_root ;
|
||||
}
|
||||
|
||||
const Resource* FolderSet::Root() const
|
||||
{
|
||||
assert( m_root != 0 ) ;
|
||||
return m_root ;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,17 @@
|
|||
#include "Resource.hh"
|
||||
#include "CommonUri.hh"
|
||||
|
||||
#include "http/Download.hh"
|
||||
#include "http/StringResponse.hh"
|
||||
#include "http/XmlResponse.hh"
|
||||
#include "util/Crypt.hh"
|
||||
#include "util/Log.hh"
|
||||
#include "util/OS.hh"
|
||||
#include "xml/Node.hh"
|
||||
#include "xml/NodeSet.hh"
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
|
||||
// for debugging
|
||||
#include <iostream>
|
||||
|
@ -37,9 +43,9 @@ Resource::Resource( const xml::Node& entry ) :
|
|||
{
|
||||
}
|
||||
|
||||
Resource::Resource( const Entry& entry ) :
|
||||
Resource::Resource( const Entry& entry, Resource *parent ) :
|
||||
m_entry ( entry ),
|
||||
m_parent ( 0 )
|
||||
m_parent ( parent )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -96,8 +102,10 @@ void Resource::AddChild( Resource *child )
|
|||
m_child.push_back( child ) ;
|
||||
}
|
||||
|
||||
void Resource::AddLeaf( File *file )
|
||||
void Resource::AddLeaf( Resource *file )
|
||||
{
|
||||
assert( file != 0 ) ;
|
||||
assert( !file->IsFolder() ) ;
|
||||
m_leaf.push_back( file ) ;
|
||||
}
|
||||
|
||||
|
@ -112,19 +120,30 @@ void Resource::Swap( Resource& coll )
|
|||
void Resource::CreateSubDir( const fs::path& prefix )
|
||||
{
|
||||
fs::path dir = prefix / m_entry.Title() ;
|
||||
// Trace( "dir = %1%, path = %2%", dir, Path() ) ;
|
||||
// assert( dir == Path() ) ;
|
||||
|
||||
fs::create_directories( dir ) ;
|
||||
|
||||
for ( std::vector<Resource*>::iterator i = m_child.begin() ; i != m_child.end() ; ++i )
|
||||
{
|
||||
assert( (*i)->m_parent == this ) ;
|
||||
(*i)->CreateSubDir( dir ) ;
|
||||
if ( (*i)->IsFolder() )
|
||||
(*i)->CreateSubDir( dir ) ;
|
||||
}
|
||||
}
|
||||
|
||||
fs::path Resource::Dir() const
|
||||
bool Resource::IsFolder() const
|
||||
{
|
||||
return m_entry.Kind() == "folder" ;
|
||||
}
|
||||
|
||||
fs::path Resource::Path() const
|
||||
{
|
||||
assert( m_parent != this ) ;
|
||||
return m_parent != 0 ? (m_parent->Dir() / m_entry.Title()) : "." ;
|
||||
std::string name = (IsFolder() ? m_entry.Title() : m_entry.Filename() ) ;
|
||||
|
||||
return m_parent != 0 ? (m_parent->Path() / name) : "." ;
|
||||
}
|
||||
|
||||
bool Resource::IsInRootTree() const
|
||||
|
@ -143,6 +162,112 @@ Resource* Resource::FindChild( const std::string& title )
|
|||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
void Resource::Update( http::Agent *http, const http::Headers& auth )
|
||||
{
|
||||
assert( m_parent != 0 ) ;
|
||||
|
||||
bool changed = true ;
|
||||
fs::path path = Path() ;
|
||||
|
||||
Trace( "updating %1%", path ) ;
|
||||
|
||||
// compare checksum first if file exists
|
||||
std::ifstream ifile( path.string().c_str(), std::ios::binary | std::ios::in ) ;
|
||||
if ( ifile && m_entry.ServerMD5() == crypt::MD5(ifile.rdbuf()) )
|
||||
changed = false ;
|
||||
|
||||
// if the checksum is different, file is changed and we need to update
|
||||
if ( changed )
|
||||
{
|
||||
DateTime remote = m_entry.ServerModified() ;
|
||||
DateTime local = ifile ? os::FileMTime( path ) : DateTime() ;
|
||||
|
||||
// remote file is newer, download file
|
||||
if ( !ifile || remote > local )
|
||||
Download( http, path, auth ) ;
|
||||
|
||||
else
|
||||
{
|
||||
// re-reading the file
|
||||
ifile.seekg(0) ;
|
||||
Upload( http, ifile.rdbuf(), auth ) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::Delete( http::Agent *http, const http::Headers& auth )
|
||||
{
|
||||
http::Headers hdr( auth ) ;
|
||||
hdr.push_back( "If-Match: " + m_entry.ETag() ) ;
|
||||
|
||||
http::StringResponse str ;
|
||||
http->Custom( "DELETE", feed_base + "/" + m_entry.ResourceID() + "?delete=true", &str, hdr ) ;
|
||||
}
|
||||
|
||||
|
||||
void Resource::Download( http::Agent* http, const fs::path& file, const http::Headers& auth ) const
|
||||
{
|
||||
Log( "Downloading %1%", file ) ;
|
||||
http::Download dl( file.string(), http::Download::NoChecksum() ) ;
|
||||
long r = http->Get( m_entry.ContentSrc(), &dl, auth ) ;
|
||||
if ( r <= 400 )
|
||||
os::SetFileTime( file, m_entry.ServerModified() ) ;
|
||||
}
|
||||
|
||||
bool Resource::Upload( http::Agent* http, std::streambuf *file, const http::Headers& auth )
|
||||
{
|
||||
// upload link missing means that file is read only
|
||||
if ( m_entry.UploadLink().empty() )
|
||||
{
|
||||
Log( "Cannot upload %1%: file read-only.", m_entry.Title(), log::warning ) ;
|
||||
return false ;
|
||||
}
|
||||
|
||||
Log( "Uploading %1%", m_entry.Title() ) ;
|
||||
|
||||
std::string meta =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
"<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:docs=\"http://schemas.google.com/docs/2007\">"
|
||||
"<category scheme=\"http://schemas.google.com/g/2005#kind\" "
|
||||
"term=\"http://schemas.google.com/docs/2007#file\"/>"
|
||||
"<title>" + m_entry.Filename() + "</title>"
|
||||
"</entry>" ;
|
||||
|
||||
std::string data(
|
||||
(std::istreambuf_iterator<char>(file)),
|
||||
(std::istreambuf_iterator<char>()) ) ;
|
||||
|
||||
std::ostringstream xcontent_len ;
|
||||
xcontent_len << "X-Upload-Content-Length: " << data.size() ;
|
||||
|
||||
http::Headers hdr( auth ) ;
|
||||
hdr.push_back( "Content-Type: application/atom+xml" ) ;
|
||||
hdr.push_back( "X-Upload-Content-Type: application/octet-stream" ) ;
|
||||
hdr.push_back( xcontent_len.str() ) ;
|
||||
hdr.push_back( "If-Match: " + m_entry.ETag() ) ;
|
||||
hdr.push_back( "Expect:" ) ;
|
||||
|
||||
http::StringResponse str ;
|
||||
http->Put( m_entry.UploadLink(), meta, &str, hdr ) ;
|
||||
|
||||
std::string uplink = http->RedirLocation() ;
|
||||
|
||||
// parse the header and find "Location"
|
||||
http::Headers uphdr ;
|
||||
uphdr.push_back( "Expect:" ) ;
|
||||
uphdr.push_back( "Accept:" ) ;
|
||||
|
||||
http::XmlResponse xml ;
|
||||
http->Put( uplink, data, &xml, uphdr ) ;
|
||||
|
||||
Trace( "Receipted response = %1%", xml.Response() ) ;
|
||||
|
||||
m_entry.Update( xml.Response() ) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
||||
namespace std
|
||||
|
|
|
@ -20,21 +20,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "Entry.hh"
|
||||
#include "http/Agent.hh"
|
||||
#include "util/Exception.hh"
|
||||
#include "util/FileSystem.hh"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace gr {
|
||||
|
||||
class File ;
|
||||
|
||||
class Resource
|
||||
{
|
||||
public :
|
||||
explicit Resource( const xml::Node& entry ) ;
|
||||
explicit Resource( const Entry& entry ) ;
|
||||
explicit Resource( const Entry& entry, Resource *parent = 0 ) ;
|
||||
Resource( const std::string& title, const std::string& href ) ;
|
||||
Resource( const std::string& title, Resource *parent ) ;
|
||||
|
||||
|
@ -42,15 +42,19 @@ public :
|
|||
|
||||
std::string Title() const ;
|
||||
std::string SelfHref() const ;
|
||||
std::string ResourceID() const ;
|
||||
|
||||
const Resource* Parent() const ;
|
||||
Resource* Parent() ;
|
||||
std::string ParentHref() const ;
|
||||
fs::path Dir() const ;
|
||||
|
||||
fs::path Path() const ;
|
||||
bool IsInRootTree() const ;
|
||||
std::string ResourceID() const ;
|
||||
|
||||
bool IsFolder() const ;
|
||||
|
||||
void AddChild( Resource *child ) ;
|
||||
void AddLeaf( File *file ) ;
|
||||
void AddLeaf( Resource *file ) ;
|
||||
|
||||
void Swap( Resource& coll ) ;
|
||||
|
||||
|
@ -62,13 +66,20 @@ public :
|
|||
Resource* FindChild( const std::string& title ) ;
|
||||
void Update( const Entry& e ) ;
|
||||
|
||||
void Update( http::Agent *http, const http::Headers& auth ) ;
|
||||
void Delete( http::Agent* http, const http::Headers& auth ) ;
|
||||
|
||||
private :
|
||||
void Download( http::Agent* http, const fs::path& file, const http::Headers& auth ) const ;
|
||||
bool Upload( http::Agent* http, std::streambuf *file, const http::Headers& auth ) ;
|
||||
|
||||
private :
|
||||
Entry m_entry ;
|
||||
|
||||
// not owned
|
||||
Resource *m_parent ;
|
||||
std::vector<Resource*> m_child ;
|
||||
std::vector<File*> m_leaf ;
|
||||
std::vector<Resource*> m_leaf ;
|
||||
} ;
|
||||
|
||||
} // end of namespace
|
||||
|
|
|
@ -38,66 +38,6 @@
|
|||
|
||||
namespace gr {
|
||||
|
||||
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 ;
|
||||
|
@ -117,13 +57,6 @@ State::State( const fs::path& 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
|
||||
|
@ -145,15 +78,14 @@ void State::Sync( const boost::filesystem3::path& p, gr::Resource* folder )
|
|||
{
|
||||
assert( folder != 0 ) ;
|
||||
|
||||
// Trace( "synchronizing = %1%", p ) ;
|
||||
for ( fs::directory_iterator i( p ) ; i != fs::directory_iterator() ; ++i )
|
||||
{
|
||||
// Trace( "file found = %2% (%1%)", i->path(), i->path().filename() ) ;
|
||||
if ( fs::is_directory( i->path() ) )
|
||||
{
|
||||
Resource *c = new Resource( i->path().filename().string(), "" ) ;
|
||||
folder->AddChild( c ) ;
|
||||
|
||||
m_impl->folders.Insert( c ) ;
|
||||
|
||||
Sync( *i, c ) ;
|
||||
}
|
||||
// else if ( i->path().filename().string()[0] != '.' )
|
||||
|
@ -166,42 +98,19 @@ 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 ;
|
||||
}
|
||||
|
||||
void State::SetId( const fs::path& p, const std::string& id )
|
||||
{
|
||||
// PathIdx& pidx = m_impl->rs.get<ByPath>() ;
|
||||
// PathIdx::iterator it = pidx.find( p ) ;
|
||||
// if ( it != pidx.end() )
|
||||
// {
|
||||
// Resource r = *it ;
|
||||
// r.id = id ;
|
||||
// pidx.replace( it, r ) ;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Trace( "can't find %1%", p ) ;
|
||||
// }
|
||||
}
|
||||
|
||||
void State::OnEntry( const Entry& e )
|
||||
{
|
||||
if ( !Update( e ) )
|
||||
{
|
||||
Trace( "can't find parent of %1%", e.Title() ) ;
|
||||
Trace( "can't resolve folder %1%", e.Title() ) ;
|
||||
m_impl->unresolved.push_back( e ) ;
|
||||
}
|
||||
}
|
||||
|
@ -230,6 +139,7 @@ std::size_t State::TryResolveEntry()
|
|||
|
||||
for ( std::vector<Entry>::iterator i = en.begin() ; i != en.end() ; )
|
||||
{
|
||||
Trace( "resolving %1%", i->Title() ) ;
|
||||
if ( Update( *i ) )
|
||||
{
|
||||
i = en.erase( i ) ;
|
||||
|
@ -261,7 +171,6 @@ bool State::Update( const Entry& e )
|
|||
{
|
||||
child = new Resource( e ) ;
|
||||
parent->AddChild( child ) ;
|
||||
m_impl->folders.Insert( child ) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue