Ctrl K
ComunidadGuías…

server/src/state_storage.h

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

Archivo original ↗Preguntar a KiBot
#pragma once

#include <boost/property_tree/ptree_fwd.hpp>
#include <nlohmann/json_fwd.hpp>
#include <mutex>
#include <optional>
#include <string>
#include <vector>

namespace statefile {

  enum class json_load_result_e {
    loaded,
    missing,
    corrupt,
    failed,
  };

  const std::string &sunshine_state_path();

  std::string sunshine_state_backup_path();

  const std::string &vibeshine_state_path();

  std::mutex &state_mutex();

  bool share_state_file();

  /**
   * @brief Write a property-tree JSON file through a temporary file and atomic replace.
   *
   * Callers that are updating shared ArtLight state should still hold state_mutex()
   * around their read/modify/write transaction; this helper only prevents partial or
   * interleaved on-disk writes from leaving malformed JSON behind. Configured
   * primary and auxiliary state writes also refresh their .bak recovery copy.
   */
  void write_json_atomic(const std::string &path, const boost::property_tree::ptree &tree);

  /**
   * @brief Persist the primary Sunshine state and refresh its recovery copy.
   *
   * The backup is written only after the primary has been atomically replaced,
   * so it remains a last-known-good snapshot if a later primary write is
   * interrupted or the primary is found unreadable.
   */
  void write_sunshine_state_atomic(const boost::property_tree::ptree &tree);

  // Preserve ArtLight JSON types in paired-client permissions and commands.
  void write_sunshine_state_atomic(const nlohmann::json &tree);
  void write_json_atomic(const std::string &path, const nlohmann::json &tree);

  /**
   * @brief Read a state file while preserving enough detail for recovery.
   *
   * Malformed or blank content is reported without changing the source; failed
   * inspection or reads are never treated as an empty state. The auxiliary state
   * is validated and recovered from its .bak copy before returning; callers hold
   * state_mutex() around reads as well as read/modify/write transactions.
   */
  json_load_result_e load_json(const std::string &path, boost::property_tree::ptree &tree);
  json_load_result_e load_json(const std::string &path, nlohmann::json &tree);

  /** Authoritative primary snapshot selection for startup and saves. Caller holds state_mutex(). */
  json_load_result_e load_primary_state(boost::property_tree::ptree &tree);
  json_load_result_e load_primary_state(nlohmann::json &tree);

  /**
   * @brief Load an existing JSON file before a read/modify/write update.
   *
   * Primary and auxiliary state recover from validated backups first and fail closed
   * when damaged state has no usable snapshot. The rules below apply to other files.
   * Returns true (with @p tree populated, or empty when there is nothing usable to
   * preserve) when it is safe for the caller to proceed and rewrite the file:
   *   - Missing or blank files yield an empty tree.
   *   - A readable-but-malformed file is quarantined (renamed aside) and yields an
   *     empty tree, so a single corrupt file can no longer permanently wedge a
   *     writer (the bad content was already unrecoverable).
   *
   * Returns false only when the file cannot be inspected or opened (I/O, permission,
   * or a non-regular path) so the caller does not overwrite state it could not read.
   */
  bool load_json_for_update(const std::string &path, boost::property_tree::ptree &tree);

  /**
   * @brief Best-effort repair for Windows config ACL inheritance.
   *
   * A previous session history build could protect the shared config directory
   * while tightening the history database. This restores inheritance on the
   * shared config directory and known mutable config/state files without
   * touching intentionally private subdirectories such as credentials.
   */
  void repair_config_permissions();

  /** Restore the configured credential file before HTTP initialization. Locks state_mutex(). */
  bool recover_credentials(const std::string &path);

  void migrate_recent_state_keys();

  /**
   * @brief Apply a restrictive, non-inherited ACL to a directory holding private key
   *        material (LocalSystem + Administrators full control, inheritance disabled).
   *
   * This is the runtime backstop for the credentials directory: it ensures the host
   * TLS private key is never left world-readable even if the installer's ACL-hardening
   * step is skipped or fails. Returns whether the restrictive ACL was applied and
   * verified; always succeeds without changing permissions on non-Windows.
   */
  [[nodiscard]] bool secure_private_directory(const std::string &path);

  /**
   * @brief Persist the snapshot exclusion device list to vibeshine_state.json.
   * @param devices List of device IDs to exclude from display snapshots.
   *
   * This is called when config is saved/applied so that the display helper
   * can read the exclusion list directly without depending on IPC from Sunshine.
   */
  void save_snapshot_exclude_devices(const std::vector<std::string> &devices);

  /**
   * @brief Load the snapshot exclusion device list from vibeshine_state.json.
   * @return The list of device IDs to exclude, or an empty vector if not found.
   */
  std::vector<std::string> load_snapshot_exclude_devices();

  /**
   * @brief Remember a Sunshine-managed virtual display device id in vibeshine_state.json.
   * @param device_id Device id of a virtual display created/resolved for a session.
   *
   * The display helper merges this list into its snapshot exclusions so virtual
   * displays are never captured into (or restored from) display baselines, even
   * when the virtual monitor uses a custom EDID the helper cannot classify.
   */
  void remember_virtual_display_device(const std::string &device_id);

  /**
   * @brief Load the remembered virtual display device ids from vibeshine_state.json.
   * @return The list of device IDs, or an empty vector if not found.
   */
  std::vector<std::string> load_virtual_display_devices();

  /**
   * @brief Persist the selected display helper engine ("legacy" or "v2") to
   *        vibeshine_state.json so the boot --restore scheduled task runs the
   *        same engine that armed it.
   */
  void save_display_helper_engine(const std::string &engine);

  /** Persist a compositor scale selected for a stable virtual-display owner. */
  void save_virtual_display_scale(const std::string &identity, double scale);

  /** Load the last compositor scale selected for a stable virtual-display owner. */
  std::optional<double> load_virtual_display_scale(const std::string &identity);

  /**
   * @brief Where the user left a virtual display on the desktop.
   *
   * Windows remembers a monitor's arrangement against the monitor, and a
   * streaming display only exists for the length of a session. It is a stranger
   * to Windows every time, so it lands on the right-hand edge instead of where
   * the user dragged it. Keeping the coordinates ourselves lets the next
   * session put it back.
   */
  struct virtual_display_position_t {
    int m_x {};
    int m_y {};
  };

  /** Persist the desktop origin the user left a virtual display at. */
  void save_virtual_display_position(const std::string &identity, int x, int y);

  /** @brief Load the remembered origin for a virtual display, if one was saved. */
  std::optional<virtual_display_position_t> load_virtual_display_position(const std::string &identity);

  /** Clear retained virtual-display scales when display state is reset. */
  void clear_virtual_display_scales();

}  // namespace statefile