opendal_service_swift/
config.rs1use std::fmt::Debug;
19
20use serde::Deserialize;
21use serde::Serialize;
22
23use super::SWIFT_SCHEME;
24use super::backend::SwiftBuilder;
25
26#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
28#[serde(default)]
29#[non_exhaustive]
30pub struct SwiftConfig {
31 pub endpoint: Option<String>,
33 pub container: Option<String>,
35 pub root: Option<String>,
37 pub token: Option<String>,
39 pub temp_url_key: Option<String>,
45 pub temp_url_hash_algorithm: Option<String>,
51}
52
53impl Debug for SwiftConfig {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.debug_struct("SwiftConfig")
56 .field("endpoint", &self.endpoint)
57 .field("container", &self.container)
58 .field("root", &self.root)
59 .finish_non_exhaustive()
60 }
61}
62
63impl opendal_core::Configurator for SwiftConfig {
64 type Builder = SwiftBuilder;
65
66 fn from_uri(uri: &opendal_core::OperatorUri) -> opendal_core::Result<Self> {
67 let mut map = uri.options().clone();
68
69 if let Some(authority) = uri.authority() {
70 map.entry("endpoint".to_string())
71 .or_insert_with(|| format!("https://{authority}"));
72 } else if !map.contains_key("endpoint") {
73 return Err(opendal_core::Error::new(
74 opendal_core::ErrorKind::ConfigInvalid,
75 "endpoint is required",
76 )
77 .with_context("service", SWIFT_SCHEME));
78 }
79
80 if let Some(path) = uri.root() {
81 if let Some((container, rest)) = path.split_once('/') {
82 if !container.is_empty() {
83 map.insert("container".to_string(), container.to_string());
84 }
85 if !rest.is_empty() {
86 map.insert("root".to_string(), rest.to_string());
87 }
88 } else if !path.is_empty() {
89 map.insert("container".to_string(), path.to_string());
90 }
91 }
92
93 if !map.contains_key("container") {
94 return Err(opendal_core::Error::new(
95 opendal_core::ErrorKind::ConfigInvalid,
96 "container is required",
97 )
98 .with_context("service", SWIFT_SCHEME));
99 }
100
101 Self::from_iter(map)
102 }
103
104 fn into_builder(self) -> Self::Builder {
105 SwiftBuilder { config: self }
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use opendal_core::Configurator;
113 use opendal_core::OperatorUri;
114
115 #[test]
116 fn from_uri_sets_endpoint_container_and_root() {
117 let uri = OperatorUri::new(
118 "swift://swift.example.com/container/assets/images",
119 Vec::<(String, String)>::new(),
120 )
121 .unwrap();
122
123 let cfg = SwiftConfig::from_uri(&uri).unwrap();
124 assert_eq!(cfg.endpoint.as_deref(), Some("https://swift.example.com"));
125 assert_eq!(cfg.container.as_deref(), Some("container"));
126 assert_eq!(cfg.root.as_deref(), Some("assets/images"));
127 }
128
129 #[test]
130 fn from_uri_accepts_container_from_query() {
131 let uri = OperatorUri::new(
132 "swift://swift.example.com",
133 vec![("container".to_string(), "logs".to_string())],
134 )
135 .unwrap();
136
137 let cfg = SwiftConfig::from_uri(&uri).unwrap();
138 assert_eq!(cfg.container.as_deref(), Some("logs"));
139 assert_eq!(cfg.endpoint.as_deref(), Some("https://swift.example.com"));
140 }
141}