summaryrefslogtreecommitdiff
path: root/src/i2impl
diff options
context:
space:
mode:
authorNamilskyy <alive6863@gmail.com>2025-11-26 22:07:47 +0300
committerNamilskyy <alive6863@gmail.com>2025-11-26 22:07:47 +0300
commitcfb0e5909b379c92411d5373758c7ba9c6b04357 (patch)
tree4e1cb3057865cfb9e79e26134d2aa70518f22598 /src/i2impl
parent691aadb4c28a93be7bfb7d87b245702795cfd4ca (diff)
Refactor i2p/fetch() function
Diffstat (limited to 'src/i2impl')
-rw-r--r--src/i2impl/mi2p.rs76
1 files changed, 66 insertions, 10 deletions
diff --git a/src/i2impl/mi2p.rs b/src/i2impl/mi2p.rs
index e0bbe3d..6d095f9 100644
--- a/src/i2impl/mi2p.rs
+++ b/src/i2impl/mi2p.rs
@@ -2,15 +2,18 @@
use crate::cfg::config::Config;
use tokio;
-
use emissary_core::runtime::{
AsyncRead,
AsyncWrite,
};
-use std::io;
-use emissary_core::Profile;
-use emissary_core::i2np::Message;
-use tokio::io::AsyncWriteExt;
+
+use std::{io,
+ fs::File,
+ path::Path,
+ io::Write};
+// use emissary_core::Profile;
+// use emissary_core::i2np::Message;
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
use yosemite::SessionOptions;
use yosemite::{Session, style::Stream};
/*
@@ -70,25 +73,30 @@ impl<S> I2P<S> {
///
/// Returns an error if the repository URL is invalid or if the request fails.
///
- async fn fetch(&mut self) -> Result<bool, std::io::Error> {
+ 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 repo_pos = repo_url_str.find("/repo").ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, "URL does not contain '/repo'")
})?;
+ // BaseURL
let base_url = &repo_url_str[..repo_pos];
+ // Url after /repo
let path_suffix = &repo_url_str[repo_pos + "/repo".len()..];
+ // HTTP path
let request_path = format!("/repo{}{}", path_suffix, if path_suffix.ends_with(".tar.gz") { "" } else { "/INDEX.tar.gz" });
- let opts = SessionOptions::default();
+ let mut opts = SessionOptions::default();
+ // FIXME: Make sure, opts setted to I2P
// opts.set_host("127.0.0.1");
- // opts.set_port(7656);
+ // opts.set_port(7656);
let mut session = Session::<Stream>::new(opts).await.map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("Failed to create session: {}", e))
})?;
let mut stream = session.connect(base_url).await.map_err(|e| {
- io::Error::new(io::ErrorKind::ConnectionReset, format!("Failed to connect: {}", e))
+ io::Error::new(io::ErrorKind::ConnectionAborted, format!("Failed to connect: {}", e))
})?;
let request = format!("GET {} HTTP/1.1\r\nHost: {}\r\n\r\n", request_path, base_url);
@@ -96,6 +104,54 @@ impl<S> I2P<S> {
io::Error::new(io::ErrorKind::Other, format!("Failed to write request: {}", e))
})?;
+ let mut response_buffer = Vec::new();
+ let mut chunk = [0u8; 1024];
+
+ loop {
+ // FIXME: Check docs and make suro stream allows to AsyncReadExt
+ let bytes_read = stream.read(&mut chunk).await.map_err(|e| {
+ io::Error::new(io::ErrorKind::Other, format!("Failed to read response: {}", e))
+ })?;
+
+ if bytes_read == 0 {
+ break;
+ }
+
+ response_buffer.extend_from_slice(&chunk[..bytes_read]);
+
+ if let Some(headers_end) = Self::find_double_crlf(&response_buffer) {
+ let body_start = headers_end + 4;
+ let headers_str = std::str::from_utf8(&response_buffer[..headers_end])
+ .map_err(|_| io::Error::new(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(io::Error::new(io::ErrorKind::Other, format!("HTTP Error: {}", headers_str.lines().next().unwrap_or("Unknown"))));
+ }
+
+ let file_path = Path::new(cache_dir).join("INDEX.tar.gz");
+ let mut file = File::create(&file_path)?;
+ file.write_all(&response_buffer[body_start..])?;
+ while let Ok(bytes_read) = stream.read(&mut chunk).await {
+ if bytes_read == 0 {
+ break;
+ }
+ file.write_all(&chunk[..bytes_read])?;
+ }
+
+ file.flush()?;
+ break;
+ }
+ }
+
Ok(true)
-}
+ }
+
+ fn find_double_crlf(buf: &[u8]) -> Option<usize> {
+ for i in 0..buf.len().saturating_sub(3) {
+ if buf[i] == b'\r' && buf[i+1] == b'\n' && buf[i+2] == b'\r' && buf[i+3] == b'\n' {
+ return Some(i);
+ }
+ }
+ None
+ }
} \ No newline at end of file