opendal_service_azdls/
config.rs1use std::fmt::Debug;
19
20use serde::Deserialize;
21use serde::Serialize;
22
23use super::AZDLS_SCHEME;
24use super::backend::AzdlsBuilder;
25
26#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
28#[serde(default)]
29pub struct AzdlsConfig {
30 pub root: Option<String>,
32 pub filesystem: String,
34 pub endpoint: Option<String>,
36 pub account_name: Option<String>,
38 pub account_key: Option<String>,
41 pub client_secret: Option<String>,
45 pub tenant_id: Option<String>,
49 pub client_id: Option<String>,
53 pub sas_token: Option<String>,
57 pub authority_host: Option<String>,
62 pub enable_hns: bool,
66}
67
68impl Debug for AzdlsConfig {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 f.debug_struct("AzdlsConfig")
71 .field("root", &self.root)
72 .field("filesystem", &self.filesystem)
73 .field("endpoint", &self.endpoint)
74 .finish_non_exhaustive()
75 }
76}
77
78impl opendal_core::Configurator for AzdlsConfig {
79 type Builder = AzdlsBuilder;
80
81 fn from_uri(uri: &opendal_core::OperatorUri) -> opendal_core::Result<Self> {
82 let mut map = uri.options().clone();
83 if let Some(authority) = uri.authority() {
84 map.insert("endpoint".to_string(), format!("https://{authority}"));
85 }
86
87 if let Some(account) = uri
88 .name()
89 .and_then(|host| host.split('.').next())
90 .filter(|account| !account.is_empty())
91 {
92 map.entry("account_name".to_string())
93 .or_insert_with(|| account.to_string());
94 }
95
96 if let Some(root) = uri.root() {
97 if let Some((filesystem, rest)) = root.split_once('/') {
98 if filesystem.is_empty() {
99 return Err(opendal_core::Error::new(
100 opendal_core::ErrorKind::ConfigInvalid,
101 "filesystem is required in uri path",
102 )
103 .with_context("service", AZDLS_SCHEME));
104 }
105 map.insert("filesystem".to_string(), filesystem.to_string());
106 if !rest.is_empty() {
107 map.insert("root".to_string(), rest.to_string());
108 }
109 } else if !root.is_empty() {
110 map.insert("filesystem".to_string(), root.to_string());
111 }
112 }
113
114 if !map.contains_key("filesystem") {
115 return Err(opendal_core::Error::new(
116 opendal_core::ErrorKind::ConfigInvalid,
117 "filesystem is required",
118 )
119 .with_context("service", AZDLS_SCHEME));
120 }
121
122 Self::from_iter(map)
123 }
124
125 #[allow(deprecated)]
126 fn into_builder(self) -> Self::Builder {
127 AzdlsBuilder { config: self }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use opendal_core::Configurator;
135 use opendal_core::OperatorUri;
136
137 #[test]
138 fn from_uri_sets_endpoint_filesystem_root_and_account() {
139 let uri = OperatorUri::new(
140 "azdls://account.dfs.core.windows.net/fs/data/2024",
141 Vec::<(String, String)>::new(),
142 )
143 .unwrap();
144
145 let cfg = AzdlsConfig::from_uri(&uri).unwrap();
146 assert_eq!(
147 cfg.endpoint.as_deref(),
148 Some("https://account.dfs.core.windows.net")
149 );
150 assert_eq!(cfg.filesystem, "fs".to_string());
151 assert_eq!(cfg.root.as_deref(), Some("data/2024"));
152 assert_eq!(cfg.account_name.as_deref(), Some("account"));
153 }
154
155 #[test]
156 fn from_uri_accepts_filesystem_from_query() {
157 let uri = OperatorUri::new(
158 "azdls://account.dfs.core.windows.net",
159 vec![("filesystem".to_string(), "logs".to_string())],
160 )
161 .unwrap();
162
163 let cfg = AzdlsConfig::from_uri(&uri).unwrap();
164 assert_eq!(cfg.filesystem, "logs".to_string());
165 }
166}