Ctrl K
ComunidadGuías…

server/src/lutris_auto_sync.cpp

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

Archivo original ↗Preguntar a KiBot
#include "lutris_auto_sync.h"

#include "config.h"
#include "confighttp.h"
#include "file_handler.h"
#include "logging.h"
#include "lutris_artwork.h"
#include "lutris_integration.h"
#include "lutris_sync_policy.h"
#include "platform/common.h"

#include <chrono>
#include <condition_variable>
#include <mutex>
#include <nlohmann/json.hpp>
#include <thread>

namespace platf::lutris::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 = 0;
          {
            std::lock_guard lock {mutex_};
            if (stopping_) return;
            settings = settings_;
            epoch = epoch_;
          }
          if (epoch != observed_epoch) {
            observed_epoch = epoch;
            have_fingerprint = false;
          }
          if (settings.enabled && settings.auto_sync && discovery_ready()) {
            try {
              auto games = discover();
              const auto fingerprint = source_fingerprint(games);
              if (!have_fingerprint || fingerprint != previous_fingerprint ||
                  std::chrono::steady_clock::now() >= next_artwork_retry) {
                artwork::prepare(games, platf::appdata());
                std::lock_guard apps_lock {confighttp::apps_file_mutex()};
                const auto contents = file_handler::read_file(config::stream.file_apps.c_str());
                if (!contents.empty()) {
                  auto root = nlohmann::json::parse(contents);
                  const auto changed = sync::policy::reconcile(
                    root, games, settings.remove_uninstalled, settings.exclusions, settings.include_steam);
                  if (changed && !confighttp::refresh_client_apps_cache(root)) {
                    BOOST_LOG(warning) << "Lutris 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) << "Lutris auto-sync failed: " << error.what();
            } catch (...) {
              BOOST_LOG(warning) << "Lutris 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 value;
      return value;
    }
  }  // namespace

  void configure(settings_t settings) { manager().configure(std::move(settings)); }
  void start() { manager().start(); }
  void stop() { manager().stop(); }
}  // namespace platf::lutris::autosync