opendal_core/services/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 crate::Configurator for AzfileConfig {
54 type Builder = AzfileBuilder;
55
56 fn from_uri(uri: &crate::types::OperatorUri) -> crate::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(host) = uri.name() {
63 if let Some(account) = host.split('.').next() {
64 if !account.is_empty() {
65 map.entry("account_name".to_string())
66 .or_insert_with(|| account.to_string());
67 }
68 }
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(crate::Error::new(
75 crate::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(crate::Error::new(
91 crate::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 {
103 config: self,
104 http_client: None,
105 }
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use crate::Configurator;
113 use crate::types::OperatorUri;
114
115 #[test]
116 fn from_uri_sets_endpoint_share_root_and_account() {
117 let uri = OperatorUri::new(
118 "azfile://account.file.core.windows.net/share/documents/reports",
119 Vec::<(String, String)>::new(),
120 )
121 .unwrap();
122
123 let cfg = AzfileConfig::from_uri(&uri).unwrap();
124 assert_eq!(
125 cfg.endpoint.as_deref(),
126 Some("https://account.file.core.windows.net")
127 );
128 assert_eq!(cfg.share_name, "share".to_string());
129 assert_eq!(cfg.root.as_deref(), Some("documents/reports"));
130 assert_eq!(cfg.account_name.as_deref(), Some("account"));
131 }
132
133 #[test]
134 fn from_uri_accepts_share_from_query() {
135 let uri = OperatorUri::new(
136 "azfile://account.file.core.windows.net",
137 vec![("share_name".to_string(), "data".to_string())],
138 )
139 .unwrap();
140
141 let cfg = AzfileConfig::from_uri(&uri).unwrap();
142 assert_eq!(
143 cfg.endpoint.as_deref(),
144 Some("https://account.file.core.windows.net")
145 );
146 assert_eq!(cfg.share_name, "data".to_string());
147 }
148}