summaryrefslogtreecommitdiff
path: root/src/net/i2p_package.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/i2p_package.rs')
-rw-r--r--src/net/i2p_package.rs120
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)
+ }
+}