build up data structures for the collections

pull/40/head
Matchman Green 2012-04-26 23:40:38 +08:00
parent e094e69d1a
commit 4001cbdbcc
14 changed files with 322 additions and 25 deletions

View File

@ -8,6 +8,7 @@ add_executable( grive
src/main.cc src/main.cc
src/OAuth2.cc src/OAuth2.cc
src/Drive.cc src/Drive.cc
src/Collection.cc
src/protocol/HTTP.cc src/protocol/HTTP.cc
src/protocol/Json.cc src/protocol/Json.cc
src/protocol/Download.cc ) src/protocol/Download.cc )

113
src/Collection.cc Normal file
View File

@ -0,0 +1,113 @@
/*
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 "Collection.hh"
#include "protocol/Json.hh"
// OS specific library
#include <sys/stat.h>
#include <sys/types.h>
// for debugging
#include <iostream>
namespace gr {
Collection::Collection( const Json& entry ) :
m_title ( entry["title"]["$t"].As<std::string>() ),
m_href ( entry["link"].FindInArray( "rel", "self" )["href"].As<std::string>() ),
m_parent ( Parent( entry ) )
{
std::cout << "title: " << m_title << " {" << m_parent << "}" << std::endl ;
}
Collection::Collection(
const std::string& title,
const std::string& href,
const std::string& parent ) :
m_title ( title ),
m_href ( href ),
m_parent( parent )
{
}
std::string Collection::Parent( const Json& entry )
{
Json node ;
return entry["link"].FindInArray( "rel", "http://schemas.google.com/docs/2007#parent", node ) ?
node["href"].As<std::string>() : std::string() ;
}
const std::string& Collection::Href() const
{
return m_href ;
}
const std::string& Collection::Title() const
{
return m_title ;
}
const std::string& Collection::Parent() const
{
return m_parent ;
}
void Collection::AddChild( Collection *child )
{
m_child.push_back( child ) ;
}
bool Collection::IsCollection( const Json& entry )
{
Json node ;
return
entry["category"].FindInArray( "scheme", "http://schemas.google.com/g/2005#kind", node ) &&
node["label"].As<std::string>() == "folder" ;
}
void Collection::Swap( Collection& coll )
{
m_title.swap( coll.m_title ) ;
m_href.swap( coll.m_href ) ;
m_child.swap( coll.m_child ) ;
}
void Collection::CreateSubDir( const std::string& prefix )
{
std::string dir = prefix + m_title ;
std::cout << dir << std::endl ;
mkdir( dir.c_str(), 0700 ) ;
for ( std::vector<Collection*>::iterator i = m_child.begin() ; i != m_child.end() ; ++i )
{
(*i)->CreateSubDir( prefix + m_title + "/" ) ;
}
}
} // end of namespace
namespace std
{
void swap( gr::Collection& c1, gr::Collection& c2 )
{
c1.Swap( c2 ) ;
}
}

66
src/Collection.hh Normal file
View File

@ -0,0 +1,66 @@
/*
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 <string>
#include <vector>
namespace gr {
class Json ;
class Collection
{
public :
explicit Collection( const Json& entry ) ;
Collection( const std::string& title, const std::string& href, const std::string& parent ) ;
// default copy ctor & op= are fine
static bool IsCollection( const Json& entry ) ;
const std::string& Title() const ;
const std::string& Href() const ;
const std::string& Parent() const ;
void AddChild( Collection *child ) ;
void Swap( Collection& coll ) ;
void CreateSubDir( const std::string& prefix ) ;
private :
static std::string Parent( const Json& entry ) ;
private :
std::string m_title ;
std::string m_href ;
std::string m_parent ;
// not owned
std::vector<Collection*> m_child ;
} ;
} // end of namespace
namespace std
{
void swap( gr::Collection& c1, gr::Collection& c2 ) ;
}

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
@ -23,18 +23,23 @@
#include "protocol/Json.hh" #include "protocol/Json.hh"
#include "OAuth2.hh" #include "OAuth2.hh"
// dependent libraries
#include <openssl/evp.h> #include <openssl/evp.h>
// standard C++ library
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
// for debugging only // for debugging only
#include <iostream> #include <iostream>
namespace gr { namespace gr {
const std::string root_url = "https://docs.google.com/feeds/default/private/full" ;
std::string MD5( std::streambuf *file ) std::string MD5( std::streambuf *file )
{ {
char buf[64 * 1024] ; char buf[64 * 1024] ;
@ -60,26 +65,89 @@ std::string MD5( std::streambuf *file )
} }
Drive::Drive( OAuth2& auth ) : Drive::Drive( OAuth2& auth ) :
m_auth( auth ) m_auth( auth ),
m_root( "", "https://docs.google.com/feeds/default/private/full/folder%3Aroot", "" )
{ {
m_http_hdr.push_back( "Authorization: Bearer " + m_auth.AccessToken() ) ; m_http_hdr.push_back( "Authorization: Bearer " + m_auth.AccessToken() ) ;
m_http_hdr.push_back( "GData-Version: 3.0" ) ; m_http_hdr.push_back( "GData-Version: 3.0" ) ;
Json resp = Json::Parse(HttpGet( "https://docs.google.com/feeds/default/private/full?alt=json", m_http_hdr )) ;
/* Json::Object map = resp["feed"]["id"].As<Json::Object>() ;
for ( Json::Object::iterator i = map.begin() ; i != map.end() ; ++i )
{
std::cout << i->first << "\t" << i->second.DataType() << std::endl ;
}*/
Json::Array a = resp["feed"]["entry"].As<Json::Array>() ; Json resp = Json::Parse(HttpGet( root_url + "?alt=json&showfolders=true", m_http_hdr )) ;
for ( Json::Array::iterator i = a.begin() ; i != a.end() ; ++i ) Json::Array entries = resp["feed"]["entry"].As<Json::Array>() ;
ConstructDirTree( entries ) ;
for ( Json::Array::iterator i = entries.begin() ; i != entries.end() ; ++i )
{ {
DownloadEntry( *i ) ; // DownloadEntry( *i ) ;
} }
} }
Drive::~Drive( )
{
}
std::string Drive::Kind( const Json& entry )
{
Json node ;
return entry["category"].FindInArray( "scheme", "http://schemas.google.com/g/2005#kind", node ) ?
node["label"].As<std::string>() : std::string() ;
}
struct SortCollectionByHref
{
bool operator()( const Collection& c1, const Collection& c2 ) const
{
return c1.Href() < c2.Href() ;
}
} ;
Drive::FolderListIterator Drive::FindFolder( const std::string& href )
{
// try to find the parent by its href
std::vector<Collection>::iterator it =
std::lower_bound(
m_coll.begin(),
m_coll.end(),
Collection( "", href, "" ),
SortCollectionByHref() ) ;
return it != m_coll.end() && it->Href() == href ? it : m_coll.end() ;
}
void Drive::ConstructDirTree( const std::vector<Json>& entries )
{
// first, get all collections from the query result
for ( Json::Array::const_iterator i = entries.begin() ; i != entries.end() ; ++i )
{
if ( Collection::IsCollection( *i ) )
m_coll.push_back( Collection( *i ) ) ;
}
// second, build up linkage between parent and child
std::sort( m_coll.begin(), m_coll.end(), SortCollectionByHref() ) ;
for ( FolderListIterator i = m_coll.begin() ; i != m_coll.end() ; ++i )
{
if ( i->Parent().empty() )
m_root.AddChild( &*i ) ;
else
{
FolderListIterator pit = FindFolder( i->Parent() ) ;
if ( pit != m_coll.end() )
pit->AddChild( &*i ) ;
}
}
// lastly, iterating from the root, create the directories in the local file system
m_root.CreateSubDir( "." ) ;
}
std::string Drive::Parent( const Json& entry )
{
Json node ;
return entry["link"].FindInArray( "ref", "http://schemas.google.com/docs/2007#parent", node ) ?
node["href"].As<std::string>() : std::string() ;
}
void Drive::DownloadEntry( const Json& entry ) void Drive::DownloadEntry( const Json& entry )
{ {
// Json::Object map = entry.As<Json::Object>() ; // Json::Object map = entry.As<Json::Object>() ;
@ -88,6 +156,8 @@ void Drive::DownloadEntry( const Json& entry )
// std::cout << i->first << "\t" << i->second.DataType() << std::endl ; // std::cout << i->first << "\t" << i->second.DataType() << std::endl ;
// } // }
Parent( entry ) ;
// only handle uploaded files // only handle uploaded files
if ( entry.Has( "docs$filename" ) ) if ( entry.Has( "docs$filename" ) )
{ {

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
@ -19,6 +19,8 @@
#pragma once #pragma once
#include "Collection.hh"
#include <string> #include <string>
#include <vector> #include <vector>
@ -29,15 +31,30 @@ class Json ;
class Drive class Drive
{ {
public :
typedef std::vector<Collection> FolderList ;
typedef std::vector<Collection>::iterator FolderListIterator ;
public : public :
Drive( OAuth2& auth ) ; Drive( OAuth2& auth ) ;
~Drive( ) ;
private : private :
void DownloadEntry( const Json& entry ) ; void DownloadEntry( const Json& entry ) ;
std::string Parent( const Json& entry ) ;
void ConstructDirTree( const std::vector<Json>& entries ) ;
static std::string Kind( const Json& entry ) ;
FolderListIterator FindFolder( const std::string& href ) ;
private : private :
OAuth2& m_auth ; OAuth2& m_auth ;
std::vector<std::string> m_http_hdr ; std::vector<std::string> m_http_hdr ;
FolderList m_coll ;
Collection m_root ;
} ; } ;
} // end of namespace } // end of namespace

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,

View File

@ -4,8 +4,8 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation version 2
of the License, or (at your option) any later version. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
@ -59,7 +59,7 @@ Json Json::Parse( const std::string& str )
Json::Json( struct json_object *json, NotOwned ) : Json::Json( struct json_object *json, NotOwned ) :
m_json( json ) m_json( json )
{ {
assert( json != 0 ) ; assert( m_json != 0 ) ;
} }
Json::Json( struct json_object *json ) : Json::Json( struct json_object *json ) :
@ -79,7 +79,8 @@ Json::Json( const Json& rhs ) :
Json::~Json( ) Json::~Json( )
{ {
assert( m_json != 0 ) ; assert( m_json != 0 ) ;
::json_object_put( m_json ) ; if ( m_json != 0 )
::json_object_put( m_json ) ;
} }
Json& Json::operator=( const Json& rhs ) Json& Json::operator=( const Json& rhs )
@ -216,4 +217,31 @@ bool Json::Is<Json::Array>() const
return ::json_object_is_type( m_json, json_type_array ) ; return ::json_object_is_type( m_json, json_type_array ) ;
} }
Json Json::FindInArray( const std::string& key, const std::string& value ) const
{
std::size_t count = ::json_object_array_length( m_json ) ;
for ( std::size_t i = 0 ; i < count ; ++i )
{
Json item( ::json_object_array_get_idx( m_json, i ) ) ;
if ( item.Has(key) && item[key].As<std::string>() == value )
return item ;
}
throw std::runtime_error( "cannot find " + key + " = " + value + " in array" ) ;
}
bool Json::FindInArray( const std::string& key, const std::string& value, Json& result ) const
{
try
{
result = FindInArray( key, value ) ;
return true ;
}
catch ( std::runtime_error& )
{
return false ;
}
}
} }

View File

@ -4,7 +4,7 @@
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 as published by the Free Software Foundation version 2
of the License. of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
@ -57,6 +57,8 @@ public :
bool Has( const std::string& key ) const ; bool Has( const std::string& key ) const ;
void Add( const std::string& key, const Json& json ) ; void Add( const std::string& key, 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 ;
friend std::ostream& operator<<( std::ostream& os, const Json& json ) ; friend std::ostream& operator<<( std::ostream& os, const Json& json ) ;