From 0f9753874b680a74f8c7e6369d99f56e16985b4f Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Jun 2026 17:11:08 -0400 Subject: [PATCH 1/9] Saving changes --- src/app.rs | 1 + src/main.rs | 20 ++++- src/service.rs | 214 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 213 insertions(+), 22 deletions(-) diff --git a/src/app.rs b/src/app.rs index d637aa0..72203a9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,6 +3,7 @@ pub const SECONDS_TO_SLEEP: u64 = 5; pub const APP_NAME: &str = "catapult"; +#[derive(Clone)] pub struct App { pub api_url: String, pub auth_url: String, diff --git a/src/main.rs b/src/main.rs index 80bfe63..bda6829 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,8 +14,26 @@ async fn main() -> Result<(), Box> { } }; + let auth = catapult::service::auth::Auth { + app: app.clone() + }; + let token = match auth.get_token().await { + Ok(token) => token, + Err(err) => { + eprintln!("Error getting token"); + eprintln!("Error: {err:?}"); + std::process::exit(-1); + } + }; + + let mut svc = catapult::service::Service { + app: app.clone(), + token + }; + loop { - catapult::service::do_the_work(&app).await; + // catapult::service::do_the_work(&app).await; + svc.do_the_work().await; tokio::time::sleep(tokio::time::Duration::from_secs( catapult::app::SECONDS_TO_SLEEP, )) diff --git a/src/service.rs b/src/service.rs index 93bb630..f2bbbbc 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,22 +1,194 @@ -pub async fn do_the_work(_app: &crate::app::App) { - println!("Do some work"); - todo!( - r#" - Need to finish this - - This function should fetch a token, check if the token is valid, and obtain a refresh token if - it has expired. - - Then do the real work. - - 1. Check the queue - 2. If there is an item, get the data, - 3. Evaluate if it is schedulable - 4. Get the events and iterate each one - 5. starting with the message - 6. Get the contact - 7. Send the message - 8. Record the message event response - "# - ); +pub struct Service { + pub app: crate::app::App, + pub token: textsender_models::token::Login } + +impl Service { + pub async fn do_the_work(&mut self) { + println!("Do some work"); + todo!( + r#" + Need to finish this + + This function should fetch a token, check if the token is valid, and obtain a refresh token if + it has expired. + + Then do the real work. + + 1. Check the queue + 2. If there is an item, get the data, + 3. Evaluate if it is schedulable + 4. Get the events and iterate each one + 5. starting with the message + 6. Get the contact + 7. Send the message + 8. Record the message event response + "# + ); + } +} + +pub mod auth { + pub struct Auth { + pub app: crate::app::App + } + + /* + #[derive(serde::Deserialize, serde::Serialize)] + struct ServiceRequest { + pub username: String, + pub passphrase: String + } + */ + + impl Auth { + pub async fn get_token(&self) -> Result { + /* + let svcRequest = ServiceRequest { + username: self.app.service_username, + passphrase: self.app.service_passphrase, + }; + */ + let client = reqwest::Client::new(); + let endpoint = String::from("api/v1/service/login"); + let api_url = format!("{}/{endpoint}", self.app.auth_url); + + let payload = serde_json::json!({ + "username": self.app.auth_url, + "passphrase": self.app.api_url + }); + + match client.post(api_url).json(&payload).send().await { + Ok(response) => match response.status() { + reqwest::StatusCode::OK => { + println!("Response: {response:?}"); + match response.json().await { + Ok(val) => { + Ok(val) + } + Err(err) => { + Err(std::io::Error::other(err)) + } + } + } + _ => { + Err(std::io::Error::other("Error getting token")) + } + } + Err(err) => { + Err(std::io::Error::other(err.to_string())) + } + } + } + } +} + + +/* + * + let client = reqwest::Client::new(); + let endpoint = String::from("api/v2/service/login"); + let api_url = format!("{}/{endpoint}", app.auth_uri); + + let payload = serde_json::json!({ + "passphrase": icarus_envy::environment::get_service_passphrase().await.value, + }); + + match client.post(api_url).json(&payload).send().await { + Ok(response) => match response + .json::() + .await + { + Ok(resp) => { + if resp.data.is_empty() { + Err(std::io::Error::other(String::from("No token returned"))) + } else { + Ok(resp.data[0].clone()) + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + }, + Err(err) => Err(std::io::Error::other(err.to_string())), + } + * + */ + +/* + * +type tokenResponse struct { + Message string `json:"message"` + Data []*token.Login `json:"data"` +} + +func (a *Auth) GetToken() (*token.Login, error) { + serv := service{ + Username: a.Application.ServiceUsername, + Passphrase: a.Application.ServicePassphrase, + } + + jsonData, err := json.Marshal(serv) + if err != nil { + return nil, err + } + resp, err := http.Post( + fmt.Sprintf("%s/api/v1/service/login", a.Application.AuthUrl), + "application/json", + bytes.NewBuffer(jsonData), + ) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var r tokenResponse + err = json.NewDecoder(resp.Body).Decode(&r) + if err != nil { + return nil, err + } + + return r.Data[0], nil +} + +type refreshTokenRequest struct { + AccessToken string `json:"access_token"` +} + +func (a *Auth) GetRefreshToken(tok *token.Login) (*token.Login, error) { + req := refreshTokenRequest{AccessToken: tok.AccessToken} + + jsonData, err := json.Marshal(req) + if err != nil { + return nil, err + } + + resp, err := http.Post(fmt.Sprintf("%s/api/v1/token/refresh", a.Application.AuthUrl), "application/json", bytes.NewBuffer(jsonData)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var r tokenResponse + err = json.NewDecoder(resp.Body).Decode(&r) + if err != nil { + return nil, err + } else { + if len(r.Data) == 0 { + return nil, nil + } else { + return r.Data[0], nil + } + } +} + +func (s *Auth) TokenExpired(tok *token.Login) bool { + now := time.Now() + expiredTime := time.Unix(tok.ExpiresIn, 0) + + if now.After(expiredTime) { + return true + } else { + return false + } +} + * + */ -- 2.47.3 From aaa20c87527e9a52046a384aadb79db16e1805f2 Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Jun 2026 17:43:29 -0400 Subject: [PATCH 2/9] Able to get token --- src/app.rs | 12 ++++++------ src/main.rs | 4 ++++ src/service.rs | 43 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/app.rs b/src/app.rs index 72203a9..866cd16 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,7 +3,7 @@ pub const SECONDS_TO_SLEEP: u64 = 5; pub const APP_NAME: &str = "catapult"; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct App { pub api_url: String, pub auth_url: String, @@ -22,8 +22,8 @@ pub async fn load_app() -> Result { let service_passphrase_env = envy::environment::get_env("SERVICE_PASSPHRASE").await; let envs = vec![ - auth_url_env, api_url_env, + auth_url_env, service_username_env, service_passphrase_env, ]; @@ -42,10 +42,10 @@ pub async fn load_app() -> Result { if envs_valid { match textsender_models::config::auxiliary::load_config().await { Ok(twilio_config) => Ok(App { - api_url: String::new(), - auth_url: String::new(), - service_username: String::new(), - service_passphrase: String::new(), + api_url: envs[0].value.clone(), + auth_url: envs[1].value.clone(), + service_username: envs[2].value.clone(), + service_passphrase: envs[3].value.clone(), twilio_config: twilio_config, }), Err(err) => Err(err), diff --git a/src/main.rs b/src/main.rs index bda6829..b4c1378 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,8 @@ async fn main() -> Result<(), Box> { } }; + println!("App: {app:?}"); + let auth = catapult::service::auth::Auth { app: app.clone() }; @@ -26,6 +28,8 @@ async fn main() -> Result<(), Box> { } }; + println!("Access token: {}", token.access_token); + let mut svc = catapult::service::Service { app: app.clone(), token diff --git a/src/service.rs b/src/service.rs index f2bbbbc..0c47f7b 100644 --- a/src/service.rs +++ b/src/service.rs @@ -53,18 +53,53 @@ pub mod auth { let endpoint = String::from("api/v1/service/login"); let api_url = format!("{}/{endpoint}", self.app.auth_url); + println!("Url: {api_url:?}"); + let payload = serde_json::json!({ - "username": self.app.auth_url, - "passphrase": self.app.api_url + "username": &self.app.service_username, + "passphrase": &self.app.service_passphrase, }); + println!("Payload: {payload:?}"); + match client.post(api_url).json(&payload).send().await { Ok(response) => match response.status() { reqwest::StatusCode::OK => { println!("Response: {response:?}"); - match response.json().await { + match response.text().await { Ok(val) => { - Ok(val) + match serde_json::from_str::(&val) { + Ok(j) => { + println!("Good"); + let message = &j["message"]; + let data = &j["data"]; + + println!("Message: {message:?}"); + println!("Data: {data:?}"); + match j.get("data") { + Some(serde_json::Value::Array(lrs)) => { + if lrs.is_empty() { + Err(std::io::Error::other("Error response is empty")) + } else { + let lr = lrs[0].clone(); + let ll: textsender_models::token::LoginResult = match serde_json::from_value(lr) { Ok(lr) => lr, + Err(err) => { + return Err(std::io::Error::other(err.to_string())); + } + }; + Ok(ll) + // Ok(textsender_models::token::LoginResult::default()) + } + } + _ => { + Err(std::io::Error::other("Error parsing response")) + } + } + } + Err(err) => { + Err(std::io::Error::other(err.to_string())) + } + } } Err(err) => { Err(std::io::Error::other(err)) -- 2.47.3 From dd9d4525768b1c0457fd985e44dce06d41813a1b Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Jun 2026 17:43:55 -0400 Subject: [PATCH 3/9] cargo fmt --- src/app.rs | 4 +- src/main.rs | 6 +- src/service.rs | 231 ++++++++++++++++++++++++------------------------- 3 files changed, 117 insertions(+), 124 deletions(-) diff --git a/src/app.rs b/src/app.rs index 866cd16..310eab0 100644 --- a/src/app.rs +++ b/src/app.rs @@ -43,9 +43,9 @@ pub async fn load_app() -> Result { match textsender_models::config::auxiliary::load_config().await { Ok(twilio_config) => Ok(App { api_url: envs[0].value.clone(), - auth_url: envs[1].value.clone(), + auth_url: envs[1].value.clone(), service_username: envs[2].value.clone(), - service_passphrase: envs[3].value.clone(), + service_passphrase: envs[3].value.clone(), twilio_config: twilio_config, }), Err(err) => Err(err), diff --git a/src/main.rs b/src/main.rs index b4c1378..a1bd966 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,9 +16,7 @@ async fn main() -> Result<(), Box> { println!("App: {app:?}"); - let auth = catapult::service::auth::Auth { - app: app.clone() - }; + let auth = catapult::service::auth::Auth { app: app.clone() }; let token = match auth.get_token().await { Ok(token) => token, Err(err) => { @@ -32,7 +30,7 @@ async fn main() -> Result<(), Box> { let mut svc = catapult::service::Service { app: app.clone(), - token + token, }; loop { diff --git a/src/service.rs b/src/service.rs index 0c47f7b..41d02f8 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,6 +1,6 @@ pub struct Service { pub app: crate::app::App, - pub token: textsender_models::token::Login + pub token: textsender_models::token::Login, } impl Service { @@ -30,7 +30,7 @@ impl Service { pub mod auth { pub struct Auth { - pub app: crate::app::App + pub app: crate::app::App, } /* @@ -63,167 +63,162 @@ pub mod auth { println!("Payload: {payload:?}"); match client.post(api_url).json(&payload).send().await { - Ok(response) => match response.status() { - reqwest::StatusCode::OK => { - println!("Response: {response:?}"); - match response.text().await { - Ok(val) => { - match serde_json::from_str::(&val) { - Ok(j) => { - println!("Good"); - let message = &j["message"]; - let data = &j["data"]; + Ok(response) => { + match response.status() { + reqwest::StatusCode::OK => { + println!("Response: {response:?}"); + match response.text().await { + Ok(val) => { + match serde_json::from_str::(&val) { + Ok(j) => { + println!("Good"); + let message = &j["message"]; + let data = &j["data"]; - println!("Message: {message:?}"); - println!("Data: {data:?}"); - match j.get("data") { - Some(serde_json::Value::Array(lrs)) => { - if lrs.is_empty() { - Err(std::io::Error::other("Error response is empty")) - } else { - let lr = lrs[0].clone(); - let ll: textsender_models::token::LoginResult = match serde_json::from_value(lr) { Ok(lr) => lr, + println!("Message: {message:?}"); + println!("Data: {data:?}"); + match j.get("data") { + Some(serde_json::Value::Array(lrs)) => { + if lrs.is_empty() { + Err(std::io::Error::other( + "Error response is empty", + )) + } else { + let lr = lrs[0].clone(); + let ll: textsender_models::token::LoginResult = match serde_json::from_value(lr) { Ok(lr) => lr, Err(err) => { return Err(std::io::Error::other(err.to_string())); } }; - Ok(ll) - // Ok(textsender_models::token::LoginResult::default()) + Ok(ll) + // Ok(textsender_models::token::LoginResult::default()) + } } - } - _ => { - Err(std::io::Error::other("Error parsing response")) + _ => Err(std::io::Error::other( + "Error parsing response", + )), } } - } - Err(err) => { - Err(std::io::Error::other(err.to_string())) + Err(err) => Err(std::io::Error::other(err.to_string())), } } - } - Err(err) => { - Err(std::io::Error::other(err)) + Err(err) => Err(std::io::Error::other(err)), } } - } - _ => { - Err(std::io::Error::other("Error getting token")) + _ => Err(std::io::Error::other("Error getting token")), } } - Err(err) => { - Err(std::io::Error::other(err.to_string())) - } + Err(err) => Err(std::io::Error::other(err.to_string())), } } } } - /* - * - let client = reqwest::Client::new(); - let endpoint = String::from("api/v2/service/login"); - let api_url = format!("{}/{endpoint}", app.auth_uri); +* + let client = reqwest::Client::new(); + let endpoint = String::from("api/v2/service/login"); + let api_url = format!("{}/{endpoint}", app.auth_uri); - let payload = serde_json::json!({ - "passphrase": icarus_envy::environment::get_service_passphrase().await.value, - }); + let payload = serde_json::json!({ + "passphrase": icarus_envy::environment::get_service_passphrase().await.value, + }); - match client.post(api_url).json(&payload).send().await { - Ok(response) => match response - .json::() - .await - { - Ok(resp) => { - if resp.data.is_empty() { - Err(std::io::Error::other(String::from("No token returned"))) - } else { - Ok(resp.data[0].clone()) - } - } - Err(err) => Err(std::io::Error::other(err.to_string())), - }, - Err(err) => Err(std::io::Error::other(err.to_string())), - } - * - */ + match client.post(api_url).json(&payload).send().await { + Ok(response) => match response + .json::() + .await + { + Ok(resp) => { + if resp.data.is_empty() { + Err(std::io::Error::other(String::from("No token returned"))) + } else { + Ok(resp.data[0].clone()) + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + }, + Err(err) => Err(std::io::Error::other(err.to_string())), + } +* +*/ /* * type tokenResponse struct { - Message string `json:"message"` - Data []*token.Login `json:"data"` + Message string `json:"message"` + Data []*token.Login `json:"data"` } func (a *Auth) GetToken() (*token.Login, error) { - serv := service{ - Username: a.Application.ServiceUsername, - Passphrase: a.Application.ServicePassphrase, - } + serv := service{ + Username: a.Application.ServiceUsername, + Passphrase: a.Application.ServicePassphrase, + } - jsonData, err := json.Marshal(serv) - if err != nil { - return nil, err - } - resp, err := http.Post( - fmt.Sprintf("%s/api/v1/service/login", a.Application.AuthUrl), - "application/json", - bytes.NewBuffer(jsonData), - ) - if err != nil { - return nil, err - } - defer resp.Body.Close() + jsonData, err := json.Marshal(serv) + if err != nil { + return nil, err + } + resp, err := http.Post( + fmt.Sprintf("%s/api/v1/service/login", a.Application.AuthUrl), + "application/json", + bytes.NewBuffer(jsonData), + ) + if err != nil { + return nil, err + } + defer resp.Body.Close() - var r tokenResponse - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, err - } + var r tokenResponse + err = json.NewDecoder(resp.Body).Decode(&r) + if err != nil { + return nil, err + } - return r.Data[0], nil + return r.Data[0], nil } type refreshTokenRequest struct { - AccessToken string `json:"access_token"` + AccessToken string `json:"access_token"` } func (a *Auth) GetRefreshToken(tok *token.Login) (*token.Login, error) { - req := refreshTokenRequest{AccessToken: tok.AccessToken} + req := refreshTokenRequest{AccessToken: tok.AccessToken} - jsonData, err := json.Marshal(req) - if err != nil { - return nil, err - } + jsonData, err := json.Marshal(req) + if err != nil { + return nil, err + } - resp, err := http.Post(fmt.Sprintf("%s/api/v1/token/refresh", a.Application.AuthUrl), "application/json", bytes.NewBuffer(jsonData)) - if err != nil { - return nil, err - } - defer resp.Body.Close() + resp, err := http.Post(fmt.Sprintf("%s/api/v1/token/refresh", a.Application.AuthUrl), "application/json", bytes.NewBuffer(jsonData)) + if err != nil { + return nil, err + } + defer resp.Body.Close() - var r tokenResponse - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, err - } else { - if len(r.Data) == 0 { - return nil, nil - } else { - return r.Data[0], nil - } - } + var r tokenResponse + err = json.NewDecoder(resp.Body).Decode(&r) + if err != nil { + return nil, err + } else { + if len(r.Data) == 0 { + return nil, nil + } else { + return r.Data[0], nil + } + } } func (s *Auth) TokenExpired(tok *token.Login) bool { - now := time.Now() - expiredTime := time.Unix(tok.ExpiresIn, 0) + now := time.Now() + expiredTime := time.Unix(tok.ExpiresIn, 0) - if now.After(expiredTime) { - return true - } else { - return false - } + if now.After(expiredTime) { + return true + } else { + return false + } } * */ -- 2.47.3 From adcc9a382f4d7ba36e407ba83e47f9175e0f4b5f Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Jun 2026 21:42:41 -0400 Subject: [PATCH 4/9] Renaming file --- src/{service.rs => service/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{service.rs => service/mod.rs} (100%) diff --git a/src/service.rs b/src/service/mod.rs similarity index 100% rename from src/service.rs rename to src/service/mod.rs -- 2.47.3 From 515c0c564b4d43291f2648f809ea3f3ca2c520f8 Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Jun 2026 22:32:52 -0400 Subject: [PATCH 5/9] Saving changes --- src/main.rs | 2 +- src/service/core.rs | 30 +++++++ src/service/mod.rs | 207 +++++++++++++++----------------------------- 3 files changed, 102 insertions(+), 137 deletions(-) create mode 100644 src/service/core.rs diff --git a/src/main.rs b/src/main.rs index a1bd966..49ab8a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,7 +28,7 @@ async fn main() -> Result<(), Box> { println!("Access token: {}", token.access_token); - let mut svc = catapult::service::Service { + let mut svc = catapult::service::core::Service { app: app.clone(), token, }; diff --git a/src/service/core.rs b/src/service/core.rs new file mode 100644 index 0000000..b17f2e7 --- /dev/null +++ b/src/service/core.rs @@ -0,0 +1,30 @@ +pub struct Service { + pub app: crate::app::App, + pub token: textsender_models::token::Login, +} + +impl Service { + pub async fn do_the_work(&mut self) { + println!("Do some work"); + todo!( + r#" + Need to finish this + + This function should fetch a token, check if the token is valid, and obtain a refresh token if + it has expired. + + Then do the real work. + + 1. Check the queue + 2. If there is an item, get the data, + 3. Evaluate if it is schedulable + 4. Get the events and iterate each one + 5. starting with the message + 6. Get the contact + 7. Send the message + 8. Record the message event response + "# + ); + } +} + diff --git a/src/service/mod.rs b/src/service/mod.rs index 41d02f8..bc71d8a 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -1,54 +1,13 @@ -pub struct Service { - pub app: crate::app::App, - pub token: textsender_models::token::Login, -} +pub mod core; -impl Service { - pub async fn do_the_work(&mut self) { - println!("Do some work"); - todo!( - r#" - Need to finish this - - This function should fetch a token, check if the token is valid, and obtain a refresh token if - it has expired. - - Then do the real work. - - 1. Check the queue - 2. If there is an item, get the data, - 3. Evaluate if it is schedulable - 4. Get the events and iterate each one - 5. starting with the message - 6. Get the contact - 7. Send the message - 8. Record the message event response - "# - ); - } -} pub mod auth { pub struct Auth { pub app: crate::app::App, } - /* - #[derive(serde::Deserialize, serde::Serialize)] - struct ServiceRequest { - pub username: String, - pub passphrase: String - } - */ - impl Auth { pub async fn get_token(&self) -> Result { - /* - let svcRequest = ServiceRequest { - username: self.app.service_username, - passphrase: self.app.service_passphrase, - }; - */ let client = reqwest::Client::new(); let endpoint = String::from("api/v1/service/login"); let api_url = format!("{}/{endpoint}", self.app.auth_url); @@ -69,37 +28,42 @@ pub mod auth { println!("Response: {response:?}"); match response.text().await { Ok(val) => { - match serde_json::from_str::(&val) { - Ok(j) => { - println!("Good"); - let message = &j["message"]; - let data = &j["data"]; + match parse_token_response(&val).await { + Ok(login_result) => Ok(login_result), + Err(err) => Err(err) + } + } + Err(err) => Err(std::io::Error::other(err)), + } + } + _ => Err(std::io::Error::other("Error getting token")), + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + } + } - println!("Message: {message:?}"); - println!("Data: {data:?}"); - match j.get("data") { - Some(serde_json::Value::Array(lrs)) => { - if lrs.is_empty() { - Err(std::io::Error::other( - "Error response is empty", - )) - } else { - let lr = lrs[0].clone(); - let ll: textsender_models::token::LoginResult = match serde_json::from_value(lr) { Ok(lr) => lr, - Err(err) => { - return Err(std::io::Error::other(err.to_string())); - } - }; - Ok(ll) - // Ok(textsender_models::token::LoginResult::default()) - } - } - _ => Err(std::io::Error::other( - "Error parsing response", - )), - } - } - Err(err) => Err(std::io::Error::other(err.to_string())), + pub async fn get_refresh_token(&self, login_result: &textsender_models::token::Login) -> Result { + let client = reqwest::Client::new(); + let endpoint = String::from("api/v1/token/refresh"); + let api_url = format!("{}/{endpoint}", self.app.auth_url); + + println!("Url: {api_url:?}"); + + let payload = serde_json::json!({ + "access_token": login_result.access_token + }); + + match client.post(api_url).json(&payload).send().await { + Ok(response) => { + match response.status() { + reqwest::StatusCode::OK => { + println!("Response: {response:?}"); + match response.text().await { + Ok(val) => { + match parse_token_response(&val).await { + Ok(login_result) => Ok(login_result), + Err(err) => Err(err) } } Err(err) => Err(std::io::Error::other(err)), @@ -112,73 +76,44 @@ pub mod auth { } } } + + async fn parse_token_response(response: &String) -> Result { + match serde_json::from_str::(response) { + Ok(j) => { + println!("Good"); + let message = &j["message"]; + let data = &j["data"]; + + println!("Message: {message:?}"); + println!("Data: {data:?}"); + match j.get("data") { + Some(serde_json::Value::Array(lrs)) => { + if lrs.is_empty() { + Err(std::io::Error::other( + "Error response is empty", + )) + } else { + let lr = lrs[0].clone(); + let ll: textsender_models::token::LoginResult = match serde_json::from_value(lr) { Ok(lr) => lr, + Err(err) => { + return Err(std::io::Error::other(err.to_string())); + } + }; + Ok(ll) + } + } + _ => Err(std::io::Error::other( + "Error parsing response", + )), + } + } + Err(err) => Err(std::io::Error::other(err.to_string())), + } + } } + /* -* - let client = reqwest::Client::new(); - let endpoint = String::from("api/v2/service/login"); - let api_url = format!("{}/{endpoint}", app.auth_uri); - - let payload = serde_json::json!({ - "passphrase": icarus_envy::environment::get_service_passphrase().await.value, - }); - - match client.post(api_url).json(&payload).send().await { - Ok(response) => match response - .json::() - .await - { - Ok(resp) => { - if resp.data.is_empty() { - Err(std::io::Error::other(String::from("No token returned"))) - } else { - Ok(resp.data[0].clone()) - } - } - Err(err) => Err(std::io::Error::other(err.to_string())), - }, - Err(err) => Err(std::io::Error::other(err.to_string())), - } -* -*/ - -/* - * -type tokenResponse struct { - Message string `json:"message"` - Data []*token.Login `json:"data"` -} - -func (a *Auth) GetToken() (*token.Login, error) { - serv := service{ - Username: a.Application.ServiceUsername, - Passphrase: a.Application.ServicePassphrase, - } - - jsonData, err := json.Marshal(serv) - if err != nil { - return nil, err - } - resp, err := http.Post( - fmt.Sprintf("%s/api/v1/service/login", a.Application.AuthUrl), - "application/json", - bytes.NewBuffer(jsonData), - ) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var r tokenResponse - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, err - } - - return r.Data[0], nil -} - type refreshTokenRequest struct { AccessToken string `json:"access_token"` } -- 2.47.3 From 5f3e4dc64b305fc244f48a54f9a41dcf07c1c100 Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Jun 2026 22:40:55 -0400 Subject: [PATCH 6/9] Adding refresh token --- src/main.rs | 11 ++++++++++- src/service/mod.rs | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 49ab8a6..ebd42ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,11 +30,20 @@ async fn main() -> Result<(), Box> { let mut svc = catapult::service::core::Service { app: app.clone(), - token, + // Use a pointer + token: token.clone(), }; loop { // catapult::service::do_the_work(&app).await; + let refresh_token = match auth.get_refresh_token(&token).await { + Ok(refresh) => refresh, + Err(err) => { + eprintln!("Error: {err:?}"); + std::process::exit(-1); + } + }; + println!("Refresh token: {refresh_token:?}"); svc.do_the_work().await; tokio::time::sleep(tokio::time::Duration::from_secs( catapult::app::SECONDS_TO_SLEEP, diff --git a/src/service/mod.rs b/src/service/mod.rs index bc71d8a..a3b4230 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -110,6 +110,11 @@ pub mod auth { Err(err) => Err(std::io::Error::other(err.to_string())), } } + + pub async fn has_token_expired(token: &textsender_models::token::LoginResult) -> bool { + todo!("Need to finish this"); + false + } } -- 2.47.3 From f2f4176a51a11874f35df1e034debec1e7ad07d0 Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Jun 2026 23:00:51 -0400 Subject: [PATCH 7/9] Adding time crate --- Cargo.lock | 1 + Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1964bbc..e1898ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,6 +136,7 @@ dependencies = [ "serde_json", "swoosh", "textsender_models", + "time", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index 64eae2d..75f702b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ futures = { version = "0.3.32" } reqwest = { version = "0.13.4", features = ["json", "stream", "multipart"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = { version = "1.0.150" } +time = { version = "0.3.49", features = ["formatting", "macros", "parsing", "serde"] } textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender_models.git", tag = "v0.4.3-29-720f3d8f75-111" } swoosh = { git = "ssh://git@git.kundeng.us/phoenix/swoosh.git", tag = "v0.4.1-10-6bdec12084-871" } -- 2.47.3 From 5ae1715fb4b1a9da2d3a68d1ba11a4963c20e14d Mon Sep 17 00:00:00 2001 From: phoenix Date: Mon, 22 Jun 2026 23:01:03 -0400 Subject: [PATCH 8/9] Adding token related code --- src/main.rs | 26 +++++++++++++-------- src/service/mod.rs | 58 ++++++++-------------------------------------- 2 files changed, 26 insertions(+), 58 deletions(-) diff --git a/src/main.rs b/src/main.rs index ebd42ac..a1a87c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,21 +30,27 @@ async fn main() -> Result<(), Box> { let mut svc = catapult::service::core::Service { app: app.clone(), - // Use a pointer - token: token.clone(), + token: token, }; loop { - // catapult::service::do_the_work(&app).await; - let refresh_token = match auth.get_refresh_token(&token).await { - Ok(refresh) => refresh, - Err(err) => { - eprintln!("Error: {err:?}"); - std::process::exit(-1); + // TODO: Need to update textsender_models. The token module needs updating. + // The LoginResult needs expires_in populated + if catapult::service::auth::has_token_expired(&svc.token).await { + match auth.get_refresh_token(&svc.token).await { + Ok(refresh) => { + println!("Refresh token: {refresh:?}"); + svc.token = refresh; + } + Err(err) => { + eprintln!("Error: {err:?}"); + std::process::exit(-1); + } } - }; - println!("Refresh token: {refresh_token:?}"); + } + svc.do_the_work().await; + tokio::time::sleep(tokio::time::Duration::from_secs( catapult::app::SECONDS_TO_SLEEP, )) diff --git a/src/service/mod.rs b/src/service/mod.rs index a3b4230..20d0d85 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -112,53 +112,15 @@ pub mod auth { } pub async fn has_token_expired(token: &textsender_models::token::LoginResult) -> bool { - todo!("Need to finish this"); - false + let now = time::OffsetDateTime::now_utc(); + let expire = match time::OffsetDateTime::from_unix_timestamp(token.expires_in) { + Ok(res) => res, + Err(err) => { + eprintln!("Error: {err:?}"); + return false; + } + }; + + now > expire } } - - -/* -type refreshTokenRequest struct { - AccessToken string `json:"access_token"` -} - -func (a *Auth) GetRefreshToken(tok *token.Login) (*token.Login, error) { - req := refreshTokenRequest{AccessToken: tok.AccessToken} - - jsonData, err := json.Marshal(req) - if err != nil { - return nil, err - } - - resp, err := http.Post(fmt.Sprintf("%s/api/v1/token/refresh", a.Application.AuthUrl), "application/json", bytes.NewBuffer(jsonData)) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var r tokenResponse - err = json.NewDecoder(resp.Body).Decode(&r) - if err != nil { - return nil, err - } else { - if len(r.Data) == 0 { - return nil, nil - } else { - return r.Data[0], nil - } - } -} - -func (s *Auth) TokenExpired(tok *token.Login) bool { - now := time.Now() - expiredTime := time.Unix(tok.ExpiresIn, 0) - - if now.After(expiredTime) { - return true - } else { - return false - } -} - * - */ -- 2.47.3 From 75116d649e71e823183bb8d6cc6b4fd9e4d4b068 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 24 Jun 2026 14:40:03 -0400 Subject: [PATCH 9/9] Code formatting --- src/service/core.rs | 1 - src/service/mod.rs | 82 +++++++++++++++++++++------------------------ 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/src/service/core.rs b/src/service/core.rs index b17f2e7..839e38f 100644 --- a/src/service/core.rs +++ b/src/service/core.rs @@ -27,4 +27,3 @@ impl Service { ); } } - diff --git a/src/service/mod.rs b/src/service/mod.rs index 20d0d85..d3bd740 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -1,6 +1,5 @@ pub mod core; - pub mod auth { pub struct Auth { pub app: crate::app::App, @@ -22,28 +21,27 @@ pub mod auth { println!("Payload: {payload:?}"); match client.post(api_url).json(&payload).send().await { - Ok(response) => { - match response.status() { - reqwest::StatusCode::OK => { - println!("Response: {response:?}"); - match response.text().await { - Ok(val) => { - match parse_token_response(&val).await { - Ok(login_result) => Ok(login_result), - Err(err) => Err(err) - } - } - Err(err) => Err(std::io::Error::other(err)), - } + Ok(response) => match response.status() { + reqwest::StatusCode::OK => { + println!("Response: {response:?}"); + match response.text().await { + Ok(val) => match parse_token_response(&val).await { + Ok(login_result) => Ok(login_result), + Err(err) => Err(err), + }, + Err(err) => Err(std::io::Error::other(err)), } - _ => Err(std::io::Error::other("Error getting token")), } - } + _ => Err(std::io::Error::other("Error getting token")), + }, Err(err) => Err(std::io::Error::other(err.to_string())), } } - pub async fn get_refresh_token(&self, login_result: &textsender_models::token::Login) -> Result { + pub async fn get_refresh_token( + &self, + login_result: &textsender_models::token::Login, + ) -> Result { let client = reqwest::Client::new(); let endpoint = String::from("api/v1/token/refresh"); let api_url = format!("{}/{endpoint}", self.app.auth_url); @@ -55,29 +53,27 @@ pub mod auth { }); match client.post(api_url).json(&payload).send().await { - Ok(response) => { - match response.status() { - reqwest::StatusCode::OK => { - println!("Response: {response:?}"); - match response.text().await { - Ok(val) => { - match parse_token_response(&val).await { - Ok(login_result) => Ok(login_result), - Err(err) => Err(err) - } - } - Err(err) => Err(std::io::Error::other(err)), - } + Ok(response) => match response.status() { + reqwest::StatusCode::OK => { + println!("Response: {response:?}"); + match response.text().await { + Ok(val) => match parse_token_response(&val).await { + Ok(login_result) => Ok(login_result), + Err(err) => Err(err), + }, + Err(err) => Err(std::io::Error::other(err)), } - _ => Err(std::io::Error::other("Error getting token")), } - } + _ => Err(std::io::Error::other("Error getting token")), + }, Err(err) => Err(std::io::Error::other(err.to_string())), } } } - async fn parse_token_response(response: &String) -> Result { + async fn parse_token_response( + response: &String, + ) -> Result { match serde_json::from_str::(response) { Ok(j) => { println!("Good"); @@ -89,22 +85,20 @@ pub mod auth { match j.get("data") { Some(serde_json::Value::Array(lrs)) => { if lrs.is_empty() { - Err(std::io::Error::other( - "Error response is empty", - )) + Err(std::io::Error::other("Error response is empty")) } else { let lr = lrs[0].clone(); - let ll: textsender_models::token::LoginResult = match serde_json::from_value(lr) { Ok(lr) => lr, - Err(err) => { - return Err(std::io::Error::other(err.to_string())); - } - }; + let ll: textsender_models::token::LoginResult = + match serde_json::from_value(lr) { + Ok(lr) => lr, + Err(err) => { + return Err(std::io::Error::other(err.to_string())); + } + }; Ok(ll) } } - _ => Err(std::io::Error::other( - "Error parsing response", - )), + _ => Err(std::io::Error::other("Error parsing response")), } } Err(err) => Err(std::io::Error::other(err.to_string())), -- 2.47.3