foxygit / Torlinkc Log in
commits tags

/include/torlinkc/ui/engine_thread.hpp · 2.02 KB

raw
#pragma once

#include <atomic>
#include <deque>
#include <functional>
#include <mutex>
#include <thread>

#include <ftxui/component/screen_interactive.hpp>

#include "torlinkc/config/config.hpp"
#include "torlinkc/engine/queue.hpp"
#include "torlinkc/ui/app_state.hpp"

namespace torlinkc::ui {

// Owns the DownloadQueue -- and therefore the libtorrent session -- on a
// dedicated background thread, since neither is safe to touch concurrently
// from the UI thread. The two threads only ever talk in one direction each:
// the UI thread enqueues a command via post(), and the engine thread replies
// (if at all) by posting a state snapshot onto FTXUI's own thread-safe queue
// (ftxui::ScreenInteractive::Post), which runs it on the UI thread. Neither
// side ever reaches across and touches the other's data directly -- see the
// "Concurrency / state model" section of the phased plan.
class EngineThread {
 public:
  EngineThread(ftxui::ScreenInteractive& screen, AppState& state);
  ~EngineThread();

  EngineThread(const EngineThread&) = delete;
  EngineThread& operator=(const EngineThread&) = delete;

  // Boots the queue (restore, safe-mode/bootguard handling) and starts
  // ticking. Call once, before screen.Loop().
  void start(Config config);

  // Signals the loop to stop, waits for it to flush state and exit. Safe to
  // call from the UI thread after screen.Loop() returns.
  void stop();

  // Thread-safe: queues `fn` to run against the live DownloadQueue on the
  // engine thread's next loop iteration. Use this for anything a keypress
  // wants the queue to do (add/pause/resume/...) -- never call DownloadQueue
  // methods directly from the UI thread.
  void post(std::function<void(DownloadQueue&)> fn);

 private:
  void run(Config config);
  void publishSnapshot(DownloadQueue& queue);

  ftxui::ScreenInteractive& screen_;
  AppState& state_;

  std::thread thread_;
  std::atomic<bool> running_{false};

  std::mutex commandsMutex_;
  std::deque<std::function<void(DownloadQueue&)>> commands_;
};

}  // namespace torlinkc::ui