Ctrl K
ComunidadGuías…

server/src/steam_auto_sync.cpp

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/** @file src/steam_auto_sync.cpp */
#include "steam_auto_sync.h"

#include "confighttp.h"
#include "file_handler.h"
#include "logging.h"
#include "platform/common.h"
#include "steam_artwork.h"
#include "steam_auto_sync_policy.h"
#include "steam_integration.h"
#include "steam_sync_policy.h"

#include <chrono>
#include <nlohmann/json.hpp>

namespace platf::steam::autosync {
  namespace {
    constexpr auto poll_interval = std::chrono::seconds {30};

    class manager_t {
    public:
      void configure(settings_t settings) {
        {
          std::lock_guard lock {mutex_};
          settings_ = std::move(settings);
          ++epoch_;
        }
        condition_.notify_all();
      }

      void start() {
        std::lock_guard lock {mutex_};
        if (worker_.joinable()) {
          return;
        }
        stopping_ = false;
        worker_ = std::thread {[this] {
          run();
        }};
      }

      void stop() {
        {
          std::lock_guard lock {mutex_};
          stopping_ = true;
        }
        condition_.notify_all();
        if (worker_.joinable()) {
          worker_.join();
        }
      }

    private:
      void run() {
        std::uint64_t previous_fingerprint = 0;
        std::uint64_t observed_epoch = 0;
        bool have_fingerprint = false;
        auto next_artwork_retry = std::chrono::steady_clock::time_point {};
        while (true) {
          settings_t settings;
          std::uint64_t epoch;
          {
            std::lock_guard lock {mutex_};
            if (stopping_) {
              return;
            }
            settings = settings_;
            epoch = epoch_;
          }

          if (epoch != observed_epoch) {
            observed_epoch = epoch;
            // A provider-policy change (exclusions/include-tools/removal)
            // must reconcile even when Steam's files did not change.
            have_fingerprint = false;
          }

          if (settings.enabled && settings.auto_sync) {
            try {
              if (platf::steam::available()) {
                auto catalog = platf::steam::discover_catalog();
                const auto fingerprint = source_fingerprint(catalog);
                if (!have_fingerprint || fingerprint != previous_fingerprint ||
                    std::chrono::steady_clock::now() >= next_artwork_retry) {
                  auto games = platf::steam::sync::policy::select_games(
                    catalog,
                    settings.sync_all_installed,
                    settings.recent_games,
                    settings.recent_max_age_days,
                    settings.exclusions,
                    settings.include_tools
                  );
                  platf::steam::artwork::prepare(games, platf::appdata());
                  std::lock_guard apps_lock {confighttp::apps_file_mutex()};
                  const auto text = file_handler::read_file(config::stream.file_apps.c_str());
                  if (!text.empty()) {
                    auto root = nlohmann::json::parse(text);
                    const auto changed = platf::steam::sync::policy::reconcile(
                      root,
                      games,
                      !settings.sync_all_installed || settings.remove_uninstalled,
                      settings.exclusions,
                      settings.include_tools,
                      settings.sync_all_installed ? "installed" : "recent"
                    );
                    if (changed && !confighttp::refresh_client_apps_cache(root)) {
                      BOOST_LOG(warning) << "Steam auto-sync could not save applications";
                    } else {
                      previous_fingerprint = fingerprint;
                      have_fingerprint = true;
                      next_artwork_retry = std::chrono::steady_clock::now() + std::chrono::minutes {5};
                    }
                  }
                }
              }
            } catch (const std::exception &error) {
              BOOST_LOG(warning) << "Steam auto-sync failed: " << error.what();
            } catch (...) {
              BOOST_LOG(warning) << "Steam auto-sync failed with an unknown error";
            }
          }

          std::unique_lock lock {mutex_};
          const auto wake_epoch = epoch_;
          condition_.wait_for(lock, poll_interval, [this, wake_epoch] {
            return stopping_ || epoch_ != wake_epoch;
          });
          if (stopping_) {
            return;
          }
        }
      }

      std::mutex mutex_;
      std::condition_variable condition_;
      settings_t settings_;
      std::uint64_t epoch_ = 0;
      bool stopping_ = false;
      std::thread worker_;
    };

    manager_t &manager() {
      static manager_t instance;
      return instance;
    }
  }  // namespace

  void configure(settings_t settings) {
    manager().configure(std::move(settings));
  }

  void start() {
    manager().start();
  }

  void stop() {
    manager().stop();
  }
}  // namespace platf::steam::autosync