Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,17 @@ These are load-bearing and enforced in the code:

## API at a glance

39 public `bt*` handlers (full signatures in **[api-reference](docs/api-reference.md)**):
56 public `bt*` handlers (full signatures in **[api-reference](docs/api-reference.md)**):

| Group | Handlers |
|---|---|
| Session | `btStartSession` · `btStopSession` · `btLastError` · `btClearError` |
| Settings | `btSetInt` · `btSetBool` · `btSetString` · `btGetSetting` · `btSetEncryption` |
| Add / remove | `btAddMagnet` · `btAddTorrentFile` · `btAddTorrentWithResume` · `btRemoveTorrent` |
| Control | `btPause` · `btResume` · `btForceRecheck` · `btForceReannounce` |
| Priorities / limits | `btSetFilePriority` · `btSetFilePriorities` · `btSetPiecePriority` · `btSetTorrentLimits` |
| Control | `btPause` · `btResume` · `btForceRecheck` · `btForceReannounce` · `btScrapeTracker` · `btClearTorrentError` |
| Priorities / limits | `btSetFilePriority` · `btSetFilePriorities` · `btSetPiecePriority` · `btSetTorrentLimits` · `btSetMaxConnections` · `btSetMaxUploads` |
| Flags / modes | `btSetTorrentFlags` · `btUnsetTorrentFlags` · `btSetSequentialDownload` · `btSetAutoManaged` · `btSetSuperSeeding` · `btSetShareMode` · `btSetUploadMode` |
| Queue / storage | `btQueuePosition` · `btQueueUp` · `btQueueDown` · `btQueueTop` · `btQueueBottom` · `btMoveStorage` |
| Inspect | `btTorrentStatus` · `btTorrentCount` · `btTorrentHandleAt` · `btInfoHash` · `btPieceBitfield` · `btPeerList` |
| Events | `btPoll` |
| DHT | `btDhtAddBootstrap` · `btDhtState` · `btDhtSaveState` · `btDhtLoadState` |
Expand Down
78 changes: 78 additions & 0 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,84 @@ unlimited). Distinct from the session-wide `download_rate_limit` /
`upload_rate_limit` settings.
- **Usage:** command - `btSetTorrentLimits tH, "1000000", "0"`.

### `btSetMaxConnections(in pTorrent as Integer, in pMax as Integer) returns Integer`
Cap the number of peer connections for this torrent (libtorrent wants `>= 2`, or
`-1` for unlimited).
- **Usage:** command - `btSetMaxConnections tH, 80`.

### `btSetMaxUploads(in pTorrent as Integer, in pMax as Integer) returns Integer`
Cap the number of simultaneously **unchoked** upload slots for this torrent.
- **Usage:** command - `btSetMaxUploads tH, 6`.

### `btClearTorrentError(in pTorrent as Integer) returns Integer`
Clear a torrent's error state (e.g. after fixing a disk-full or permission problem
that paused it) so it can resume. Distinct from `btClearError`, which clears the
library's last-error string.
- **Usage:** command - `btClearTorrentError tH`.

### `btScrapeTracker(in pTorrent as Integer) returns Integer`
Ask the tracker(s) for current seed / leecher counts. **Asynchronous**: the
numbers arrive later as a `scrapeReply` event.
- **Usage:** command - `btScrapeTracker tH`, then handle `scrapeReply`.

### `btMoveStorage(in pTorrent as Integer, in pSavePath as String) returns Integer`
Move the torrent's downloaded files to a new directory. **Asynchronous**: success
arrives as a `storageMoved` event (or `fileError` on failure). The bytes move
engine-side; nothing crosses into script.
- **Usage:** command - `btMoveStorage tH, "/mnt/big/downloads"`.

#### Torrent flags

The full `torrent_flags_t` set is exposed as two primitives plus named
conveniences. Flag **values** are the `kFlag*` constants (decimal strings you add
together): `kFlagSeedMode` (1), `kFlagUploadMode` (2), `kFlagShareMode` (4),
`kFlagApplyIpFilter` (8), `kFlagPaused` (16), `kFlagAutoManaged` (32),
`kFlagSuperSeeding` (256), `kFlagSequentialDownload` (512), `kFlagStopWhenReady`
(1024).

### `btSetTorrentFlags(in pTorrent as Integer, in pFlags as String, in pMask as String) returns Integer`
Set the bits named in `pFlags`, touching only the bits named in `pMask` (a
read-modify-write: `set(flags, mask)`). Both are decimal strings - add `kFlag*`
constants to combine them.
- **Usage:** command - `btSetTorrentFlags tH, kFlagSequentialDownload, kFlagSequentialDownload`.

### `btUnsetTorrentFlags(in pTorrent as Integer, in pFlags as String) returns Integer`
Clear the bits named in `pFlags`.
- **Usage:** command - `btUnsetTorrentFlags tH, kFlagSequentialDownload`.

