openai_client_cli/program/loaders/
organization.rs1use crate::{Entry, Error, Result, traits::*};
2use regex::Regex;
3use shellexpand::path::tilde;
4use std::{env, fs, path::{Path, PathBuf}, str::FromStr};
5use tracing::{debug, info};
6
7pub struct Organization(String);
9
10impl Organization {
11 fn post_fetch_ok(self, source: &str) -> Result<Self> {
12 info!(
13 "Successfully fetched the organization ID from {source}: {:?}",
14 format!("{}...{}", &self.value_ref()[..7], &self.value_ref()[26..]),
15 );
16 Ok(self)
17 }
18}
19
20impl FromFile for Organization {
21 fn from_file<P>(path: P) -> Result<Self>
22 where
23 P: AsRef<Path>,
24 {
25 let text = fs::read_to_string(path)?;
26 Self::from_str(&text)
27 }
28}
29
30impl FromStr for Organization {
31 type Err = Error;
32
33 fn from_str(text: &str) -> Result<Self> {
34 Ok(Self(
35 Regex::new(r"org-[[:alnum:]]{24}")?
36 .find(text)
37 .ok_or(Error::msg("Invalid format of OpenAI organization ID"))?
38 .as_str()
39 .to_string()
40 ))
41 }
42}
43
44impl Loader<String> for Organization {
45 fn fetch(entry: &Entry) -> Result<Self> {
46 for provided_file in [
47 entry.organization_file.as_ref(),
48 entry.key_file.as_ref(),
49 ]
50 .into_iter()
51 .flatten()
52 {
53 let source = &format!("the provided file {provided_file:?}");
54 match Organization::from_file(provided_file) {
55 Ok(organization) => return organization.post_fetch_ok(source),
56 Err(err) => debug!("Failed to obtain the organization ID from {source}: {err:?}"),
57 }
58 }
59
60 let source = "the environment variable `OPENAI_ORG_KEY`";
61 match env::var("OPENAI_ORG_KEY")
62 .map_err(Error::from)
63 .and_then(Organization::try_from)
64 {
65 Ok(organization) => return organization.post_fetch_ok(source),
66 Err(err) => debug!("Failed to obtain the organization ID from {source}: {err:?}"),
67 }
68
69 for default_file in [
70 &PathBuf::from("openai.env"),
71 &PathBuf::from(".openai_profile"),
72 &PathBuf::from(".env"),
73 &PathBuf::from(tilde("~/openai.env")),
74 &PathBuf::from(tilde("~/.openai_profile")),
75 &PathBuf::from(tilde("~/.env")),
76 ].into_iter()
77 {
78 let source = &format!("the default file {default_file:?}");
79 match Organization::from_file(default_file) {
80 Ok(organization) => return organization.post_fetch_ok(source),
81 Err(err) => debug!("Failed to obtain the organization ID from {source}: {err:?}"),
82 }
83 }
84 Err(Error::msg("Failed to fetch the organization ID"))
85 }
86 fn value(self) -> String {
87 self.0
88 }
89 fn value_ref(&self) -> &String {
90 &self.0
91 }
92}
93
94impl TryFrom<&str> for Organization {
95 type Error = Error;
96
97 fn try_from(text: &str) -> Result<Self> {
98 Self::from_str(text)
99 }
100}
101
102impl TryFrom<String> for Organization {
103 type Error = Error;
104
105 fn try_from(text: String) -> Result<Self> {
106 Self::from_str(&text)
107 }
108}
109
110impl TryFrom<&String> for Organization {
111 type Error = Error;
112
113 fn try_from(text: &String) -> Result<Self> {
114 Self::from_str(text)
115 }
116}