1use reqwest::header::{ HeaderMap, AUTHORIZATION };
2
3pub const MPESA_SANDBOX_API_URL: &str = "https://sandbox.safaricom.co.ke";
5pub const MPESA_PRODUCTION_API_URL: &str = "https://api.safaricom.co.ke";
6
7pub trait Config: Clone {
8 fn headers(&self) -> HeaderMap;
9 fn url(&self, path: &str) -> String;
10 fn api_url(&self) -> &str;
11 fn access_token(&self) -> &str;
12}
13
14#[derive(Clone, Debug)]
15pub enum Environment {
16 Sandbox,
17 Production,
18}
19
20#[derive(Clone, Debug)]
22pub struct MpesaConfig {
23 api_url: String,
24 access_token: String,
25 environment: Environment,
26}
27
28impl Default for MpesaConfig {
30 fn default() -> Self {
31 Self {
32 api_url: MPESA_SANDBOX_API_URL.to_string(),
33 access_token: std::env::var("MPESA_ACCESS_TOKEN").unwrap_or_else(|_| "".to_string()),
34 environment: Environment::Sandbox
35 }
36 }
37}
38
39impl MpesaConfig {
40 pub fn new() -> Self {
42 Default::default()
43 }
44
45 pub fn with_access_token<S: Into<String>>(mut self, access_token: S) -> Self {
47 self.access_token = access_token.into();
48 self
49 }
50
51 pub fn with_api_url<S: Into<String>>(mut self, api_url: S) -> Self {
53 self.api_url = api_url.into();
54 self
55 }
56
57 pub fn with_environment(mut self, environment: Environment) -> Self {
58 self.environment = environment;
59 self
60 }
61}
62
63impl Config for MpesaConfig {
64 fn headers(&self) -> HeaderMap {
65 let mut headers = HeaderMap::new();
66
67 headers.insert(
68 AUTHORIZATION,
69 format!("Bearer {}", self.access_token).as_str().parse().unwrap(),
70 );
71
72 headers
73 }
74
75 fn url(&self, path: &str) -> String {
76 match &self.environment {
77 Environment::Sandbox => format!("{}{}", MPESA_SANDBOX_API_URL, path),
78 Environment::Production => format!("{}{}", MPESA_PRODUCTION_API_URL, path)
79 }
80 }
81
82 fn api_url(&self) -> &str {
83 &self.api_url
84 }
85
86 fn access_token(&self) -> &str {
87 &self.access_token
88 }
89}