diff options
Diffstat (limited to 'src/net/i2p_package.rs')
| -rw-r--r-- | src/net/i2p_package.rs | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/net/i2p_package.rs b/src/net/i2p_package.rs new file mode 100644 index 0000000..2776eea --- /dev/null +++ b/src/net/i2p_package.rs @@ -0,0 +1,120 @@ + +use crate::cfg::config::Config; + +use tokio; +/* +use emissary_core::runtime::{ + AsyncRead, + AsyncWrite, +}; +*/ + +use std::{fs::File, + path::Path, + io::Write}; +// use emissary_core::Profile; +// use emissary_core::i2np::Message; +use tokio::io::{AsyncReadExt, + AsyncWriteExt, + BufReader}; + +use yosemite::SessionOptions; +use yosemite::{Session, style::Stream}; +use url; + +pub struct I2PPackage { + config: Config, + +} + + +impl I2PPackage { + /// Creates a new I2P object with the given configuration. + /// + /// # Returns + /// + /// A new I2P object with the given configuration. The session is initially set to None and the connected status is set to false. + pub fn new(config: Config) -> Self { + I2PPackage{ + + config: config, + } + } + + + /// Downloads the INDEX.tar.gz file from the configured repository + /// and stores it in the configured cache directory. + /// + /// # Errors + /// + /// Returns an error if the request fails, if the response status is not successful, or if there's an issue while reading or writing the file. + pub async fn fetch_index(&mut self) -> Result<bool, std::io::Error> { + let repo_url_str = &self.config.repo.repo_url; + let cache_dir = &self.config.paths.cache_dir; + + let url = url::Url::parse(repo_url_str) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid repo URL"))?; + + let host = url.host_str() + .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::InvalidInput, "No host in URL"))?; + + let request_path = url.path(); + let request_path = if request_path.ends_with(".tar.gz") { + request_path.to_string() + } else { + format!("{}/INDEX.tar.gz", request_path.trim_end_matches('/')) + }; + + let sam_host = "127.0.0.1"; + let sam_port = 7656; + let session_options = SessionOptions::default(); + let mut session = Session::new(session_options).await + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to create SAM session: {}", e)))?; + + let mut stream = session.connect(host).await + .map_err(|e| std::io::Error::new(std::io::ErrorKind::ConnectionAborted, format!("Failed to connect: {}", e)))?; + + let request = format!( + "GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", + request_path, host + ); + + + stream.write_all(request.as_bytes()).await + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to write request: {}", e)))?; + + let mut reader = BufReader::new(stream); + let mut response_buffer = Vec::new(); + reader.read_to_end(&mut response_buffer).await + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to read response: {}", e)))?; + + + let headers_end = response_buffer + .windows(4) + .position(|window| window == b"\r\n\r\n") + .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid response: no headers end"))?; + + let headers_str = std::str::from_utf8(&response_buffer[..headers_end]) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid header encoding"))?; + + if !headers_str.starts_with("HTTP/1.1 200") && !headers_str.starts_with("HTTP/1.0 200") { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("HTTP Error: {}", headers_str.lines().next().unwrap_or("Unknown")), + )); + } + + let body_start = headers_end + 4; + let file_path = Path::new(cache_dir).join("INDEX.tar.gz"); + + + let mut file = File::create(&file_path) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to create file: {}", e)))?; + file.write_all(&response_buffer[body_start..]) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to write file: {}", e)))?; + file.flush() + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to flush file: {}", e)))?; + + Ok(true) + } +} |