### `btSetSequentialDownload(in pTorrent as Integer, in pOn as Boolean) returns Integer`
Convenience: turn in-order (streaming) download on or off.
- **Usage:** command - `btSetSequentialDownload tH, true`.

### `btSetAutoManaged(in pTorrent as Integer, in pOn as Boolean) returns Integer`
Convenience: let libtorrent automatically queue / start / stop this torrent.
- **Usage:** command - `btSetAutoManaged tH, true`.

### `btSetSuperSeeding(in pTorrent as Integer, in pOn as Boolean) returns Integer`
Convenience: super-seed (initial-seeding) mode - only meaningful on a complete seed.
- **Usage:** command - `btSetSuperSeeding tH, true`.

### `btSetShareMode(in pTorrent as Integer, in pOn as Boolean) returns Integer`
Convenience: optimise this torrent for share-ratio rather than for completion.
- **Usage:** command - `btSetShareMode tH, true`.

### `btSetUploadMode(in pTorrent as Integer, in pOn as Boolean) returns Integer`
Convenience: upload-only - serve pieces but never request any.
- **Usage:** command - `btSetUploadMode tH, true`.

#### Download queue

### `btQueuePosition(in pTorrent as Integer) returns Integer`
The torrent's 0-based position in the download queue, or `-1` if it is not queued
(or the handle is invalid). This getter returns `-1`, not `0`, for "no value",
because `0` is itself a real position - the one getter in the API that does so.
- **Usage:** function - `put btQueuePosition(tH) into tPos`.

### `btQueueUp(in pTorrent as Integer) returns Integer` · `btQueueDown(...)` · `btQueueTop(...)` · `btQueueBottom(...)`
Move the torrent one step up / down, or all the way to the top / bottom of the
download queue. (Only meaningful for auto-managed torrents.)
- **Usage:** command - `btQueueTop tH`.

