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 {
128 config: self,
129 credential_providers: None,
130 }
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use opendal_core::Configurator;
138 use opendal_core::OperatorUri;
139
140 #[test]
141 fn from_uri_sets_endpoint_filesystem_root_and_account() {
142 let uri = OperatorUri::new(
143 "azdls://account.dfs.core.windows.net/fs/data/2024",
144 Vec::<(String, String)>::new(),
145 )
146 .unwrap();
147
148 let cfg = AzdlsConfig::from_uri(&uri).unwrap();
149 assert_eq!(
150 cfg.endpoint.as_deref(),
151 Some("https://account.dfs.core.windows.net")
152 );
153 assert_eq!(cfg.filesystem, "fs".to_string());
154 assert_eq!(cfg.root.as_deref(), Some("data/2024"));
155 assert_eq!(cfg.account_name.as_deref(), Some("account"));
156 }
157
158 #[test]
159 fn from_uri_accepts_filesystem_from_query() {
160 let uri = OperatorUri::new(
161 "azdls://account.dfs.core.windows.net",
162 vec![("filesystem".to_string(), "logs".to_string())],
163 )
164 .unwrap();
165
166 let cfg = AzdlsConfig::from_uri(&uri).unwrap();
167 assert_eq!(cfg.filesystem, "logs".to_string());
168 }
169}