Перейти к содержанию

Tauri-команды: стриминг

Все Tauri-команды стриминга реализованы в src-tauri/src/vozduxan_stream.rs. Они служат мостом между фронтенд-плеером и C++-библиотекой vozduxan.

Источник: src-tauri/src/vozduxan_stream.rs


Справочник команд

torrent_prepare_stream

Запускает или возобновляет воспроизведение конкретного файла в торренте.

// Фронтенд
const ready = await invoke<{ url: string }>("torrent_prepare_stream", {
  magnet: string,
  fileIdx: number,
  torrentFileB64: string | null,   // base64 .torrent файл, или null
});
// ready.url = "http://127.0.0.1:<port>/stream/<token>"

Rust-сторона: декодирует torrentFileB64 из base64, если передан, затем вызывает state.prepare(app, magnet, fileIdx, torrent_bytes). Полная логика token bucket и паттерн version-guard описаны в Rust-обёртка — prepare().

Если torrentFileB64 передан, vozduxan запускает торрент напрямую из бинарного содержимого, пропуская DHT-обмен метаданными. Это экономит несколько секунд при первом воспроизведении треков с RuTracker.

Возвращает: { url: string } — локальный HTTP URL потока.


torrent_release_stream

Освобождает поток по token. Вызывается, когда трек заканчивается, пропускается или компонент размонтируется.

await invoke("torrent_release_stream", { token: string });

Rust-сторона: выполняется в spawn_blocking, так как vozduxan_stream_release ожидает завершения C++ priority-потока (~100 мс). Блокирующий вызов не должен происходить в потоке async executor.

После возврата C++-вызова Rust-сторона: 1. Очищает тот token bucket, в котором находился данный token (current_token, prefetch_token или warm_prefetch_token). 2. Увеличивает счётчик вытеснений. Каждые 10 release вызывает vozduxan_session_evict для удаления из libtorrent-session неактивных торрентов с истёкшим TTL.


torrent_dispose_preview

Освобождает все активные tokens (current + prefetch + warm). Вызывается действием очистки cache в настройках.

Rust-сторона: выполняется в spawn_blocking. Собирает значения всех трёх tokens (извлекая их из mutex) до входа в C++, затем освобождает их последовательно. Этот паттерн «снять mutex до C++» предотвращает сериализацию несвязанных Tauri-команд на ~300 мс суммарного времени ожидания C++ (3 token × ~100 мс каждый).

После освобождения безусловно вызывает vozduxan_session_evict.


torrent_prepare_cancel

Отменяет выполняющийся вызов torrent_prepare_stream.

await invoke("torrent_prepare_cancel");

Устанавливает prepare_cancelled AtomicBool в true. Цикл prepare() в Rust проверяет этот флаг и возвращает ошибку, когда он установлен. Используется плеером, когда пользователь переключает трек до завершения буферизации текущего.


torrent_prefetch_next_track

Прогревает окно приоритетов кусков следующего трека, не прерывая текущий.

const result = await invoke("torrent_prefetch_next_track", {
  currentMagnet: string,
  currentFileIdx: number,
  nextMagnet: string,
  nextFileIdx: number,
  nextTorrentFileB64: string | null,
  warmOnly: boolean,   // false = bucket track+1, true = bucket track+2
});

currentMagnet и currentFileIdx принимаются для совместимости API, но в пути vozduxan не используются — vozduxan управляет активной session внутренне и не нуждается в идентификаторе текущего трека для планирования prefetch.

warmOnly = false → сохраняется в prefetch_token (настоящий следующий трек). warmOnly = true → сохраняется в warm_prefetch_token (прогрев второго трека вперёд).


vozduxan_notify_position

Передаёт текущее байтовое смещение воспроизведения планировщику приоритетов C++.

await invoke("vozduxan_notify_position", {
  token: string,
  byteOffset: number,  // текущая позиция воспроизведения в байтах
});

Вызывается на каждое событие timeupdate от элемента <audio> и при перемотке. C++ priority worker использует это для сдвига окна приоритетов кусков вперёд.

Эта команда не блокирует на Rust-стороне — она вызывает notify_position, который немедленно записывает в структуру состояния token без конкуренции за mutex на стороне C++.


vozduxan_stream_stats

Возвращает скорость загрузки и количество peers для token потока. Используется всплывающим окном статуса потока в пользовательском интерфейсе плеера.

const stats = await invoke<{ downloadRate: number; numPeers: number }>(
  "vozduxan_stream_stats",
  { token: string }
);

Вызывает vozduxan_stream_stats в C++ напрямую — spawn_blocking не нужен, так как функция только читает из легковесных полей статистики.


torrent_magnet_list_files

Перечисляет файлы внутри magnet/torrent без запуска воспроизведения.

const files = await invoke<TorrentFile[]>("torrent_magnet_list_files", {
  magnet: string,
});

Используется для перечисления файлов до того, как пользователь выберет конкретный трек для воспроизведения. Вызывает state.list_files(magnet, None) — см. Rust-обёртка.


Дисциплина spawn_blocking

Команды, вызывающие C++-код, блокирующий на значительное время (ожидание завершения priority-потока, вытеснение), используют tokio::task::spawn_blocking. Это переносит блокирующий вызов с пула потоков async executor, предотвращая голодание других ожидающих команд.

Паттерн:

tokio::task::spawn_blocking(move || {
    // C++-вызов здесь (может блокировать на ~100 мс)
    unsafe { ffi::vozduxan_stream_release(inner.ptr, token_c.as_ptr()) };
    // очистка после C++
})
.await
.map_err(|e| format!("spawn_blocking error: {e}"))

Команды, которые только читают легковесную статистику или записывают флаги (vozduxan_notify_position, torrent_prepare_cancel), не требуют spawn_blocking.