17 #include <zypp/base/Logger.h> 18 #include <zypp/base/String.h> 19 #include <zypp/base/Gettext.h> 21 #include <zypp-core/base/Regex.h> 22 #include <zypp-core/fs/TmpPath.h> 23 #include <zypp-core/zyppng/base/EventDispatcher> 24 #include <zypp-core/zyppng/base/EventLoop> 25 #include <zypp-core/zyppng/base/private/threaddata_p.h> 27 #include <zypp-curl/ng/network/Downloader> 28 #include <zypp-curl/ng/network/NetworkRequestDispatcher> 29 #include <zypp-curl/ng/network/DownloadSpec> 31 #include <zypp-media/MediaConfig> 33 #include <zypp-media/auth/CredentialManager> 44 constexpr std::string_view
MEDIACACHE_REGEX(
"^\\/media\\.[1-9][0-9]*\\/media$");
48 using clock = std::chrono::steady_clock;
64 clock::time_point now = clock::now();
73 if ( dlnow && dlnow !=
_dnlNow ) {
102 MIL <<
"Releasing internal::SharedData for MediaNetwork." << std::endl;
106 static std::shared_ptr<SharedData> data = std::shared_ptr<SharedData>(
new SharedData() );
123 std::chrono::steady_clock::time_point
_creationTime = std::chrono::steady_clock::now();
130 auto age = std::chrono::steady_clock::now() - i->second._creationTime;
131 if ( age > std::chrono::minutes( 30 ) ) {
132 MIL <<
"Found cached media file, but it's older than 30 mins, requesting a new one" << std::endl;
146 MIL <<
"Initializing internal::SharedData for MediaNetwork" << std::endl;
147 _dispatcher = zyppng::ThreadData::current().ensureDispatcher();
148 _downloader = std::make_shared<zyppng::Downloader>();
162 MediaNetwork::MediaNetwork(
const Url & url_r,
163 const Pathname & attach_point_hint_r )
168 MIL <<
"MediaNetwork::MediaNetwork(" << url_r <<
", " << attach_point_hint_r <<
")" << endl;
177 char *atemp = ::strdup( apath.
asString().c_str());
180 atemp == NULL || (atest=::mkdtemp(atemp)) == NULL)
182 WAR <<
"attach point " << ainfo.
path()
183 <<
" is not useable for " << url_r.
getScheme() << endl;
186 else if( atest != NULL)
203 if ( !
_shared->_downloader->requestDispatcher()->supportsProtocol(
_url ) ) {
204 std::string msg(
"Unsupported protocol '");
238 auto ev = zyppng::EventLoop::create();
239 std::vector<zyppng::connection> signalConnections;
241 while( signalConnections.size() ) {
242 signalConnections.back().disconnect();
243 signalConnections.pop_back();
247 zyppng::DownloadRef dl =
_shared->_downloader->downloadFile( spec );
248 std::optional<internal::ProgressTracker> progTracker;
251 if ( !report)
return;
256 if ( !report || !progTracker )
258 progTracker->updateStats( 0.0, dlNow );
259 if ( !(*report)->progress( progTracker->_dnlPercent, spec.
url(), progTracker-> _drateTotal, progTracker->_drateLast ) )
263 const auto &progressSlot = [&](
zyppng::Download &req, off_t dlTotal, off_t dlNow ) {
264 if ( !report || !progTracker )
267 progTracker->updateStats( dlTotal, dlNow );
268 if ( !(*report)->progress( progTracker->_dnlPercent, spec.
url(), progTracker-> _drateTotal, progTracker->_drateLast ) )
276 bool firstTry =
true;
285 if ( cmcred && auth.lastDatabaseUpdate() < cmcred->lastDatabaseUpdate() ) {
287 DBG <<
"got stored credentials:" << endl << *credentials << endl;
300 curlcred->setUsername(cmcred->username());
309 curlcred->setAuthType( availAuth );
312 if (auth_report->prompt(
_url, prompt_msg, *curlcred))
314 DBG <<
"callback answer: retry" << endl
315 <<
"CurlAuthData: " << *curlcred << endl;
317 if (curlcred->valid())
319 credentials = curlcred;
333 DBG <<
"callback answer: cancel" << endl;
337 if ( !credentials ) {
344 credentials->setUrl(
_url);
350 signalConnections.insert( signalConnections.end(), {
358 signalConnections.insert( signalConnections.end(), {
367 std::for_each( signalConnections.begin(), signalConnections.end(), [](
auto &conn ) { conn.disconnect(); });
369 if ( dl->hasError() ) {
371 std::exception_ptr excp;
372 const auto &error = dl->lastRequestError();
373 switch ( error.type() ) {
421 DBG <<
"BUG: Download error flag is set , but Error code is NoError" << std::endl;
426 if ( report ) (*report)->finish( spec.
url(), errCode, error.toString() );
427 std::rethrow_exception( excp );
442 const auto &filename = file.
filename();
445 const bool requestedMediaFile =
_shared->mediaRegex().matches( filename.asString() );
446 auto &mediaFileCache =
_shared->_mediaCacheEntries;
449 DBG <<
"FILEURL IS: " << fileurl << std::endl;
450 DBG <<
"Downloading to: " << targetFilename << std::endl;
453 DBG <<
"assert_dir " << targetFilename.
dirname() <<
" failed" << endl;
457 if ( requestedMediaFile ) {
458 MIL <<
"Requested " << filename <<
" trying media cache first" << std::endl;
460 auto i =
_shared->findInCache( mediaCacheKey );
461 if ( i != mediaFileCache.end() ) {
462 MIL <<
"Found cached media file, returning a copy to the file" << std::endl;
466 mediaFileCache.erase(i);
467 MIL <<
"Failed to copy the requested file, proceeding with download" << std::endl;
470 MIL <<
"Nothing in the file cache, requesting the file from the server." << std::endl;
484 if ( requestedMediaFile ) {
485 MIL <<
"Media file was not found, remembering in the cache" << std::endl;
488 std::rethrow_exception( std::current_exception() );
492 if ( requestedMediaFile ) {
497 MIL <<
"Saved requested media file in media cache for future use" << std::endl;
499 MIL <<
"Failed to save requested media file in cache, requesting again next time." << std::endl;
506 MIL <<
"Checking if file " << filename <<
" does exist" << std::endl;
508 const bool requestMediaFile =
_shared->mediaRegex().matches( filename.
asString() );
509 auto &mediaFileCache =
_shared->_mediaCacheEntries;
512 if ( requestMediaFile ) {
513 MIL <<
"Request for " << filename <<
" is a media file, trying the cache first" << std::endl;
514 auto i =
_shared->findInCache( mediaCacheKey );
515 if ( i != mediaFileCache.end() ) {
516 MIL <<
"Found a cache entry for requested media file, returning right away" << std::endl;
517 if ( i->second._file->empty() ) {
550 if ( !result && requestMediaFile ) {
551 MIL << filename <<
" does not exist on medium, remembering in the cache" << std::endl;
563 for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
564 Pathname filename = dirname + it->name;
567 switch ( it->type ) {
574 getDir( filename, recurse_r );
578 WAR <<
"Ignore error (" << res <<
") on creating local directory '" <<
localPath( filename ) <<
"'" << endl;
590 const Pathname & dirname,
bool dots )
const 596 const Pathname & dirname,
bool dots )
const std::string getScheme() const
Returns the scheme name of the URL.
static const zypp::str::regex & mediaRegex()
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
SignalProxy< void(Download &req, off_t dlnow)> sigAlive()
const Pathname & path() const
Return current Pathname.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
static ZConfig & instance()
Singleton ctor.
int _dnlPercent
Percent completed or 0 if _dnlTotal is unknown.
std::string asString() const
DownloadSpec & setTransferSettings(TransferSettings &&set)
SignalProxy< void(Download &req, NetworkAuthData &auth, const std::string &availAuth)> sigAuthRequired()
std::optional< clock::time_point > _timeLast
Start last period(~1sec)
static std::shared_ptr< SharedData > instance()
static const Pathname & defaultLocation()
double _drateLast
Download rate in last period.
zypp::filesystem::TmpDir _mediaCacheDir
SignalProxy< void(Download &req)> sigFinished()
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
constexpr std::string_view MEDIACACHE_REGEX("^\media\[1-9][0-9]*\media$")
static CheckSum md5FromString(const std::string &input_r)
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
std::string asString() const
Returns a default string representation of the Url object.
auto findInCache(const std::string &mediaCacheKey)
Provide a new empty temporary directory and recursively delete it when no longer needed.
int unlink(const Pathname &path)
Like 'unlink'.
std::optional< clock::time_point > _timeStart
Start total stats.
const std::string & asString() const
String representation.
Pathname dirname() const
Return all but the last component od this path.
void updateStats(double dltotal=0.0, double dlnow=0.0)
std::string asCompleteString() const
Returns a complete string representation of the Url object.
std::list< DirEntry > DirContent
Returned by readdir.
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
bool isValid() const
Verifies the Url.
double _dnlLast
Bytes downloaded at period start.
const zypp::Pathname & targetPath() const
zypp::ByteCount expectedFileSize() const
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
zypp::media::CurlAuthData NetworkAuthData
int rmdir(const Pathname &path)
Like 'rmdir'.
SignalProxy< void(Download &req)> sigStarted()
zyppng::DownloaderRef _downloader
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
std::chrono::steady_clock::time_point _creationTime
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
zyppng::EventDispatcherRef _dispatcher
SignalProxy< void(Download &req, off_t dltotal, off_t dlnow)> sigProgress()
Wrapper class for ::stat/::lstat.
double _dnlNow
Bytes downloaded now.
double _dnlTotal
Bytes to download or 0 if unknown.
Easy-to use interface to the ZYPP dependency resolver.
std::chrono::steady_clock clock
double _drateTotal
Download rate so far.
DownloadSpec & setCheckExistsOnly(bool set=true)
std::unordered_map< std::string, MediaFileCacheEntry > _mediaCacheEntries
MediaFileCacheEntry(zypp::ManagedFile &&file)
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.