3 Commits
Author SHA1 Message Date
phoenix 8dbfd88aae Refactoring (#15)
catapult PR / Check (pull_request) Successful in 59s
catapult PR / Rustfmt (pull_request) Successful in 1m25s
catapult PR / Clippy (pull_request) Successful in 1m18s
Reviewed-on: #15
2026-07-07 15:51:06 -04:00
phoenix 71ba4a9c56 Update rust (#14)
catapult PR / Rustfmt (pull_request) Successful in 49s
catapult PR / Clippy (pull_request) Successful in 1m35s
catapult PR / Check (pull_request) Successful in 2m1s
Reviewed-on: #14
2026-07-06 22:53:39 -04:00
phoenix 8fc4bb7626 Update dependencies (#13)
catapult PR / Rustfmt (pull_request) Successful in 1m4s
catapult PR / Clippy (pull_request) Successful in 1m32s
catapult PR / Check (pull_request) Successful in 2m13s
Reviewed-on: #13
2026-07-04 21:26:22 -04:00
14 changed files with 266 additions and 699 deletions
+6 -6
View File
@@ -14,10 +14,10 @@ jobs:
name: Check name: Check
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
@@ -33,10 +33,10 @@ jobs:
name: Rustfmt name: Rustfmt
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- run: rustup component add rustfmt - run: rustup component add rustfmt
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
@@ -53,10 +53,10 @@ jobs:
name: Clippy name: Clippy
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- run: rustup component add clippy - run: rustup component add clippy
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
Generated
+182 -604
View File
File diff suppressed because it is too large Load Diff
+5 -7
View File
@@ -1,18 +1,16 @@
[package] [package]
name = "catapult" name = "catapult"
version = "0.3.0" version = "0.3.3"
rust-version = "1.96" rust-version = "1.96.1"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
tokio = { version = "1.52.3", features = ["full"] } tokio = { version = "1.52.3", features = ["full"] }
futures = { version = "0.3.32" }
reqwest = { version = "0.13.4", features = ["json", "stream", "multipart"] } reqwest = { version = "0.13.4", features = ["json", "stream", "multipart"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.150" } serde_json = { version = "1.0.150" }
time = { version = "0.3.49", features = ["formatting", "macros", "parsing", "serde"] } time = { version = "0.3.53", features = ["formatting", "macros", "parsing", "serde"] }
uuid = { version = "1.23.3", features = ["v4", "serde"] } uuid = { version = "1.23.3", features = ["v4", "serde"] }
textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender_models.git", tag = "v0.4.10" } textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender_models.git", tag = "v0.5.1" }
swoosh = { git = "ssh://git@git.kundeng.us/phoenix/swoosh.git", tag = "v0.4.2.0" } swoosh = { git = "ssh://git@git.kundeng.us/phoenix/swoosh.git", tag = "v0.5.2" }
[dev-dependencies] [dev-dependencies]
+1 -1
View File
@@ -1,5 +1,5 @@
# Stage 1: Build the application # Stage 1: Build the application
FROM rust:1.96 as builder FROM rust:1.96.1 as builder
# Set the working directory inside the container # Set the working directory inside the container
WORKDIR /usr/src/app WORKDIR /usr/src/app
+23 -19
View File
@@ -12,23 +12,21 @@ pub struct App {
pub twilio_config: textsender_models::config::auxiliary::TwilioConfig, pub twilio_config: textsender_models::config::auxiliary::TwilioConfig,
} }
// TODO: Change this to non-async at some point. pub fn load_app() -> Result<App, std::io::Error> {
// Will require changes in other libraries
pub async fn load_app() -> Result<App, std::io::Error> {
use textsender_models::envy; use textsender_models::envy;
let auth_url_env = envy::environment::get_env("AUTH_URL").await; let auth_url_env = envy::environment::get_env("AUTH_URL");
let api_url_env = envy::environment::get_env("API_URL").await; let api_url_env = envy::environment::get_env("API_URL");
let service_username_env = envy::environment::get_env("SERVICE_USERNAME").await; let service_username_env = envy::environment::get_env("SERVICE_USERNAME");
let service_passphrase_env = envy::environment::get_env("SERVICE_PASSPHRASE").await; let service_passphrase_env = envy::environment::get_env("SERVICE_PASSPHRASE");
let envs = vec![ let envs = vec![
api_url_env, &api_url_env,
auth_url_env, &auth_url_env,
service_username_env, &service_username_env,
service_passphrase_env, &service_passphrase_env,
]; ];
let check_envs = |vs: &Vec<envy::EnvVar>| -> (bool, Option<String>) { let check_envs = |vs: &Vec<&envy::EnvVar>| -> (bool, Option<String>) {
for env in vs { for env in vs {
if env.value.is_empty() { if env.value.is_empty() {
return (false, Some(format!("Key {} is not provided", env.key))); return (false, Some(format!("Key {} is not provided", env.key)));
@@ -38,19 +36,25 @@ pub async fn load_app() -> Result<App, std::io::Error> {
}; };
let (envs_valid, reason) = check_envs(&envs); let (envs_valid, reason) = check_envs(&envs);
if envs_valid { if envs_valid {
match textsender_models::config::auxiliary::load_config().await { let auth_url: String = auth_url_env.value;
let api_url: String = api_url_env.value;
let service_username: String = service_username_env.value;
let service_passphrase: String = service_passphrase_env.value;
match textsender_models::config::auxiliary::load_config() {
Ok(twilio_config) => Ok(App { Ok(twilio_config) => Ok(App {
api_url: envs[0].value.clone(), api_url,
auth_url: envs[1].value.clone(), auth_url,
service_username: envs[2].value.clone(), service_username,
service_passphrase: envs[3].value.clone(), service_passphrase,
twilio_config, twilio_config,
}), }),
Err(err) => Err(err), Err(err) => Err(err),
} }
} else { } else {
Err(std::io::Error::other(reason.unwrap())) match reason {
Some(reason) => Err(std::io::Error::other(reason)),
None => Err(std::io::Error::other("No reason found")),
}
} }
} }
+10 -7
View File
@@ -6,8 +6,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
std::process::exit(-1); std::process::exit(-1);
} }
let app = match catapult::app::load_app().await { let app = match catapult::app::load_app() {
Ok(app) => app, Ok(app) => std::sync::Arc::new(app),
Err(err) => { Err(err) => {
eprintln!("Error: {err:?}"); eprintln!("Error: {err:?}");
std::process::exit(-1); std::process::exit(-1);
@@ -16,9 +16,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("App: {app:?}"); println!("App: {app:?}");
let auth = catapult::service::auth::Auth { app: app.clone() }; let auth = catapult::service::auth::Auth {
app: std::sync::Arc::clone(&app),
};
let token = match auth.get_token().await { let token = match auth.get_token().await {
Ok(token) => token, Ok(token) => std::sync::Arc::new(token),
Err(err) => { Err(err) => {
eprintln!("Error getting token"); eprintln!("Error getting token");
eprintln!("Error: {err:?}"); eprintln!("Error: {err:?}");
@@ -27,8 +29,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}; };
let mut svc = catapult::service::core::Service { let mut svc = catapult::service::core::Service {
app: app.clone(), app: std::sync::Arc::clone(&app),
token, token: std::sync::Arc::clone(&token),
}; };
loop { loop {
@@ -36,7 +38,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
match auth.get_refresh_token(&svc.token).await { match auth.get_refresh_token(&svc.token).await {
Ok(refresh) => { Ok(refresh) => {
println!("Refresh token: {refresh:?}"); println!("Refresh token: {refresh:?}");
svc.token = refresh; let refreshed = std::sync::Arc::new(refresh);
svc.token = refreshed;
} }
Err(err) => { Err(err) => {
eprintln!("Error: {err:?}"); eprintln!("Error: {err:?}");
+1 -1
View File
@@ -1,5 +1,5 @@
pub struct Auth { pub struct Auth {
pub app: crate::app::App, pub app: std::sync::Arc<crate::app::App>,
} }
impl Auth { impl Auth {
+2 -2
View File
@@ -1,6 +1,6 @@
pub struct Contact { pub struct Contact {
pub app: crate::app::App, pub app: std::sync::Arc<crate::app::App>,
pub token: textsender_models::token::LoginResult, pub token: std::sync::Arc<textsender_models::token::LoginResult>,
} }
impl Contact { impl Contact {
+26 -42
View File
@@ -1,18 +1,17 @@
pub struct Service { pub struct Service {
pub app: crate::app::App, pub app: std::sync::Arc<crate::app::App>,
pub token: textsender_models::token::Login, pub token: std::sync::Arc<textsender_models::token::Login>,
} }
impl Service { impl Service {
pub async fn do_the_work(&mut self) { pub async fn do_the_work(&mut self) {
println!("Do some work");
println!("Checking queue"); println!("Checking queue");
use textsender_models::message::scheduling::ScheduledMessage; use textsender_models::message::scheduling::ScheduledMessage;
let queue = super::queue::Queue { let queue = super::queue::Queue {
app: self.app.clone(), app: std::sync::Arc::clone(&self.app),
token: self.token.clone(), token: std::sync::Arc::clone(&self.token),
}; };
let queue_item: Option<ScheduledMessage> = match queue.get_queue().await { let queue_item: Option<ScheduledMessage> = match queue.get_queue().await {
Ok(item) => Some(item), Ok(item) => Some(item),
@@ -38,8 +37,8 @@ impl Service {
println!("Can schedule"); println!("Can schedule");
let events_req = super::event::Event { let events_req = super::event::Event {
app: self.app.clone(), app: std::sync::Arc::clone(&self.app),
token: self.token.clone(), token: std::sync::Arc::clone(&self.token),
}; };
let scheduled_message_id = queue_item.id; let scheduled_message_id = queue_item.id;
@@ -52,23 +51,31 @@ impl Service {
}; };
let contacts = super::contact::Contact { let contacts = super::contact::Contact {
app: self.app.clone(), app: std::sync::Arc::clone(&self.app),
token: self.token.clone(), token: std::sync::Arc::clone(&self.token),
}; };
let messages = super::message::Message { let messages = super::message::Message {
app: self.app.clone(), app: std::sync::Arc::clone(&self.app),
token: self.token.clone(), token: std::sync::Arc::clone(&self.token),
}; };
let sch_msg = super::scheduler::ScheduledMessage { let sch_msg = super::scheduler::ScheduledMessage {
app: self.app.clone(), app: std::sync::Arc::clone(&self.app),
token: self.token.clone(), token: std::sync::Arc::clone(&self.token),
}; };
let mer_req = super::mer::MessageEventResponse { let mer_req = super::mer::MessageEventResponse {
app: self.app.clone(), app: std::sync::Arc::clone(&self.app),
token: self.token.clone(), token: std::sync::Arc::clone(&self.token),
}; };
let events = events.unwrap_or_default(); let events = events.unwrap_or_default();
let mut sendmsg = swoosh::SendMsg::default();
sendmsg.load_config(
&self.app.twilio_config.auth_token,
&self.app.twilio_config.phone_number,
&self.app.twilio_config.service_sid,
&self.app.twilio_config.account_sid,
);
for event in &events { for event in &events {
println!("Event: {event:?}"); println!("Event: {event:?}");
let contact = &match contacts.get(&event.contact_id).await { let contact = &match contacts.get(&event.contact_id).await {
@@ -105,8 +112,10 @@ impl Service {
let twilio_config = &self.app.twilio_config; let twilio_config = &self.app.twilio_config;
println!("Config: {twilio_config:?}"); println!("Config: {twilio_config:?}");
println!("SM: {scheduled_message:?}"); println!("SM: {scheduled_message:?}");
sendmsg.load_message(&message.content);
sendmsg.load_recipient(&contact.phone_number);
match swoosh::twilio::api::send_message(message, contact, &param, twilio_config).await { match sendmsg.send_message(&param).await {
Ok(resp) => { Ok(resp) => {
println!("Message scheduled"); println!("Message scheduled");
// MER response // MER response
@@ -138,39 +147,14 @@ impl Service {
} }
} }
} }
/*
todo!(
r#"
Need to finish this
[X] - 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 - Done
2. If there is an item, get the data - Done
3. Evaluate if it is schedulable - Done
4. Get the events and iterate each one - Done
5. Starting with the message - Done
6. Get the contact - Done
7. Send the message
8. Record the message event response - Added, not used
9. Add to scheduler
"#
);
*/
} }
fn is_schedulable( fn is_schedulable(
&self, &self,
queue_item: &textsender_models::message::scheduling::ScheduledMessage, queue_item: &textsender_models::message::scheduling::ScheduledMessage,
) -> bool { ) -> bool {
let now = time::OffsetDateTime::now_utc();
match queue_item.scheduled { match queue_item.scheduled {
Some(date) => date > now, Some(date) => date > time::OffsetDateTime::now_utc(),
None => false, None => false,
} }
} }
+2 -2
View File
@@ -1,6 +1,6 @@
pub struct Event { pub struct Event {
pub app: crate::app::App, pub app: std::sync::Arc<crate::app::App>,
pub token: textsender_models::token::LoginResult, pub token: std::sync::Arc<textsender_models::token::LoginResult>,
} }
impl Event { impl Event {
+2 -2
View File
@@ -1,6 +1,6 @@
pub struct MessageEventResponse { pub struct MessageEventResponse {
pub app: crate::app::App, pub app: std::sync::Arc<crate::app::App>,
pub token: textsender_models::token::LoginResult, pub token: std::sync::Arc<textsender_models::token::LoginResult>,
} }
impl MessageEventResponse { impl MessageEventResponse {
+2 -2
View File
@@ -1,6 +1,6 @@
pub struct Message { pub struct Message {
pub app: crate::app::App, pub app: std::sync::Arc<crate::app::App>,
pub token: textsender_models::token::LoginResult, pub token: std::sync::Arc<textsender_models::token::LoginResult>,
} }
impl Message { impl Message {
+2 -2
View File
@@ -1,6 +1,6 @@
pub struct Queue { pub struct Queue {
pub app: crate::app::App, pub app: std::sync::Arc<crate::app::App>,
pub token: textsender_models::token::LoginResult, pub token: std::sync::Arc<textsender_models::token::LoginResult>,
} }
impl Queue { impl Queue {
+2 -2
View File
@@ -1,6 +1,6 @@
pub struct ScheduledMessage { pub struct ScheduledMessage {
pub app: crate::app::App, pub app: std::sync::Arc<crate::app::App>,
pub token: textsender_models::token::LoginResult, pub token: std::sync::Arc<textsender_models::token::LoginResult>,
} }
impl ScheduledMessage { impl ScheduledMessage {