/** * Pause command for Torm CLI. * * Pauses an active torrent. * * @module cli/commands/pause */ import React, { useEffect, useState } from 'react'; import { render, Text, Box } from 'ink'; import { TormEngine } from '../../engine/TormEngine.js'; import { Torrent } from '../../engine/types.js'; import { successMessage, errorMessage, parseTorrentId, truncateText, } from '../utils/output.js'; // ============================================================================= // Types // ============================================================================= export interface PauseCommandOptions { /** Torrent ID (info hash or prefix) */ torrentId: string; } interface PauseResultProps { torrent: Torrent | null; error: string | null; loading: boolean; success: boolean; } // ============================================================================= // Helper Functions // ============================================================================= /** * Find a torrent by ID (full hash or prefix) */ function findTorrent( engine: TormEngine, torrentId: string ): { torrent: Torrent | undefined; hash: string } { const { type, value } = parseTorrentId(torrentId); if (type === 'hash') { return { torrent: engine.getTorrent(value), hash: value }; } // Search by prefix const torrents = engine.getAllTorrents(); const matches = torrents.filter((t) => t.infoHash.startsWith(value)); if (matches.length === 0) { return { torrent: undefined, hash: value }; } if (matches.length > 1) { throw new Error( `Ambiguous torrent ID "${torrentId}" matches ${matches.length} torrents. ` + 'Please provide a longer prefix.' ); } return { torrent: matches[0], hash: matches[0].infoHash }; } // ============================================================================= // Components // ============================================================================= /** * Component to display the result of pausing a torrent */ const PauseResult: React.FC = ({ torrent, error, loading, success, }) => { if (loading) { return ( Pausing torrent... ); } if (error) { return ( [ERROR] {error} ); } if (success && torrent) { return ( [OK] Torrent paused Name: {truncateText(torrent.name, 50)} Hash: {torrent.infoHash} ); } return null; }; // ============================================================================= // Main Pause Function // ============================================================================= /** * Execute the pause command (non-interactive). * * @param options - Command options */ export async function executePause( options: PauseCommandOptions ): Promise { const { torrentId } = options; const engine = new TormEngine(); try { await engine.start(); const { torrent, hash } = findTorrent(engine, torrentId); if (!torrent) { console.error(errorMessage(`Torrent not found: ${torrentId}`)); await engine.stop(); process.exit(1); } // Pause the torrent await engine.pauseTorrent(hash); console.log(successMessage('Torrent paused')); console.log(` Name: ${truncateText(torrent.name, 50)}`); console.log(` Hash: ${hash}`); await engine.stop(); } catch (err) { const message = err instanceof Error ? err.message : String(err); console.error(errorMessage(message)); if (engine.isRunning()) { await engine.stop(); } process.exit(1); } } /** * Pause command component using Ink for rendering */ export function PauseCommand({ torrentId, }: PauseCommandOptions): React.ReactElement { const [torrent, setTorrent] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const [success, setSuccess] = useState(false); useEffect(() => { const doPause = async () => { const engine = new TormEngine(); try { await engine.start(); const { torrent: foundTorrent, hash } = findTorrent(engine, torrentId); if (!foundTorrent) { setError(`Torrent not found: ${torrentId}`); await engine.stop(); setLoading(false); return; } await engine.pauseTorrent(hash); setTorrent(foundTorrent); setSuccess(true); await engine.stop(); } catch (err) { const message = err instanceof Error ? err.message : String(err); setError(message); if (engine.isRunning()) { await engine.stop(); } } finally { setLoading(false); } }; doPause(); }, [torrentId]); return ( ); } /** * Run the pause command with Ink rendering */ export function runPause(options: PauseCommandOptions): void { const { waitUntilExit } = render(); waitUntilExit().then(() => { process.exit(0); }); } export default executePause;