返回 CodeWhale
provider_setup.rs
根目录 / crates / tui / src / tui / ui / provider_setup.rs
1 //! Provider-configuration support: runtime-preset file snapshots with
2 //! rollback, and the provider key verification seam
3 //! (TUI_MODULARIZATION.md slice 8).
4
5 use super::*;
6
7 pub(crate) trait ProviderKeyVerifier {
8 fn verify<'a>(
9 &'a self,
10 provider: ApiProvider,
11 api_key: &'a str,
12 base_url: &'a str,
13 ) -> ProviderKeyVerification<'a>;
14 }
15
16 pub(crate) struct LiveProviderKeyVerifier;
17
18 impl ProviderKeyVerifier for LiveProviderKeyVerifier {
19 fn verify<'a>(
20 &'a self,
21 provider: ApiProvider,
22 api_key: &'a str,
23 base_url: &'a str,
24 ) -> ProviderKeyVerification<'a> {
25 Box::pin(crate::client::verify_provider_api_key(
26 provider, api_key, base_url,
27 ))
28 }
29 }
30
31 pub(crate) struct RuntimePresetFileSnapshot {
32 pub(crate) path: PathBuf,
33 pub(crate) contents: Option<Vec<u8>>,
34 }
35
36 impl RuntimePresetFileSnapshot {
37 pub(crate) fn capture(path: PathBuf) -> Result<Self> {
38 let contents = match std::fs::read(&path) {
39 Ok(contents) => Some(contents),
40 Err(error) if error.kind() == io::ErrorKind::NotFound => None,
41 Err(error) => {
42 return Err(error)
43 .with_context(|| format!("failed to snapshot {}", path.display()));
44 }
45 };
46 Ok(Self { path, contents })
47 }
48
49 fn restore(&self) -> Result<()> {
50 match &self.contents {
51 Some(contents) => crate::utils::write_atomic(&self.path, contents)
52 .with_context(|| format!("failed to restore {}", self.path.display())),
53 None => match std::fs::remove_file(&self.path) {
54 Ok(()) => Ok(()),
55 Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(()),
56 Err(error) => {
57 Err(error).with_context(|| format!("failed to remove {}", self.path.display()))
58 }
59 },
60 }
61 }
62 }
63
64 pub(crate) fn runtime_preset_error_with_rollback(
65 error: anyhow::Error,
66 snapshots: &[&RuntimePresetFileSnapshot],
67 ) -> anyhow::Error {
68 let rollback_errors = snapshots
69 .iter()
70 .filter_map(|snapshot| snapshot.restore().err())
71 .map(|error| format!("{error:#}"))
72 .collect::<Vec<_>>();
73 if rollback_errors.is_empty() {
74 error
75 } else {
76 anyhow::anyhow!(
77 "{error:#}; runtime preset rollback also failed: {}",
78 rollback_errors.join("; ")
79 )
80 }
81 }
82
82 lines RUST