mirror of https://github.com/vitalif/grive2
pull/40/head
commit
ac1763f2c7
|
@ -4,3 +4,13 @@ grive.kdev4
|
||||||
.project
|
.project
|
||||||
.cproject
|
.cproject
|
||||||
build/
|
build/
|
||||||
|
/CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
moc_*.cxx*
|
||||||
|
bgrive/ui_MainWindow.h
|
||||||
|
Makefile
|
||||||
|
*.a
|
||||||
|
bgrive/bgrive
|
||||||
|
grive/grive
|
||||||
|
libgrive/btest
|
||||||
|
*.cmake
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "xml/Node.hh"
|
#include "xml/Node.hh"
|
||||||
#include "xml/NodeSet.hh"
|
#include "xml/NodeSet.hh"
|
||||||
#include "xml/String.hh"
|
#include "xml/String.hh"
|
||||||
|
#include "xml/TreeBuilder.hh"
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/exception/all.hpp>
|
#include <boost/exception/all.hpp>
|
||||||
|
@ -252,7 +253,7 @@ void Resource::FromRemoteFile( const Entry& remote, const DateTime& last_sync )
|
||||||
void Resource::FromLocal( const DateTime& last_sync )
|
void Resource::FromLocal( const DateTime& last_sync )
|
||||||
{
|
{
|
||||||
fs::path path = Path() ;
|
fs::path path = Path() ;
|
||||||
assert( fs::exists( path ) ) ;
|
//assert( fs::exists( path ) ) ;
|
||||||
|
|
||||||
// root folder is always in sync
|
// root folder is always in sync
|
||||||
if ( !IsRoot() )
|
if ( !IsRoot() )
|
||||||
|
@ -270,8 +271,8 @@ void Resource::FromLocal( const DateTime& last_sync )
|
||||||
m_state = ( m_mtime > last_sync ? local_new : remote_deleted ) ;
|
m_state = ( m_mtime > last_sync ? local_new : remote_deleted ) ;
|
||||||
|
|
||||||
m_name = path.filename().string() ;
|
m_name = path.filename().string() ;
|
||||||
m_kind = fs::is_directory(path) ? "folder" : "file" ;
|
//m_kind = fs::is_directory(path) ? "folder" : "file" ;
|
||||||
m_md5 = fs::is_directory(path) ? "" : crypt::MD5::Get( path ) ;
|
m_md5 = IsFolder() ? "" : crypt::MD5::Get( path ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( m_state != unknown ) ;
|
assert( m_state != unknown ) ;
|
||||||
|
@ -579,23 +580,68 @@ bool Resource::Upload(
|
||||||
% xml::Escape(m_name)
|
% xml::Escape(m_name)
|
||||||
).str() ;
|
).str() ;
|
||||||
|
|
||||||
http::StringResponse str ;
|
bool retrying=false;
|
||||||
if ( post )
|
while ( true ) {
|
||||||
http->Post( link, meta, &str, hdr ) ;
|
if ( retrying ) {
|
||||||
else
|
file.Seek( 0, SEEK_SET );
|
||||||
http->Put( link, meta, &str, hdr ) ;
|
os::Sleep( 5 );
|
||||||
|
}
|
||||||
http::Header uphdr ;
|
|
||||||
uphdr.Add( "Expect:" ) ;
|
|
||||||
uphdr.Add( "Accept:" ) ;
|
|
||||||
|
|
||||||
// the content upload URL is in the "Location" HTTP header
|
try {
|
||||||
std::string uplink = http->RedirLocation() ;
|
http::StringResponse str ;
|
||||||
http::XmlResponse xml ;
|
if ( post )
|
||||||
|
http->Post( link, meta, &str, hdr ) ;
|
||||||
http->Put( uplink, &file, &xml, uphdr ) ;
|
else
|
||||||
AssignIDs( Entry( xml.Response() ) ) ;
|
http->Put( link, meta, &str, hdr ) ;
|
||||||
m_mtime = Entry(xml.Response()).MTime();
|
} catch ( Error &e ) {
|
||||||
|
std::string const *info = boost::get_error_info<xml::TreeBuilder::ExpatApiError>(e);
|
||||||
|
if ( info && (*info == "XML_Parse") ) {
|
||||||
|
Log( "Error parsing pre-upload response XML, retrying whole upload in 5s",
|
||||||
|
log::warning );
|
||||||
|
retrying = true;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
http::Header uphdr ;
|
||||||
|
uphdr.Add( "Expect:" ) ;
|
||||||
|
uphdr.Add( "Accept:" ) ;
|
||||||
|
|
||||||
|
// the content upload URL is in the "Location" HTTP header
|
||||||
|
std::string uplink = http->RedirLocation() ;
|
||||||
|
http::XmlResponse xml ;
|
||||||
|
|
||||||
|
long http_code = 0;
|
||||||
|
try {
|
||||||
|
http_code = http->Put( uplink, &file, &xml, uphdr ) ;
|
||||||
|
} catch ( Error &e ) {
|
||||||
|
std::string const *info = boost::get_error_info<xml::TreeBuilder::ExpatApiError>(e);
|
||||||
|
if ( info && (*info == "XML_Parse") ) {
|
||||||
|
Log( "Error parsing response XML, retrying whole upload in 5s",
|
||||||
|
log::warning );
|
||||||
|
retrying = true;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( http_code == 410 || http_code == 412 ) {
|
||||||
|
Log( "request failed with %1%, retrying whole upload in 5s", http_code,
|
||||||
|
log::warning ) ;
|
||||||
|
retrying = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( retrying )
|
||||||
|
Log( "upload succeeded on retry", log::warning );
|
||||||
|
Entry responseEntry = Entry( xml.Response() );
|
||||||
|
AssignIDs( responseEntry ) ;
|
||||||
|
m_mtime = responseEntry.MTime();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return true ;
|
return true ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ void State::FromLocal( const fs::path& p )
|
||||||
|
|
||||||
bool State::IsIgnore( const std::string& filename )
|
bool State::IsIgnore( const std::string& filename )
|
||||||
{
|
{
|
||||||
return filename[0] == '.' ;
|
return filename == ".grive" || filename == ".grive_state";
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::FromLocal( const fs::path& p, Resource* folder )
|
void State::FromLocal( const fs::path& p, Resource* folder )
|
||||||
|
@ -89,19 +89,20 @@ void State::FromLocal( const fs::path& p, Resource* folder )
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
bool is_dir = fs::is_directory(i->path());
|
||||||
// if the Resource object of the child already exists, it should
|
// if the Resource object of the child already exists, it should
|
||||||
// have been so no need to do anything here
|
// have been so no need to do anything here
|
||||||
Resource *c = folder->FindChild( fname ) ;
|
Resource *c = folder->FindChild( fname ) ;
|
||||||
if ( c == 0 )
|
if ( c == 0 )
|
||||||
{
|
{
|
||||||
c = new Resource( fname, fs::is_directory(i->path()) ? "folder" : "file" ) ;
|
c = new Resource( fname, is_dir ? "folder" : "file" ) ;
|
||||||
folder->AddChild( c ) ;
|
folder->AddChild( c ) ;
|
||||||
m_res.Insert( c ) ;
|
m_res.Insert( c ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->FromLocal( m_last_sync ) ;
|
c->FromLocal( m_last_sync ) ;
|
||||||
|
|
||||||
if ( fs::is_directory( i->path() ) )
|
if ( is_dir )
|
||||||
FromLocal( *i, c ) ;
|
FromLocal( *i, c ) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,11 @@ XmlResponse::XmlResponse() : m_tb( new xml::TreeBuilder )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XmlResponse::Clear()
|
||||||
|
{
|
||||||
|
m_tb.reset(new xml::TreeBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t XmlResponse::Write( const char *data, std::size_t count )
|
std::size_t XmlResponse::Write( const char *data, std::size_t count )
|
||||||
{
|
{
|
||||||
m_tb->ParseData( data, count ) ;
|
m_tb->ParseData( data, count ) ;
|
||||||
|
|
|
@ -21,8 +21,10 @@
|
||||||
|
|
||||||
#include "http/Error.hh"
|
#include "http/Error.hh"
|
||||||
#include "http/Header.hh"
|
#include "http/Header.hh"
|
||||||
|
#include "http/XmlResponse.hh"
|
||||||
#include "util/log/Log.hh"
|
#include "util/log/Log.hh"
|
||||||
#include "util/OS.hh"
|
#include "util/OS.hh"
|
||||||
|
#include "util/File.hh"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
@ -69,8 +71,22 @@ long AuthAgent::Put(
|
||||||
Header auth = AppendHeader(hdr) ;
|
Header auth = AppendHeader(hdr) ;
|
||||||
|
|
||||||
long response ;
|
long response ;
|
||||||
while ( CheckRetry(
|
bool keepTrying = true;
|
||||||
response = m_agent->Put( url, file, dest, AppendHeader(hdr) ) ) ) ;
|
while ( keepTrying ) {
|
||||||
|
response = m_agent->Put( url, file, dest, auth );
|
||||||
|
keepTrying = CheckRetry( response );
|
||||||
|
if ( keepTrying ) {
|
||||||
|
file->Seek( 0, SEEK_SET );
|
||||||
|
XmlResponse *xmlResponse = dynamic_cast<XmlResponse*>(dest);
|
||||||
|
if( xmlResponse )
|
||||||
|
xmlResponse->Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// On 410 Gone or 412 Precondition failed, recovery may be possible so don't
|
||||||
|
// throw an exception
|
||||||
|
if ( response == 410 || response == 412 )
|
||||||
|
return response;
|
||||||
|
|
||||||
return CheckHttpResponse(response, url, auth) ;
|
return CheckHttpResponse(response, url, auth) ;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +168,7 @@ bool AuthAgent::CheckRetry( long response )
|
||||||
Log( "resquest failed due to auth token expired: %1%. refreshing token",
|
Log( "resquest failed due to auth token expired: %1%. refreshing token",
|
||||||
response, log::warning ) ;
|
response, log::warning ) ;
|
||||||
|
|
||||||
|
os::Sleep( 5 ) ;
|
||||||
m_auth.Refresh() ;
|
m_auth.Refresh() ;
|
||||||
return true ;
|
return true ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "Error.hh"
|
#include "Error.hh"
|
||||||
#include "Node.hh"
|
#include "Node.hh"
|
||||||
|
#include "util/log/Log.hh"
|
||||||
|
|
||||||
#include <expat.h>
|
#include <expat.h>
|
||||||
|
|
||||||
|
@ -72,8 +73,10 @@ void TreeBuilder::ParseData( const char *data, std::size_t count, bool last )
|
||||||
{
|
{
|
||||||
is_new = false ;
|
is_new = false ;
|
||||||
|
|
||||||
if ( ::XML_Parse( m_impl->psr, data, count, last ) == 0 )
|
if ( ::XML_Parse( m_impl->psr, data, count, last ) == 0 ) {
|
||||||
|
Log("Error parsing XML: %1%", data, log::error);
|
||||||
BOOST_THROW_EXCEPTION( Error() << ExpatApiError("XML_Parse") );
|
BOOST_THROW_EXCEPTION( Error() << ExpatApiError("XML_Parse") );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Node TreeBuilder::Parse( const std::string& xml )
|
Node TreeBuilder::Parse( const std::string& xml )
|
||||||
|
|
Loading…
Reference in New Issue