opendal_service_azfile/
config.rs1use std::fmt::Debug;
19
20use serde::Deserialize;
21use serde::Serialize;
22
23use super::AZFILE_SCHEME;
24use super::backend::AzfileBuilder;
25
26#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
28pub struct AzfileConfig {
29 pub root: Option<String>,
31 pub endpoint: Option<String>,
33 pub share_name: String,
35 pub account_name: Option<String>,
37 pub account_key: Option<String>,
39 pub sas_token: Option<String>,
41}
42
43impl Debug for AzfileConfig {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 f.debug_struct("AzfileConfig")
46 .field("root", &self.root)
47 .field("endpoint", &self.endpoint)
48 .field("share_name", &self.share_name)
49 .finish_non_exhaustive()
50 }
51}
52
53impl opendal_core::Configurator for AzfileConfig {
54 type Builder = AzfileBuilder;
55
56 fn from_uri(uri: &opendal_core::OperatorUri) -> opendal_core::Result<Self> {
57 let mut map = uri.options().clone();
58 if let Some(authority) = uri.authority() {
59 map.insert("endpoint".to_string(), format!("https://{authority}"));
60 }
61
62 if let Some(account) = uri
63 .name()
64 .and_then(|host| host.split('.').next())
65 .filter(|account| !account.is_empty())
66 {
67 map.entry("account_name".to_string())
68 .or_insert_with(|| account.to_string());
69 }
70
71 if let Some(root) = uri.root() {
72 if let Some((share, rest)) = root.split_once('/') {
73 if share.is_empty() {
74 return Err(opendal_core::Error::new(
75 opendal_core::ErrorKind::ConfigInvalid,
76 "share name is required in uri path",
77 )
78 .with_context("service", AZFILE_SCHEME));
79 }
80 map.insert("share_name".to_string(), share.to_string());
81 if !rest.is_empty() {
82 map.insert("root".to_string(), rest.to_string());
83 }
84 } else if !root.is_empty() {
85 map.insert("share_name".to_string(), root.to_string());
86 }
87 }
88
89 if !map.contains_key("share_name") {
90 return Err(opendal_core::Error::new(
91 opendal_core::ErrorKind::ConfigInvalid,
92 "share name is required",
93 )
94 .with_context("service", AZFILE_SCHEME));
95 }
96
97 Self::from_iter(map)
98 }
99
100 #[allow(deprecated)]
101 fn into_builder(self) -> Self::Builder {
102 AzfileBuilder { config: self }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use opendal_core::Configurator;
110 use opendal_core::OperatorUri;
111
112 #[test]
113 fn from_uri_sets_endpoint_share_root_and_account() {
114 let uri = OperatorUri::new(
115 "azfile://account.file.core.windows.net/share/documents/reports",
116 Vec::<(String, String)>::new(),
117 )
118 .unwrap();
119
120 let cfg = AzfileConfig::from_uri(&uri).unwrap();
121 assert_eq!(
122 cfg.endpoint.as_deref(),
123 Some("https://account.file.core.windows.net")
124 );
125 assert_eq!(cfg.share_name, "share".to_string());
126 assert_eq!(cfg.root.as_deref(), Some("documents/reports"));
127 assert_eq!(cfg.account_name.as_deref(), Some("account"));
128 }
129
130 #[test]
131 fn from_uri_accepts_share_from_query() {
132 let uri = OperatorUri::new(
133 "azfile://account.file.core.windows.net",
134 vec![("share_name".to_string(), "data".to_string())],
135 )
136 .unwrap();
137
138 let cfg = AzfileConfig::from_uri(&uri).unwrap();
139 assert_eq!(
140 cfg.endpoint.as_deref(),
141 Some("https://account.file.core.windows.net")
142 );
143 assert_eq!(cfg.share_name, "data".to_string());
144 }
145}