43  template <
class Executor, 
class OpType>
 
   44  struct ProbeRepoLogic : 
public LogicBase<Executor, OpType>
 
   52    using MediaHandle     = 
typename ProvideType::MediaHandle;
 
   57      : _zyppContext(std::move(zyppCtx))
 
   58      , _medium(std::move(medium))
 
   59      , _path(std::move(path))
 
   60      , _targetPath(std::move(targetPath))
 
   63    MaybeAsyncRef<expected<zypp::repo::RepoType>> execute( ) {
 
   64      const auto &
url = _medium.baseUrl();
 
   65      MIL << 
"going to probe the repo type at " << 
url << 
" (" << _path << 
")" << std::endl;
 
   69        MIL << 
"Probed type NONE (not exists) at " << 
url << 
" (" << _path << 
")" << std::endl;
 
   79      std::shared_ptr<ProvideType> providerRef = _zyppContext->provider();
 
   84      return providerRef->attachMediaIfNeeded( _medium )
 
   85      | 
and_then([
this, providerRef]( MediaHandle medium )
 
   88        return providerRef->provide( medium, _path/
"repodata/repomd.xml", 
ProvideFileSpec().setCheckExistsOnly( !_targetPath.has_value() ).
setMirrorsAllowed(
false) )
 
   89          | 
and_then( maybeCopyResultToDest(
"repodata/repomd.xml") )
 
   92          | 
or_else( [
this, providerRef, medium]( std::exception_ptr err ) {
 
   94              std::rethrow_exception (err);
 
   99              DBG << 
"problem checking for repodata/repomd.xml file" << std::endl;
 
  100              _error.remember ( err );
 
  101              _gotMediaError = 
true;
 
  107                | 
and_then( maybeCopyResultToDest(
"content") )
 
  111          | 
or_else( [
this, medium]( std::exception_ptr err ) {
 
  114              std::rethrow_exception (err);
 
  119              DBG << 
"problem checking for content file" << std::endl;
 
  120              _error.remember ( err );
 
  121              _gotMediaError = 
true;
 
  131            const auto &
url = medium.baseUrl();
 
  134            if ( ! ( 
url.schemeIsDownloading() || 
url.schemeIsPlugin() ) ) {
 
  138                MIL << 
"Probed type RPMPLAINDIR at " << 
url << 
" (" << _path << 
")" << std::endl;
 
  146            MIL << 
"Probed type NONE at " << 
url << 
" (" << _path << 
")" << std::endl;
 
  158    auto maybeCopyResultToDest ( std::string &&subPath ) {
 
  161          MIL << 
"Target path is set, copying " << file.file() << 
" to " << *_targetPath/subPath << std::endl;
 
  162          return std::move(file)
 
  163              | ProvideType::copyResultToDest( _zyppContext->provider(), *_targetPath/subPath)
 
  171    ZyppContextRefType _zyppContext;
 
  174    std::optional<zypp::Pathname> _targetPath;
 
  177    bool _gotMediaError = 
false;
 
  180  template <
class RefreshContextRef>
 
  181  auto probeRepoLogic( RefreshContextRef ctx, 
RepoInfo repo, std::optional<zypp::Pathname> targetPath)
 
  185      | 
and_then( [ctx, path = 
repo.path() ]( 
auto &&mediaHandle ) {
 
  186        return probeRepoType( ctx, std::forward<decltype(mediaHandle)>(mediaHandle), path );
 
  204    return probeRepoLogic( std::move(ctx), std::move(
repo), std::move(targetPath) );
 
 
  209    return probeRepoLogic( std::move(ctx), std::move(
repo), std::move(targetPath) );
 
 
  214    template <
class ZyppContextRef>
 
  215    auto readRepoFileLogic( ZyppContextRef ctx, 
zypp::Url repoFileUrl )
 
  219      | 
and_then([repoFileUrl]( 
auto local ){
 
  220        DBG << 
"reading repo file " << repoFileUrl << 
", local path: " << local.file() << std::endl;
 
  228    return readRepoFileLogic( std::move(ctx), std::move(repoFileUrl) );
 
 
  233    return readRepoFileLogic( std::move(ctx), std::move(repoFileUrl) );
 
 
  238    template<
typename Executor, 
class OpType>
 
  239    struct CheckIfToRefreshMetadataLogic : 
public LogicBase<Executor, OpType> {
 
  245      using ZyppContextRefType = 
typename RefreshContextRefType::element_type::ContextRefType;
 
  246      using ZyppContextType = 
typename RefreshContextRefType::element_type::ContextType;
 
  247      using ProvideType     = 
typename ZyppContextType::ProvideType;
 
  249      using MediaHandle     = 
typename ProvideType::MediaHandle;
 
  252      CheckIfToRefreshMetadataLogic( RefreshContextRefType refCtx, 
LazyMediaHandle &&medium, ProgressObserverRef progressObserver )
 
  253        : _refreshContext(
std::move(refCtx))
 
  254        , _progress(
std::move( progressObserver ))
 
  255        , _medium(
std::move( medium ))
 
  258      MaybeAsyncRef<expected<repo::RefreshCheckStatus>> execute( ) {
 
  260        MIL << 
"Going to CheckIfToRefreshMetadata" << std::endl;
 
  265          const auto &info = _refreshContext->repoInfo();
 
  266          MIL << 
"Check if to refresh repo " << _refreshContext->repoInfo().alias() << 
" at " << _medium.baseUrl() << 
" (" << info.type() << 
")" << std::endl;
 
  271        | 
and_then( [
this](zypp::RepoStatus oldstatus) {
 
  273          const auto &info = _refreshContext->repoInfo();
 
  275          if ( oldstatus.
empty() ) {
 
  276            MIL << 
"No cached metadata, going to refresh" << std::endl;
 
  280          if ( _medium.baseUrl().schemeIsVolatile() ) {
 
  281            MIL << 
"Never refresh CD/DVD" << std::endl;
 
  286            MIL << 
"Forced refresh!" << std::endl;
 
  290          if ( _medium.baseUrl().schemeIsLocal() ) {
 
  303            if ( oldstatus == *cachestatus ) {
 
  306              const auto refDelay = _refreshContext->zyppContext()->config().repo_refresh_delay();
 
  307              if ( diff < refDelay ) {
 
  309                  WAR << 
"Repository '" << info.alias() << 
"' was refreshed in the future!" << std::endl;
 
  312                  MIL << 
"Repository '" << info.alias()
 
  313                  << 
"' has been refreshed less than repo.refresh.delay (" 
  315                  << 
") minutes ago. Advising to skip refresh" << std::endl;
 
  321              MIL << 
"Metadata and solv cache don't match. Check data on server..." << std::endl;
 
  325          return info.type() | [
this]( zypp::repo::RepoType repokind ) {
 
  328              return probeRepoType( _refreshContext->zyppContext(), _medium, _refreshContext->repoInfo().path() );
 
  330          } | 
and_then([
this, oldstatus]( zypp::repo::RepoType repokind ) {
 
  333            _refreshContext->repoInfo().setProbedType( repokind );
 
  335            auto dlContext = std::make_shared<repo::DownloadContext<ZyppContextRefType>>( _refreshContext->zyppContext(), _refreshContext->repoInfo(), _refreshContext->targetDir() );
 
  337              | 
and_then( [
this, dlContext, oldstatus]( zypp::RepoStatus newstatus ){
 
  339                if ( oldstatus == newstatus ) {
 
  340                  MIL << 
"repo has not changed" << std::endl;
 
  345                  MIL << 
"repo has changed, going to refresh" << std::endl;
 
  346                  MIL << 
"Old status: " << oldstatus << 
" New Status: " << newstatus << std::endl;
 
  355      RefreshContextRefType _refreshContext;
 
  356      ProgressObserverRef _progress;
 
  357      LazyMediaHandle _medium;
 
  374    template<
typename Executor, 
class OpType>
 
  375    struct RefreshMetadataLogic : 
public LogicBase<Executor, OpType>{
 
  382      using ZyppContextRefType = 
typename RefreshContextRefType::element_type::ContextRefType;
 
  383      using ZyppContextType    = 
typename RefreshContextRefType::element_type::ContextType;
 
  384      using ProvideType        = 
typename ZyppContextType::ProvideType;
 
  385      using MediaHandle        = 
typename ProvideType::MediaHandle;
 
  390      using DlContextRefType = std::shared_ptr<DlContextType>;
 
  392      RefreshMetadataLogic( RefreshContextRefType refCtx, 
LazyMediaHandle &&medium, ProgressObserverRef progressObserver )
 
  393        : _refreshContext(
std::move(refCtx))
 
  394        , _progress ( 
std::move( progressObserver ) )
 
  395        , _medium   ( 
std::move( medium ) )
 
  398      MaybeAsyncRef<expected<RefreshContextRefType>> execute() {
 
  405          MIL << 
"RefreshCheckStatus returned: " << status << std::endl;
 
  413          if ( 
zypp::IamNotRoot() && not zypp::PathInfo(_refreshContext->rawCachePath().dirname()).userMayWX() ) {
 
  414            WAR << 
"No permision to write cache " << zypp::PathInfo(_refreshContext->rawCachePath().dirname()) << std::endl;
 
  415            auto exception = 
ZYPP_EXCPT_PTR( zypp::repo::RepoNoPermissionException( _refreshContext->repoInfo() ) );
 
  419          MIL << 
"Going to refresh metadata from " << _medium.baseUrl() << std::endl;
 
  424          return probeRepoType ( _refreshContext->zyppContext(), _medium, _refreshContext->repoInfo().path()  )
 
  425          | 
and_then([
this]( zypp::repo::RepoType repokind ) {
 
  427            auto &info = _refreshContext->repoInfo();
 
  429            if ( info.type() != repokind ) {
 
  430              _refreshContext->setProbedType( repokind );
 
  432              info.setProbedType( repokind ); 
 
  439            const zypp::Pathname &mediarootpath = _refreshContext->rawCachePath();
 
  445            auto dlContext = std::make_shared<DlContextType>( _refreshContext->zyppContext(), _refreshContext->repoInfo(), _refreshContext->targetDir() );
 
  446            dlContext->setPluginRepoverification( _refreshContext->pluginRepoverification() );
 
  451          | 
and_then([
this]( DlContextRefType && ) {
 
  455            _refreshContext->saveToRawCache();
 
  465      RefreshContextRefType _refreshContext;
 
  466      ProgressObserverRef _progress;
 
  467      LazyMediaHandle _medium;
 
  468      zypp::Pathname _mediarootpath;
 
  484    template <
class RefreshContextRef>
 
  485    auto refreshMetadataLogic( RefreshContextRef refCtx, ProgressObserverRef progressObserver)
 
  493        : rexception { info_r, 
_(
"Failed to retrieve new repository metadata.") }
 
  497          if ( rexception.historyEmpty() ) {
 
  498            rexception.remember( old_r );
 
  503        zypp::repo::RepoException rexception;
 
  506      auto helper = std::make_shared<ExHelper>( ExHelper{ refCtx->repoInfo() } );
 
  509      auto refreshPipeline = [ refCtx, progressObserver ]( zypp::MirroredOrigin origin ){
 
  510        return refCtx->zyppContext()->provider()->prepareMedia( origin, zyppng::ProvideMediaSpec() )
 
  511            | 
and_then( [ refCtx , progressObserver]( 
auto mediaHandle ) 
mutable { 
return refreshMetadata ( std::move(refCtx), std::move(mediaHandle), progressObserver ); } );
 
  515      auto predicate = [ info = refCtx->repoInfo(), helper ]( 
const expected<RefreshContextRef> &res ) -> 
bool{
 
  519          } 
catch ( 
const zypp::repo::RepoNoPermissionException &e ) {
 
  521            ERR << 
"Giving up..." << std::endl;
 
  522            helper->remember( e );
 
  524          } 
catch ( 
const zypp::Exception &e ) {
 
  525            ERR << 
"Trying another url..." << std::endl;
 
  526            helper->remember( e );
 
  535      return refCtx->repoInfo().repoOrigins()
 
  537        | [helper]( expected<RefreshContextRef> result ) {
 
  540            ERR << 
"No more urls..." << std::endl;
 
  550    return refreshMetadataLogic ( std::move(refCtx), std::move(progressObserver) );
 
 
  554    return refreshMetadataLogic ( std::move(refCtx), std::move(progressObserver) );
 
 
  560    template <
typename ZyppCtxRef> 
struct Repo2SolvOp;
 
  563    struct Repo2SolvOp<ContextRef> : 
public AsyncOp<expected<void>>
 
  568        MIL << 
"Starting repo2solv for repo " << 
repo.alias () << std::endl;
 
  569        auto me = std::make_shared<Repo2SolvOp<ContextRef>>();
 
  570        me->_repo = std::move(
repo);
 
  575        std::vector<const char *> argsIn;
 
  576        argsIn.reserve ( args.size() );
 
  577        std::for_each( args.begin (), args.end(), [&]( 
const std::string &s ) { argsIn.push_back(s.data()); });
 
  578        argsIn.push_back (
nullptr);
 
  580        if (!me->_proc->start( argsIn.data() )) {
 
  587        const ByteArray &data = _proc->readLine();
 
  588        const std::string &line = data.
asString();
 
  593      void procFinished( 
int ret ) {
 
  595        while ( _proc->canReadLine() )
 
  599          zypp::repo::RepoException ex( _repo, 
zypp::str::form( 
_(
"Failed to cache repo (%d)."), ret ));
 
  600          ex.addHistory( zypp::str::Str() << _proc->executedCommand() << std::endl << _errdetail << _proc->execError() ); 
 
  609      zypp::RepoInfo _repo;
 
  610      std::string _errdetail;
 
  614    struct Repo2SolvOp<SyncContextRef>
 
  618        std::string errdetail;
 
  620        for ( std::string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
 
  621          WAR << 
"  " << output;
 
  625        int ret = prog.close();
 
  628          zypp::repo::RepoException ex(repo, 
zypp::str::form( 
_(
"Failed to cache repo (%d)."), ret ));
 
  629          ex.addHistory( zypp::str::Str() << prog.command() << std::endl << errdetail << prog.execError() ); 
 
  636    template<
typename Executor, 
class OpType>
 
  637    struct BuildCacheLogic : 
public LogicBase<Executor, OpType>{
 
  640      using ZyppContextRefType    = 
typename RefreshContextRefType::element_type::ContextRefType;
 
  641      using ZyppContextType       = 
typename RefreshContextRefType::element_type::ContextType;
 
  642      using ProvideType           = 
typename ZyppContextType::ProvideType;
 
  643      using MediaHandle           = 
typename ProvideType::MediaHandle;
 
  644      using ProvideRes            = 
typename ProvideType::Res;
 
  649        : _refCtx( std::move(refCtx) )
 
  651        , _progressObserver( std::move(progressObserver) )
 
  654      MaybeAsyncRef<expected<RefreshContextRefType>> execute() {
 
  665          const auto &options = _refCtx->repoManagerOptions();
 
  676          if ( raw_metadata_status.
empty() )
 
  682            zypp::Pathname mediarootParent { _mediarootpath.dirname() };
 
  685              && ( 
zypp::IamRoot() || zypp::PathInfo(mediarootParent).userMayWX() ) ) {
 
  692              WAR << 
"No permission to write raw cache " << mediarootParent << std::endl;
 
  693              auto exception = 
ZYPP_EXCPT_PTR( zypp::repo::RepoNoPermissionException( _refCtx->repoInfo() ) );
 
  701          bool needs_cleaning = 
false;
 
  702          const auto &info = _refCtx->repoInfo();
 
  703          if ( _refCtx->repoManager()->isCached( info ) )
 
  705            MIL << info.alias() << 
" is already cached." << std::endl;
 
  710            if ( *cache_status == raw_metadata_status )
 
  712              MIL << info.alias() << 
" cache is up to date with metadata." << std::endl;
 
  718                  | 
and_then([
this]( zypp::Pathname base ){
 
  719                    if ( ! zypp::PathInfo(base/
"solv.idx").isExist() )
 
  726                MIL << info.alias() << 
" cache rebuild is forced" << std::endl;
 
  730            needs_cleaning = 
true;
 
  737            auto r = _refCtx->repoManager()->cleanCache(info);
 
  742          MIL << info.alias() << 
" building cache..." << info.type() << std::endl;
 
  756            zypp::Exception ex(
zypp::str::form( 
_(
"Can't create cache at %s - no writing permissions."), base->c_str()) );
 
  760          zypp::Pathname solvfile = *base / 
"solv";
 
  763          zypp::repo::RepoType repokind = info.type();
 
  766          switch ( repokind.
toEnum() )
 
  776          MIL << 
"repo type is " << repokind << std::endl;
 
  778          return mountIfRequired( repokind, info )
 
  779          | 
and_then([
this, repokind, solvfile = std::move(solvfile) ]( std::optional<MediaHandle> forPlainDirs ) 
mutable {
 
  781            const auto &info = _refCtx->repoInfo();
 
  783            switch ( repokind.
toEnum() )
 
  793#ifdef ZYPP_REPO2SOLV_PATH 
  794                cmd.push_back( ZYPP_REPO2SOLV_PATH );
 
  796                cmd.push_back( zypp::PathInfo( 
"/usr/bin/repo2solv" ).isFile() ? 
"repo2solv" : 
"repo2solv.sh" );
 
  799                cmd.push_back( 
"-o" );
 
  800                cmd.push_back( solvfile.
asString() );
 
  801                cmd.push_back( 
"-X" );  
 
  807                  cmd.push_back( 
"-R" );
 
  809                  std::optional<zypp::Pathname> localPath = forPlainDirs.has_value() ? forPlainDirs->localPath() : zypp::Pathname();
 
  814                  cmd.push_back( (*localPath / info.path().absolutename()).c_str() );
 
  817                  cmd.push_back( _productdatapath.asString() );
 
  819                return Repo2SolvOp<ZyppContextRefType>::run( info, std::move(cmd) )
 
  820                | 
and_then( [
this, guard = std::move(guard), solvfile = std::move(solvfile) ]() 
mutable {
 
  822                  guard.resetDispose();
 
  832          | 
and_then([
this, raw_metadata_status](){
 
  834            return _refCtx->repoManager()->setCacheStatus( _refCtx->repoInfo(), raw_metadata_status );
 
  838          MIL << 
"Commit cache.." << std::endl;
 
  843        | 
or_else ( [
this]( std::exception_ptr e ) {
 
  850      MaybeAsyncRef<expected<std::optional<MediaHandle>>> mountIfRequired ( zypp::repo::RepoType repokind, zypp::RepoInfo info  ) {
 
  854        return _refCtx->zyppContext()->provider()->attachMedia( info.
url(), ProvideMediaSpec() )
 
  855        | 
and_then( [
this]( MediaHandle handle ) {
 
  861      RefreshContextRefType _refCtx;
 
  863      ProgressObserverRef   _progressObserver;
 
  865      zypp::Pathname _mediarootpath;
 
  866      zypp::Pathname _productdatapath;
 
  884    template<
typename Executor, 
class OpType>
 
  885    struct AddRepoLogic : 
public LogicBase<Executor, OpType>{
 
  891      AddRepoLogic( RepoManagerPtrType &&repoMgrRef, 
RepoInfo &&info, ProgressObserverRef &&myProgress )
 
  892        : _repoMgrRef( 
std::move(repoMgrRef) )
 
  893        , _info( 
std::move(info) )
 
  894        , _myProgress ( 
std::move(myProgress) )
 
  897      MaybeAsyncRef<expected<RepoInfo> > execute() {
 
  903          MIL << 
"Try adding repo " << _info << std::endl;
 
  907          if ( _repoMgrRef->repos().find(_info) != _repoMgrRef->repos().end() )
 
  911          if ( _repoMgrRef->options().probe )
 
  913            DBG << 
"unknown repository type, probing" << std::endl;
 
  916            | 
and_then([
this]( zypp::repo::RepoType probedtype ) {
 
  929        | 
and_then( [
this]( 
RepoInfo tosave ){ 
return _repoMgrRef->addProbedRepository( tosave, tosave.
type() ); })
 
  932          MIL << 
"done" << std::endl;
 
  935        | 
or_else( [
this]( std::exception_ptr e) {
 
  937          MIL << 
"done" << std::endl;
 
  943      RepoManagerPtrType _repoMgrRef;
 
  945      ProgressObserverRef _myProgress;
 
  961    template<
typename Executor, 
class OpType>
 
  962    struct AddReposLogic : 
public LogicBase<Executor, OpType>{
 
  967      AddReposLogic( RepoManagerPtrType &&repoMgrRef, 
zypp::Url &&
url, ProgressObserverRef &&myProgress )
 
  968        : _repoMgrRef( 
std::move(repoMgrRef) )
 
  970        , _myProgress ( 
std::move(myProgress) )
 
  973      MaybeAsyncRef<expected<void>> execute() {
 
  978        | 
and_then([
this]( std::list<RepoInfo> repos ) {
 
  980          for ( std::list<RepoInfo>::const_iterator it = repos.begin();
 
  985            for_ ( kit, _repoMgrRef->repoBegin(), _repoMgrRef->repoEnd() )
 
  987              if ( (*it).alias() == (*kit).alias() )
 
  989                ERR << 
"To be added repo " << (*it).alias() << 
" conflicts with existing repo " << (*kit).alias() << std::endl;
 
  995          std::string filename = zypp::Pathname(_url.getPathName()).basename();
 
  996          if ( filename == zypp::Pathname() )
 
 1002          const auto &options = _repoMgrRef->options();
 
 1007          zypp::Pathname repofile = _repoMgrRef->generateNonExistingName( options.knownReposPath, filename );
 
 1009          MIL << 
"Saving " << repos.size() << 
" repo" << ( repos.size() ? 
"s" : 
"" ) << 
" in " << repofile << std::endl;
 
 1011          std::ofstream file(repofile.
c_str());
 
 1018          for ( std::list<RepoInfo>::iterator it = repos.begin();
 
 1022            MIL << 
"Saving " << (*it).alias() << std::endl;
 
 1030            it->dumpAsIniOn(file);
 
 1031            it->setFilepath(repofile);
 
 1032            it->setMetadataPath( *rawCachePath );
 
 1033            it->setPackagesPath( *pckCachePath );
 
 1034            _repoMgrRef->reposManip().insert(*it);
 
 1036            zypp::HistoryLog( _repoMgrRef->options().rootDir).addRepository(*it);
 
 1039          MIL << 
"done" << std::endl;
 
 1045      RepoManagerPtrType _repoMgrRef;
 
 1047      ProgressObserverRef _myProgress;
 
 1065    template<
typename Executor, 
class OpType>
 
 1066    struct RefreshGeoIpLogic : 
public LogicBase<Executor, OpType>{
 
 1072        using ZyppContextType    = 
typename ZyppContextRefType::element_type;
 
 1073        using ProvideType        = 
typename ZyppContextType::ProvideType;
 
 1074        using MediaHandle        = 
typename ProvideType::MediaHandle;
 
 1075        using ProvideRes         = 
typename ProvideType::Res;
 
 1079          : _zyppCtx( 
std::move(zyppCtx) )
 
 1080          , _origins( 
std::move(origins) )
 
 1083        MaybeAsyncRef<expected<void>> execute() {
 
 1087          if ( !_zyppCtx->config().geoipEnabled() ) {
 
 1088            MIL << 
"GeoIp disabled via ZConfig, not refreshing the GeoIP information." << std::endl;
 
 1092          std::vector<std::string> hosts;
 
 1093          for ( 
const zypp::MirroredOrigin &origin : _origins ){
 
 1094            if ( !origin.schemeIsDownloading () )
 
 1097            for ( 
const auto &originEndpoint : origin ) {
 
 1098              const auto &host = originEndpoint.url().getHost();
 
 1099              if ( 
zypp::any_of( _zyppCtx->config().geoipHostnames(), [&host]( 
const auto &elem ){ return ( zypp::str::compareCI( host, elem ) == 0 ); } ) ) {
 
 1100                hosts.push_back( host );
 
 1106          if ( hosts.empty() ) {
 
 1107            MIL << 
"No configured geoip URL found, not updating geoip data" << std::endl;
 
 1111          _geoIPCache = _zyppCtx->config().geoipCachePath();
 
 1114            MIL << 
"Unable to create cache directory for GeoIP." << std::endl;
 
 1118          if ( 
zypp::IamNotRoot() && not zypp::PathInfo(_geoIPCache).userMayRWX() ) {
 
 1119            MIL << 
"No access rights for the GeoIP cache directory." << std::endl;
 
 1128            zypp::PathInfo pi( dir/entry.
name );
 
 1129            auto age = std::chrono::system_clock::now() - std::chrono::system_clock::from_time_t( pi.mtime() );
 
 1130            if ( age < std::chrono::hours(24) )
 
 1133            MIL << 
"Removing GeoIP file for " << entry.
name << 
" since it's older than 24hrs." << std::endl;
 
 1138          auto firstOfCb = [
this]( std::string hostname ) {
 
 1141            if ( zypp::PathInfo( _geoIPCache / hostname ).isExist() )  {
 
 1142              MIL << 
"Skipping GeoIP request for " << hostname << 
" since a valid cache entry exists." << std::endl;
 
 1146            MIL << 
"Query GeoIP for " << hostname << std::endl;
 
 1153            } 
catch(
const zypp::Exception &e ) {
 
 1155              MIL << 
"Ignoring invalid GeoIP hostname: " << hostname << std::endl;
 
 1160            return _zyppCtx->provider()->attachMedia( url, ProvideMediaSpec() )
 
 1161            | 
and_then( [
this]( MediaHandle provideHdl ) { 
return _zyppCtx->provider()->provide( provideHdl, 
"/geoip", ProvideFileSpec() ); })
 
 1162            | 
inspect_err( [hostname]( 
const std::exception_ptr& ){ 
MIL << 
"Failed to query GeoIP from hostname: " << hostname << std::endl; } )
 
 1163            | 
and_then( [hostname, 
this]( ProvideRes provideRes ) {
 
 1167              constexpr auto writeHostToFile = []( 
const zypp::Pathname &fName, 
const std::string &host ){
 
 1169                out.open( fName.
asString(), std::ios_base::trunc );
 
 1170                if ( out.is_open() ) {
 
 1171                  out << host << std::endl;
 
 1173                  MIL << 
"Failed to create/open GeoIP cache file " << fName << std::endl;
 
 1177              std::string geoipMirror;
 
 1179                zypp::xml::Reader reader( provideRes.
file() );
 
 1180                if ( reader.seekToNode( 1, 
"host" ) ) {
 
 1181                  const auto &str = reader.nodeText().asString();
 
 1189                    MIL << 
"Storing geoIP redirection: " << hostname << 
" -> " << str << std::endl;
 
 1194                  MIL << 
"No host entry or empty file returned for GeoIP, remembering for 24hrs" << std::endl;
 
 1196              } 
catch ( 
const zypp::Exception &e ) {
 
 1198                MIL << 
"Empty or invalid GeoIP file, not requesting again for 24hrs" << std::endl;
 
 1201              writeHostToFile( _geoIPCache / hostname, geoipMirror );
 
 1204            | []( expected<void> res ) { 
return res.
is_valid(); };
 
 1207          return std::move(hosts)
 
 1208          | 
firstOf( std::move(firstOfCb), 
false, zyppng::detail::ContinueUntilValidPredicate() )
 
 1209          | []( 
bool foundGeoIP ) {
 
 1212              MIL << 
"Successfully queried GeoIP data." << std::endl;
 
 1216            MIL << 
"Failed to query GeoIP data." << std::endl;
 
 1217            return expected<void>::error( std::make_exception_ptr( zypp::Exception(
"No valid geoIP url found" )) );
 
 1223        ZyppContextRefType _zyppCtx;
 
 1224        zypp::MirroredOriginSet _origins;
 
 1225        zypp::Pathname     _geoIPCache;