From 4e6db3fa2155eb9a2c95d638085e8e46e339564f Mon Sep 17 00:00:00 2001 From: Warren Lo Date: Thu, 19 Mar 2026 00:32:44 +0800 Subject: [PATCH] Add cloud.rs for cloud input --- src/input/cloud.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/input/cloud.rs diff --git a/src/input/cloud.rs b/src/input/cloud.rs new file mode 100644 index 0000000..959c8b0 --- /dev/null +++ b/src/input/cloud.rs @@ -0,0 +1,77 @@ +//! 雲端輸入 + +use anyhow::Result; + +#[derive(Debug, Clone)] +pub enum CloudSource { + S3 { + bucket: String, + key: String, + region: Option, + }, + Http { + url: String, + headers: Vec<(String, String)>, + }, +} + +impl CloudSource { + pub fn from_s3_url(url: &str) -> Result { + let parsed = url::Url::parse(url)?; + + if parsed.scheme() != "s3" { + anyhow::bail!("Not an S3 URL"); + } + + let bucket = parsed.host_str().unwrap_or("").to_string(); + let key = parsed.path().trim_start_matches('/').to_string(); + + Ok(Self::S3 { + bucket, + key, + region: None, + }) + } + + pub fn from_http_url(url: &str) -> Self { + Self::Http { + url: url.to_string(), + headers: Vec::new(), + } + } +} + +pub struct CloudInput { + source: Option, +} + +impl CloudInput { + pub fn new() -> Self { + Self { source: None } + } + + pub fn open(&mut self, url: &str) -> Result { + let source = if url.starts_with("s3://") { + CloudSource::from_s3_url(url)? + } else if url.starts_with("http://") || url.starts_with("https://") { + CloudSource::from_http_url(url) + } else { + anyhow::bail!("Unsupported URL scheme"); + }; + + self.source = Some(source.clone()); + Ok(source) + } + + pub fn get_stream_url(&self) -> Option { + match &self.source { + Some(CloudSource::S3 { bucket, key, .. }) => { + Some(format!("https://{}.s3.amazonaws.com/{}", bucket, key)) + } + Some(CloudSource::Http { url, .. }) => { + Some(url.clone()) + } + None => None, + } + } +}