foxygit / Torlinkc Log in
commits tags

/include/torlinkc/engine/torrent_engine.hpp · 2.79 KB

raw
#pragma once

#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>

#include <libtorrent/info_hash.hpp>
#include <libtorrent/session.hpp>

namespace torlinkc {

struct TorrentProgress {
  double progress = 0.0;  // 0..1
  std::int64_t downloaded = 0;
  std::int64_t total = 0;
  int speed = 0;        // bytes/sec, download
  int uploadSpeed = 0;  // bytes/sec
  std::int64_t uploaded = 0;
  int peers = 0;
  double timeRemaining = 0.0;  // ms; +infinity when unknown, matching the TS original
  std::string name;
};

struct TorrentMeta {
  std::string name;
  std::int64_t total = 0;
  int files = 0;
  // Raw bencoded .torrent bytes, available once metadata arrives. Persisted so
  // a later re-seed can verify the on-disk file without re-fetching metadata
  // from the swarm (which a bare magnet would require).
  std::optional<std::string> torrentFile;
};

struct AddHandlers {
  std::function<void(const TorrentMeta&)> onMetadata;
  std::function<void()> onDone;
  std::function<void(const std::string&)> onError;
};

// Wraps a single lt::session. `source` accepted by add() is a magnet URI, a
// bare info hash, or a path to a .torrent file -- mirroring engine.ts's
// contract with webtorrent's client.add(). Ported from download/engine.ts;
// where the original polled webtorrent's async getters defensively, this
// polls libtorrent's synchronous torrent_handle::status() instead (Phase 2
// switches metadata/done/error over to the alert-driven push model; for
// Phase 1's console harness, pollAlerts() is called synchronously from the
// caller's own tick loop).
class TorrentEngine {
 public:
  TorrentEngine();
  ~TorrentEngine();

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

  void add(const std::string& id, const std::string& source, const std::string& dir, AddHandlers handlers,
           const std::vector<std::string>& announce = {});

  // Drains pending libtorrent alerts and dispatches metadata/done/error to the
  // handlers registered in add(). Must be called periodically (the queue's
  // tick() does this) or those callbacks never fire.
  void pollAlerts();

  std::optional<TorrentProgress> stats(const std::string& id);
  void remove(const std::string& id);
  void destroy();

  // The port the session accepts incoming peers on (diagnostics / tests).
  int listenPort() const;

 private:
  struct Entry {
    lt::torrent_handle handle;
    AddHandlers handlers;
  };

  std::unique_ptr<lt::session> session_;
  std::unordered_map<std::string, Entry> torrents_;             // our id -> entry
  std::unordered_map<lt::sha1_hash, std::string> infoHashToId_;  // reverse lookup for alert dispatch

  void removeEntry(const std::string& id);
};

}  // namespace torlinkc