### `btSaveResumeData(in pTorrent as Integer) returns Integer`
**Request** resume data for the torrent. This is **asynchronous** (libtorrent's
model): the bytes do not return here - they arrive later as a `resumeDataReady`
Expand Down
35 changes: 34 additions & 1 deletion src/btx_abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ extern "C" {
* signature, a new record fieldId or alert code, or a framing change. The LCB
* layer hard-codes the matching number in checkABI() and refuses to run on
* skew. Start at 1. */
#define BTX_ABI_VERSION 3
#define BTX_ABI_VERSION 4

/* ----------------------------------------------------------- export linkage */

Expand Down Expand Up @@ -170,6 +170,39 @@ BTX_API int BTX_CALL btx_set_piece_priority(int t, int pieceIndex, int priority)
BTX_API int BTX_CALL btx_set_torrent_limits(int t, const char *downDec,
const char *upDec);

/* ---- extended control (ABI v4): flags, slots, queue, storage ---------------
* More of libtorrent's torrent_handle surface. torrent_flags_t rides as a
* 64-bit decimal string (there is no 64-bit foreign int): set_flags writes only
* the bits named in `mask`, unset_flags clears the bits named in `flags`. The
* named bit values (sequential_download, auto_managed, share_mode, upload_mode,
* super_seeding, apply_ip_filter, stop_when_ready, ...) are stable libtorrent
* constants the LCB layer mirrors as kFlag*. */
BTX_API int BTX_CALL btx_set_torrent_flags(int t, const char *flagsDec,
const char *maskDec);
BTX_API int BTX_CALL btx_unset_torrent_flags(int t, const char *flagsDec);

/* Per-torrent caps: max peer connections, and max unchoked upload slots. */
BTX_API int BTX_CALL btx_set_max_connections(int t, int maxConns);
BTX_API int BTX_CALL btx_set_max_uploads(int t, int maxUploads);

/* Clear a torrent's error state so it can resume (e.g. after fixing a disk or
* permission problem that paused it). */
BTX_API int BTX_CALL btx_torrent_clear_error(int t);

/* Ask the tracker(s) for current seed/leecher counts; result -> A_SCRAPE_REPLY. */
BTX_API int BTX_CALL btx_scrape_tracker(int t);

/* Move the downloaded files to a new directory; result -> A_STORAGE_MOVED (or
* A_FILE_ERROR on failure). The bytes move engine-side, never through script. */
BTX_API int BTX_CALL btx_move_storage(int t, const char *savePath);

/* Download-queue positioning. btx_queue_position returns the 0-based position,
* or -1 when the torrent is not queued (or the handle is invalid). This is the
* ONE int-getter that uses -1 (not 0) for "no value", because 0 is itself a
* valid queue position. btx_queue_move op: 0=up 1=down 2=top 3=bottom. */
BTX_API int BTX_CALL btx_queue_position(int t);
BTX_API int BTX_CALL btx_queue_move(int t, int op);

/* ====================================================================== *
* Status — ONE snapshot per call (perf: never one FFI call per field, §8)
* ====================================================================== */
Expand Down
168 changes: 167 additions & 1 deletion src/torrent.lcb
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,25 @@ metadata title is "TorrentXT"
-- ===================================================================== --

-- Must equal BTX_ABI_VERSION in src/btx_abi.h; _checkABI() throws on skew.
constant kABIVersion is 3
constant kABIVersion is 4

-- libfoundation MCStringEncoding value for UTF-8 (ASCII=0, Windows1252=1,
-- MacRoman=2, ISO8859_1=3, UTF8=4). Used by _decodeText via MCStringDecode.
constant kEncodingUtf8 is 4

-- torrent_flags_t bit VALUES (stable libtorrent constants; mirror of
-- libtorrent/torrent_flags.hpp). Passed to btSetTorrentFlags / btUnsetTorrentFlags
-- as decimal strings. Combine by adding the values (the bits are disjoint).
constant kFlagSeedMode is "1" -- bit 0: assume we already have all data
constant kFlagUploadMode is "2" -- bit 1: upload only, never request
constant kFlagShareMode is "4" -- bit 2: optimise for share-ratio
constant kFlagApplyIpFilter is "8" -- bit 3: subject this torrent to the IP filter
constant kFlagPaused is "16" -- bit 4: start paused
constant kFlagAutoManaged is "32" -- bit 5: let libtorrent queue/start/stop it
constant kFlagSuperSeeding is "256" -- bit 8: super-seed (initial-seed) mode
constant kFlagSequentialDownload is "512" -- bit 9: download pieces in order (streaming)
constant kFlagStopWhenReady is "1024" -- bit 10: pause as soon as checking finishes

-- Reusable buffer capacities (the single-thread performance playbook: allocate
-- once, reuse every poll, never rebuild). Grown on demand if the shim reports a
-- bigger -needed.
Expand Down Expand Up @@ -201,6 +214,17 @@ private foreign handler _btx_set_file_priorities(in pT as CInt, in pPrios as Poi
private foreign handler _btx_set_piece_priority(in pT as CInt, in pPiece as CInt, in pPrio as CInt) returns CInt binds to "c:torrentxt>btx_set_piece_priority!cdecl"
private foreign handler _btx_set_torrent_limits(in pT as CInt, in pDown as ZStringUTF8, in pUp as ZStringUTF8) returns CInt binds to "c:torrentxt>btx_set_torrent_limits!cdecl"

-- extended control (ABI v4): flags, connection/upload caps, queue, storage
private foreign handler _btx_set_torrent_flags(in pT as CInt, in pFlags as ZStringUTF8, in pMask as ZStringUTF8) returns CInt binds to "c:torrentxt>btx_set_torrent_flags!cdecl"
private foreign handler _btx_unset_torrent_flags(in pT as CInt, in pFlags as ZStringUTF8) returns CInt binds to "c:torrentxt>btx_unset_torrent_flags!cdecl"
private foreign handler _btx_set_max_connections(in pT as CInt, in pMax as CInt) returns CInt binds to "c:torrentxt>btx_set_max_connections!cdecl"
private foreign handler _btx_set_max_uploads(in pT as CInt, in pMax as CInt) returns CInt binds to "c:torrentxt>btx_set_max_uploads!cdecl"
private foreign handler _btx_torrent_clear_error(in pT as CInt) returns CInt binds to "c:torrentxt>btx_torrent_clear_error!cdecl"
private foreign handler _btx_scrape_tracker(in pT as CInt) returns CInt binds to "c:torrentxt>btx_scrape_tracker!cdecl"
private foreign handler _btx_move_storage(in pT as CInt, in pPath as ZStringUTF8) returns CInt binds to "c:torrentxt>btx_move_storage!cdecl"
private foreign handler _btx_queue_position(in pT as CInt) returns CInt binds to "c:torrentxt>btx_queue_position!cdecl"
private foreign handler _btx_queue_move(in pT as CInt, in pOp as CInt) returns CInt binds to "c:torrentxt>btx_queue_move!cdecl"

private foreign handler _btx_torrent_status(in pT as CInt, in pOut as Pointer, in pCap as CInt) returns CInt binds to "c:torrentxt>btx_torrent_status!cdecl"
private foreign handler _btx_torrent_count(in pS as CInt) returns CInt binds to "c:torrentxt>btx_torrent_count!cdecl"
private foreign handler _btx_torrent_handle_at(in pS as CInt, in pIndex as CInt) returns CInt binds to "c:torrentxt>btx_torrent_handle_at!cdecl"
Expand Down Expand Up @@ -848,6 +872,148 @@ public handler btSetTorrentLimits(in pTorrent as Integer, in pDownBytesPerSec as
return tR
end handler

-- ---- extended control (ABI v4): flags, caps, queue, storage --------------

-- Set/clear raw torrent_flags_t bits. pFlags and pMask are decimal strings;
-- combine the kFlag* constants by adding their values. set writes ONLY the
-- masked bits, so set(flags, mask) is the read-modify-write primitive.
public handler btSetTorrentFlags(in pTorrent as Integer, in pFlags as String, in pMask as String) returns Integer
variable tR as Integer
unsafe
put _btx_set_torrent_flags(pTorrent, pFlags, pMask) into tR
end unsafe
return tR
end handler

public handler btUnsetTorrentFlags(in pTorrent as Integer, in pFlags as String) returns Integer
variable tR as Integer
unsafe
put _btx_unset_torrent_flags(pTorrent, pFlags) into tR
end unsafe
return tR
end handler

-- Convenience: toggle one common flag by name (built on the generic pair).
public handler btSetSequentialDownload(in pTorrent as Integer, in pOn as Boolean) returns Integer
if pOn then
return btSetTorrentFlags(pTorrent, kFlagSequentialDownload, kFlagSequentialDownload)
end if
return btUnsetTorrentFlags(pTorrent, kFlagSequentialDownload)
end handler

public handler btSetAutoManaged(in pTorrent as Integer, in pOn as Boolean) returns Integer
if pOn then
return btSetTorrentFlags(pTorrent, kFlagAutoManaged, kFlagAutoManaged)
end if
return btUnsetTorrentFlags(pTorrent, kFlagAutoManaged)
end handler

public handler btSetSuperSeeding(in pTorrent as Integer, in pOn as Boolean) returns Integer
if pOn then
return btSetTorrentFlags(pTorrent, kFlagSuperSeeding, kFlagSuperSeeding)
end if
return btUnsetTorrentFlags(pTorrent, kFlagSuperSeeding)
end handler

public handler btSetShareMode(in pTorrent as Integer, in pOn as Boolean) returns Integer
if pOn then
return btSetTorrentFlags(pTorrent, kFlagShareMode, kFlagShareMode)
end if
return btUnsetTorrentFlags(pTorrent, kFlagShareMode)
end handler

public handler btSetUploadMode(in pTorrent as Integer, in pOn as Boolean) returns Integer
if pOn then
return btSetTorrentFlags(pTorrent, kFlagUploadMode, kFlagUploadMode)
end if
return btUnsetTorrentFlags(pTorrent, kFlagUploadMode)
end handler

-- Per-torrent caps: max peer connections, and max unchoked upload slots.
public handler btSetMaxConnections(in pTorrent as Integer, in pMax as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_set_max_connections(pTorrent, pMax) into tR
end unsafe
return tR
end handler

public handler btSetMaxUploads(in pTorrent as Integer, in pMax as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_set_max_uploads(pTorrent, pMax) into tR
end unsafe
return tR
end handler

-- Clear a torrent's error state so it can resume (after fixing disk/permission).
public handler btClearTorrentError(in pTorrent as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_torrent_clear_error(pTorrent) into tR
end unsafe
return tR
end handler

-- Ask the tracker(s) for current seed/leecher counts (-> scrapeReply event).
public handler btScrapeTracker(in pTorrent as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_scrape_tracker(pTorrent) into tR
end unsafe
return tR
end handler

-- Move the downloaded files to a new folder (-> storageMoved / fileError event).
public handler btMoveStorage(in pTorrent as Integer, in pSavePath as String) returns Integer
variable tR as Integer
unsafe
put _btx_move_storage(pTorrent, pSavePath) into tR
end unsafe
return tR
end handler

-- Download-queue position: 0-based, or -1 if not queued (or invalid handle).
public handler btQueuePosition(in pTorrent as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_queue_position(pTorrent) into tR
end unsafe
return tR
end handler

public handler btQueueUp(in pTorrent as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_queue_move(pTorrent, 0) into tR
end unsafe
return tR
end handler

public handler btQueueDown(in pTorrent as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_queue_move(pTorrent, 1) into tR
end unsafe
return tR
end handler

public handler btQueueTop(in pTorrent as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_queue_move(pTorrent, 2) into tR
end unsafe
return tR
end handler

public handler btQueueBottom(in pTorrent as Integer) returns Integer
variable tR as Integer
unsafe
put _btx_queue_move(pTorrent, 3) into tR
end unsafe
return tR
end handler

-- Request resume data (async; arrives later as a resumeDataReady event whose
-- "resumeData" key holds the bytes to persist).
public handler btSaveResumeData(in pTorrent as Integer) returns Integer
Expand Down
Loading
Loading