opendal/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 authority = uri.authority().ok_or_else(|| {
58 crate::Error::new(crate::ErrorKind::ConfigInvalid, "uri authority is required")
59 .with_context("service", AZFILE_SCHEME)
60 })?;
61
62 let mut map = uri.options().clone();
63 map.insert("endpoint".to_string(), format!("https://{authority}"));
64
65 if let Some(host) = uri.name() {
66 if let Some(account) = host.split('.').next() {
67 if !account.is_empty() {
68 map.entry("account_name".to_string())
69 .or_insert_with(|| account.to_string());
70 }
71 }
72 }
73
74 if let Some(root) = uri.root() {
75 if let Some((share, rest)) = root.split_once('/') {
76 if share.is_empty() {
77 return Err(crate::Error::new(
78 crate::ErrorKind::ConfigInvalid,
79 "share name is required in uri path",
80 )
81 .with_context("service", AZFILE_SCHEME));
82 }
83 map.insert("share_name".to_string(), share.to_string());
84 if !rest.is_empty() {
85 map.insert("root".to_string(), rest.to_string());
86 }
87 } else if !root.is_empty() {
88 map.insert("share_name".to_string(), root.to_string());
89 }
90 }
91
92 if !map.contains_key("share_name") {
93 return Err(crate::Error::new(
94 crate::ErrorKind::ConfigInvalid,
95 "share name is required",
96 )
97 .with_context("service", AZFILE_SCHEME));
98 }
99
100 Self::from_iter(map)
101 }
102
103 #[allow(deprecated)]
104 fn into_builder(self) -> Self::Builder {
105 AzfileBuilder {
106 config: self,
107 http_client: None,
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use crate::Configurator;
116 use crate::types::OperatorUri;
117
118 #[test]
119 fn from_uri_sets_endpoint_share_root_and_account() {
120 let uri = OperatorUri::new(
121 "azfile://account.file.core.windows.net/share/documents/reports",
122 Vec::<(String, String)>::new(),
123 )
124 .unwrap();
125
126 let cfg = AzfileConfig::from_uri(&uri).unwrap();
127 assert_eq!(
128 cfg.endpoint.as_deref(),
129 Some("https://account.file.core.windows.net")
130 );
131 assert_eq!(cfg.share_name, "share".to_string());
132 assert_eq!(cfg.root.as_deref(), Some("documents/reports"));
133 assert_eq!(cfg.account_name.as_deref(), Some("account"));
134 }
135
136 #[test]
137 fn from_uri_accepts_share_from_query() {
138 let uri = OperatorUri::new(
139 "azfile://account.file.core.windows.net",
140 vec![("share_name".to_string(), "data".to_string())],
141 )
142 .unwrap();
143
144 let cfg = AzfileConfig::from_uri(&uri).unwrap();
145 assert_eq!(
146 cfg.endpoint.as_deref(),
147 Some("https://account.file.core.windows.net")
148 );
149 assert_eq!(cfg.share_name, "data".to_string());
150 }
151}