torrust-actix 4.2.3

A rich, fast and efficient Bittorrent Tracker.
use crate::rtctorrent_bridge::enums::rtc_torrent_bridge_error::RtcTorrentBridgeError;
use crate::rtctorrent_bridge::structs::rtc_torrent_bridge::RtcTorrentBridge;
use serde_json::Value;
use std::process::Command;

impl RtcTorrentBridge {
    pub fn new(tracker_url: String) -> Self {
        Self { tracker_url }
    }

    pub fn create_torrent(&self, file_path: &str, torrent_name: Option<&str>) -> Result<Value, RtcTorrentBridgeError> {
        if !std::path::Path::new(file_path).exists() {
            return Err(RtcTorrentBridgeError::FileNotFoundError(
                format!("File does not exist: {file_path}")
            ));
        }
        let js_command = format!(
            r"
            const fs = require('fs');
            const path = require('path');
            const RtcTorrentLib = require('./lib/rtctorrent/dist/rtctorrent.node.js');
            const RtcTorrent = RtcTorrentLib.default || RtcTorrentLib.RtcTorrent || RtcTorrentLib;
            (async () => {{
                try {{
                    const client = new RtcTorrent({{
                        trackerUrl: '{}'
                    }});
                    const stat = fs.statSync('{}');
                    const fileObj = {{
                        path: '{}',
                        name: path.basename('{}'),
                        size: stat.size
                    }};
                    const result = await client.create([fileObj], {{
                        name: '{}'
                    }});
                    console.log(JSON.stringify(result));
                }} catch (error) {{
                    console.error('Error creating torrent:', error);
                    process.exit(1);
                }}
            }})();
            ",
            self.tracker_url,
            file_path,
            file_path,
            file_path,
            torrent_name.unwrap_or("Generated Torrent")
        );
        let output = Command::new("node")
            .arg("-e")
            .arg(js_command)
            .output()
            .map_err(|e| RtcTorrentBridgeError::CommandExecutionError(e.to_string()))?;
        if !output.status.success() {
            return Err(RtcTorrentBridgeError::CommandExecutionError(
                String::from_utf8_lossy(&output.stderr).to_string()
            ));
        }
        let result_str = String::from_utf8(output.stdout)
            .map_err(|e| RtcTorrentBridgeError::JsonParseError(e.to_string()))?;
        serde_json::from_str(&result_str)
            .map_err(|e| RtcTorrentBridgeError::JsonParseError(e.to_string()))
    }

    pub fn seed_torrent(&self, torrent_path: &str) -> Result<Value, RtcTorrentBridgeError> {
        if !std::path::Path::new(torrent_path).exists() {
            return Err(RtcTorrentBridgeError::FileNotFoundError(
                format!("Torrent file does not exist: {torrent_path}")
            ));
        }
        let js_command = format!(
            r"
            const fs = require('fs');
            const RtcTorrentLib = require('./lib/rtctorrent/dist/rtctorrent.node.js');
            const RtcTorrent = RtcTorrentLib.default || RtcTorrentLib.RtcTorrent || RtcTorrentLib;
            (async () => {{
                try {{
                    const client = new RtcTorrent({{
                        trackerUrl: '{}',
                        announceInterval: 30000,
                        rtcInterval: 10000
                    }});
                    const torrentBuffer = fs.readFileSync('{}');
                    const torrent = await client.seed(torrentBuffer);
                    console.log(JSON.stringify({{
                        success: true,
                        infoHash: torrent.data.infoHash,
                        peers: torrent.peers.size
                    }}));
                }} catch (error) {{
                    console.error('Error seeding torrent:', error);
                    process.exit(1);
                }}
            }})();
            ",
            self.tracker_url,
            torrent_path
        );
        let output = Command::new("node")
            .arg("-e")
            .arg(js_command)
            .output()
            .map_err(|e| RtcTorrentBridgeError::CommandExecutionError(e.to_string()))?;
        if !output.status.success() {
            return Err(RtcTorrentBridgeError::CommandExecutionError(
                String::from_utf8_lossy(&output.stderr).to_string()
            ));
        }
        let result_str = String::from_utf8(output.stdout)
            .map_err(|e| RtcTorrentBridgeError::JsonParseError(e.to_string()))?;
        serde_json::from_str(&result_str)
            .map_err(|e| RtcTorrentBridgeError::JsonParseError(e.to_string()))
    }

    pub fn download_torrent(&self, torrent_identifier: &str) -> Result<Value, RtcTorrentBridgeError> {
        let js_command = if torrent_identifier.starts_with("magnet:") {
            format!(
                r"
                const RtcTorrentLib = require('./lib/rtctorrent/dist/rtctorrent.node.js');
                const RtcTorrent = RtcTorrentLib.default || RtcTorrentLib.RtcTorrent || RtcTorrentLib;
                (async () => {{
                    try {{
                        const client = new RtcTorrent({{
                            trackerUrl: '{}',
                            announceInterval: 30000,
                            rtcInterval: 10000
                        }});
                        const torrent = await client.download('{}');
                        console.log(JSON.stringify({{
                            success: true,
                            infoHash: torrent.data.infoHash,
                            downloaded: torrent.downloaded,
                            totalSize: torrent.totalSize
                        }}));
                    }} catch (error) {{
                        console.error('Error downloading torrent:', error);
                        process.exit(1);
                    }}
                }})();
                ",
                self.tracker_url,
                torrent_identifier
            )
        } else {
            if !std::path::Path::new(torrent_identifier).exists() {
                return Err(RtcTorrentBridgeError::FileNotFoundError(
                    format!("Torrent file does not exist: {torrent_identifier}")
                ));
            }
            format!(
                r"
                const fs = require('fs');
                const RtcTorrentLib = require('./lib/rtctorrent/dist/rtctorrent.node.js');
                const RtcTorrent = RtcTorrentLib.default || RtcTorrentLib.RtcTorrent || RtcTorrentLib;
                (async () => {{
                    try {{
                        const client = new RtcTorrent({{
                            trackerUrl: '{}',
                            announceInterval: 30000,
                            rtcInterval: 10000
                        }});
                        const torrentBuffer = fs.readFileSync('{}');
                        const torrent = await client.download(torrentBuffer);
                        console.log(JSON.stringify({{
                            success: true,
                            infoHash: torrent.data.infoHash,
                            downloaded: torrent.downloaded,
                            totalSize: torrent.totalSize
                        }}));
                    }} catch (error) {{
                        console.error('Error downloading torrent:', error);
                        process.exit(1);
                    }}
                }})();
                ",
                self.tracker_url,
                torrent_identifier
            )
        };
        let output = Command::new("node")
            .arg("-e")
            .arg(js_command)
            .output()
            .map_err(|e| RtcTorrentBridgeError::CommandExecutionError(e.to_string()))?;
        if !output.status.success() {
            return Err(RtcTorrentBridgeError::CommandExecutionError(
                String::from_utf8_lossy(&output.stderr).to_string()
            ));
        }
        let result_str = String::from_utf8(output.stdout)
            .map_err(|e| RtcTorrentBridgeError::JsonParseError(e.to_string()))?;
        serde_json::from_str(&result_str)
            .map_err(|e| RtcTorrentBridgeError::JsonParseError(e.to_string()))
    }
}