+56
@@ -0,0 +1,56 @@
|
||||
/// Seconds to sleep after finising a task
|
||||
pub const SECONDS_TO_SLEEP: u64 = 5;
|
||||
|
||||
pub const APP_NAME: &str = "catapult";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct App {
|
||||
pub api_url: String,
|
||||
pub auth_url: String,
|
||||
pub service_username: String,
|
||||
pub service_passphrase: String,
|
||||
pub twilio_config: textsender_models::config::auxiliary::TwilioConfig,
|
||||
}
|
||||
|
||||
// TODO: Change this to non-async at some point.
|
||||
// Will require changes in other libraries
|
||||
pub async fn load_app() -> Result<App, std::io::Error> {
|
||||
use textsender_models::envy;
|
||||
let auth_url_env = envy::environment::get_env("AUTH_URL").await;
|
||||
let api_url_env = envy::environment::get_env("API_URL").await;
|
||||
let service_username_env = envy::environment::get_env("SERVICE_USERNAME").await;
|
||||
let service_passphrase_env = envy::environment::get_env("SERVICE_PASSPHRASE").await;
|
||||
|
||||
let envs = vec![
|
||||
api_url_env,
|
||||
auth_url_env,
|
||||
service_username_env,
|
||||
service_passphrase_env,
|
||||
];
|
||||
|
||||
let check_envs = |vs: &Vec<envy::EnvVar>| -> (bool, Option<String>) {
|
||||
for env in vs {
|
||||
if env.value.is_empty() {
|
||||
return (false, Some(format!("Key {} is not provided", env.key)));
|
||||
}
|
||||
}
|
||||
(true, None)
|
||||
};
|
||||
|
||||
let (envs_valid, reason) = check_envs(&envs);
|
||||
|
||||
if envs_valid {
|
||||
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(),
|
||||
service_username: envs[2].value.clone(),
|
||||
service_passphrase: envs[3].value.clone(),
|
||||
twilio_config,
|
||||
}),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
} else {
|
||||
Err(std::io::Error::other(reason.unwrap()))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod app;
|
||||
pub mod service;
|
||||
pub mod version;
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = std::env::args().collect();
|
||||
if catapult::version::contains_version(&args) {
|
||||
catapult::version::print_version();
|
||||
std::process::exit(-1);
|
||||
}
|
||||
|
||||
let app = match catapult::app::load_app().await {
|
||||
Ok(app) => app,
|
||||
Err(err) => {
|
||||
eprintln!("Error: {err:?}");
|
||||
std::process::exit(-1);
|
||||
}
|
||||
};
|
||||
|
||||
println!("App: {app:?}");
|
||||
|
||||
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::core::Service {
|
||||
app: app.clone(),
|
||||
token,
|
||||
};
|
||||
|
||||
loop {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svc.do_the_work().await;
|
||||
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(
|
||||
catapult::app::SECONDS_TO_SLEEP,
|
||||
))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
pub struct Auth {
|
||||
pub app: crate::app::App,
|
||||
}
|
||||
|
||||
impl Auth {
|
||||
pub async fn get_token(&self) -> Result<textsender_models::token::Login, std::io::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
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.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.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(err) => Err(std::io::Error::other(err.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_refresh_token(
|
||||
&self,
|
||||
login_result: &textsender_models::token::Login,
|
||||
) -> Result<textsender_models::token::Login, std::io::Error> {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
_ => Err(std::io::Error::other("Error getting token")),
|
||||
},
|
||||
Err(err) => Err(std::io::Error::other(err.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_token_response(
|
||||
response: &str,
|
||||
) -> Result<textsender_models::token::LoginResult, std::io::Error> {
|
||||
match serde_json::from_str::<serde_json::Value>(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())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn has_token_expired(token: &textsender_models::token::LoginResult) -> bool {
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
pub struct Contact {
|
||||
pub app: crate::app::App,
|
||||
pub token: textsender_models::token::LoginResult,
|
||||
}
|
||||
|
||||
impl Contact {
|
||||
pub async fn get(
|
||||
&self,
|
||||
contact_id: &uuid::Uuid,
|
||||
) -> Result<Vec<textsender_models::contact::Contact>, std::io::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
let endpoint = format!("api/v1/contact?id={contact_id}");
|
||||
let api_url = format!("{}/{endpoint}", self.app.api_url);
|
||||
|
||||
println!("Url: {api_url:?}");
|
||||
|
||||
let (key, header) = super::auth_header(&self.token.access_token);
|
||||
|
||||
match client.get(api_url).header(key, header).send().await {
|
||||
Ok(response) => match response.status() {
|
||||
reqwest::StatusCode::OK => match response.text().await {
|
||||
Ok(val) => match parse_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())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_response(
|
||||
response: &str,
|
||||
) -> Result<Vec<textsender_models::contact::Contact>, std::io::Error> {
|
||||
match serde_json::from_str::<serde_json::Value>(response) {
|
||||
Ok(j) => 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 mut events: Vec<textsender_models::contact::Contact> = Vec::new();
|
||||
|
||||
for event in lrs.iter() {
|
||||
let ll: textsender_models::contact::Contact =
|
||||
match serde_json::from_value(event.clone()) {
|
||||
Ok(lr) => lr,
|
||||
Err(err) => {
|
||||
return Err(std::io::Error::other(err.to_string()));
|
||||
}
|
||||
};
|
||||
events.push(ll);
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
}
|
||||
_ => Err(std::io::Error::other("Error parsing response")),
|
||||
},
|
||||
Err(err) => Err(std::io::Error::other(err.to_string())),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
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");
|
||||
println!("Checking queue");
|
||||
|
||||
use textsender_models::message::scheduling::ScheduledMessage;
|
||||
|
||||
let queue = super::queue::Queue {
|
||||
app: self.app.clone(),
|
||||
token: self.token.clone(),
|
||||
};
|
||||
let queue_item: Option<ScheduledMessage> = match queue.get_queue().await {
|
||||
Ok(item) => Some(item),
|
||||
Err(err) => {
|
||||
eprintln!("Error: {err:?}");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if queue_item.is_none() {
|
||||
println!("No queue item found");
|
||||
return;
|
||||
}
|
||||
let queue_item = queue_item.unwrap();
|
||||
|
||||
println!("Queue item Id: {:?}", queue_item.id);
|
||||
|
||||
if !self.is_schedulable(&queue_item) {
|
||||
println!("Not schedulable");
|
||||
return;
|
||||
}
|
||||
|
||||
println!("Can schedule");
|
||||
|
||||
let events_req = super::event::Event {
|
||||
app: self.app.clone(),
|
||||
token: self.token.clone(),
|
||||
};
|
||||
|
||||
let scheduled_message_id = queue_item.id;
|
||||
let events = match events_req.get(&scheduled_message_id).await {
|
||||
Ok(events) => Some(events),
|
||||
Err(err) => {
|
||||
eprintln!("Error: {err:?}");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let contacts = super::contact::Contact {
|
||||
app: self.app.clone(),
|
||||
token: self.token.clone(),
|
||||
};
|
||||
let messages = super::message::Message {
|
||||
app: self.app.clone(),
|
||||
token: self.token.clone(),
|
||||
};
|
||||
let sch_msg = super::scheduler::ScheduledMessage {
|
||||
app: self.app.clone(),
|
||||
token: self.token.clone(),
|
||||
};
|
||||
let mer_req = super::mer::MessageEventResponse {
|
||||
app: self.app.clone(),
|
||||
token: self.token.clone(),
|
||||
};
|
||||
|
||||
let events = events.unwrap_or_default();
|
||||
for event in &events {
|
||||
println!("Event: {event:?}");
|
||||
let contact = &match contacts.get(&event.contact_id).await {
|
||||
Ok(contact) => contact,
|
||||
Err(err) => {
|
||||
eprintln!("Error: {err:?}");
|
||||
continue;
|
||||
}
|
||||
}[0];
|
||||
let message = &match messages.get(&event.message_id).await {
|
||||
Ok(messages) => messages,
|
||||
Err(err) => {
|
||||
eprintln!("Error: {err:?}");
|
||||
continue;
|
||||
}
|
||||
}[0];
|
||||
let scheduled_message = match sch_msg.get(&event.scheduled_message_id).await {
|
||||
Ok(sch_msg_here) => sch_msg_here,
|
||||
Err(err) => {
|
||||
eprintln!("Error: {err:?}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
println!("Contact Id: {:?}", contact.id);
|
||||
println!("Message Id: {:?}", message.id);
|
||||
println!("Scheduled Message Id: {:?}", scheduled_message.id);
|
||||
|
||||
let param = swoosh::twilio::types::Parameters {
|
||||
schedule: true,
|
||||
schedule_at: scheduled_message.scheduled,
|
||||
};
|
||||
|
||||
let twilio_config = &self.app.twilio_config;
|
||||
println!("Config: {twilio_config:?}");
|
||||
println!("SM: {scheduled_message:?}");
|
||||
|
||||
match swoosh::twilio::api::send_message(message, contact, ¶m, twilio_config).await {
|
||||
Ok(resp) => {
|
||||
println!("Message scheduled");
|
||||
// MER response
|
||||
let result = swoosh::twilio::api::response_to_json(resp).await;
|
||||
let mer = textsender_models::message::event::MessageEventResponse {
|
||||
contact_id: contact.id.unwrap(),
|
||||
scheduled_message_event_id: Some(event.id),
|
||||
response: result,
|
||||
message_id: message.id.unwrap(),
|
||||
sent: scheduled_message.scheduled,
|
||||
user_id: scheduled_message.user_id,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
match mer_req.record_message_event_response(&mer).await {
|
||||
Ok(response) => {
|
||||
println!("Recording MER");
|
||||
println!("Response: {response:?}");
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Error recording mer");
|
||||
eprintln!("Error: {err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Message not sent");
|
||||
eprintln!("Error: {err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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(
|
||||
&self,
|
||||
queue_item: &textsender_models::message::scheduling::ScheduledMessage,
|
||||
) -> bool {
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
|
||||
match queue_item.scheduled {
|
||||
Some(date) => date > now,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
pub struct Event {
|
||||
pub app: crate::app::App,
|
||||
pub token: textsender_models::token::LoginResult,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub async fn get(
|
||||
&self,
|
||||
scheduled_message_id: &uuid::Uuid,
|
||||
) -> Result<Vec<textsender_models::message::scheduling::ScheduledMessageEvent>, std::io::Error>
|
||||
{
|
||||
let client = reqwest::Client::new();
|
||||
let endpoint =
|
||||
format!("api/v1/schedule/message/event?scheduled_message_id={scheduled_message_id}");
|
||||
let api_url = format!("{}/{endpoint}", self.app.api_url);
|
||||
|
||||
println!("Url: {api_url:?}");
|
||||
|
||||
let (key, header) = super::auth_header(&self.token.access_token);
|
||||
|
||||
match client.get(api_url).header(key, header).send().await {
|
||||
Ok(response) => match response.status() {
|
||||
reqwest::StatusCode::OK => match response.text().await {
|
||||
Ok(val) => match parse_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 Scheduled Message Event",
|
||||
)),
|
||||
},
|
||||
Err(err) => Err(std::io::Error::other(err.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_response(
|
||||
response: &str,
|
||||
) -> Result<Vec<textsender_models::message::scheduling::ScheduledMessageEvent>, std::io::Error> {
|
||||
match serde_json::from_str::<serde_json::Value>(response) {
|
||||
Ok(j) => 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 mut events: Vec<
|
||||
textsender_models::message::scheduling::ScheduledMessageEvent,
|
||||
> = Vec::new();
|
||||
|
||||
for event in lrs.iter() {
|
||||
let ll: textsender_models::message::scheduling::ScheduledMessageEvent =
|
||||
match serde_json::from_value(event.clone()) {
|
||||
Ok(lr) => lr,
|
||||
Err(err) => {
|
||||
return Err(std::io::Error::other(err.to_string()));
|
||||
}
|
||||
};
|
||||
events.push(ll);
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
}
|
||||
_ => Err(std::io::Error::other("Error parsing response")),
|
||||
},
|
||||
Err(err) => Err(std::io::Error::other(err.to_string())),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
pub struct MessageEventResponse {
|
||||
pub app: crate::app::App,
|
||||
pub token: textsender_models::token::LoginResult,
|
||||
}
|
||||
|
||||
impl MessageEventResponse {
|
||||
pub async fn record_message_event_response(
|
||||
&self,
|
||||
mer: &textsender_models::message::event::MessageEventResponse,
|
||||
) -> Result<textsender_models::message::event::MessageEventResponse, std::io::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
let endpoint = String::from("api/v1/schedule/message/event/response/record");
|
||||
let api_url = format!("{}/{endpoint}", self.app.api_url);
|
||||
|
||||
println!("Url: {api_url:?}");
|
||||
|
||||
use time::format_description::well_known::Iso8601;
|
||||
let sent = match mer.sent.unwrap().format(&Iso8601::DEFAULT) {
|
||||
Ok(converted) => converted,
|
||||
Err(err) => {
|
||||
return Err(std::io::Error::other(err.to_string()));
|
||||
}
|
||||
};
|
||||
|
||||
let payload = serde_json::json!({
|
||||
"scheduled_message_event_id": mer.scheduled_message_event_id.unwrap(),
|
||||
"response": mer.response,
|
||||
"user_id": mer.user_id,
|
||||
"sent": sent,
|
||||
"status": textsender_models::message::event::MESSAGE_EVENT_RESPONSE_STATUS_SCHEDULED,
|
||||
"contact_id": mer.contact_id,
|
||||
"message_id": mer.message_id
|
||||
});
|
||||
|
||||
println!("Payload: {payload:?}");
|
||||
|
||||
let (key, header) = super::auth_header(&self.token.access_token);
|
||||
|
||||
match client
|
||||
.post(api_url)
|
||||
.json(&payload)
|
||||
.header(key, header)
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(response) => match response.status() {
|
||||
reqwest::StatusCode::CREATED | reqwest::StatusCode::OK => {
|
||||
println!("Response: {response:?}");
|
||||
match response.text().await {
|
||||
Ok(val) => match parse_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 recording Message Event Response",
|
||||
)),
|
||||
},
|
||||
Err(err) => Err(std::io::Error::other(err.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* {
|
||||
"scheduled_message_event_id": "{{scheduled_message_event_id}}",
|
||||
"response": {{text_response_raw}},
|
||||
"user_id": "{{user_id}}",
|
||||
"sent": "2026-06-20T17:10:00Z",
|
||||
"status": "{{mer_status_scheduled}}",
|
||||
"contact_id": "{{contact_id}}",
|
||||
"message_id": "{{message_id}}"
|
||||
}
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
async fn parse_response(
|
||||
response: &str,
|
||||
) -> Result<textsender_models::message::event::MessageEventResponse, std::io::Error> {
|
||||
match serde_json::from_str::<serde_json::Value>(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::message::event::MessageEventResponse =
|
||||
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())),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
pub struct Message {
|
||||
pub app: crate::app::App,
|
||||
pub token: textsender_models::token::LoginResult,
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub async fn get(
|
||||
&self,
|
||||
message_id: &uuid::Uuid,
|
||||
) -> Result<Vec<textsender_models::message::Message>, std::io::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
let endpoint = format!("api/v1/message?id={message_id}");
|
||||
let api_url = format!("{}/{endpoint}", self.app.api_url);
|
||||
|
||||
println!("Url: {api_url:?}");
|
||||
|
||||
let (key, header) = super::auth_header(&self.token.access_token);
|
||||
|
||||
match client.get(api_url).header(key, header).send().await {
|
||||
Ok(response) => match response.status() {
|
||||
reqwest::StatusCode::OK => match response.text().await {
|
||||
Ok(val) => match parse_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())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_response(
|
||||
response: &str,
|
||||
) -> Result<Vec<textsender_models::message::Message>, std::io::Error> {
|
||||
match serde_json::from_str::<serde_json::Value>(response) {
|
||||
Ok(j) => 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 mut events: Vec<textsender_models::message::Message> = Vec::new();
|
||||
|
||||
for event in lrs.iter() {
|
||||
let ll: textsender_models::message::Message =
|
||||
match serde_json::from_value(event.clone()) {
|
||||
Ok(lr) => lr,
|
||||
Err(err) => {
|
||||
return Err(std::io::Error::other(err.to_string()));
|
||||
}
|
||||
};
|
||||
events.push(ll);
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
}
|
||||
_ => Err(std::io::Error::other("Error parsing response")),
|
||||
},
|
||||
Err(err) => Err(std::io::Error::other(err.to_string())),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
pub mod auth;
|
||||
pub mod contact;
|
||||
pub mod core;
|
||||
pub mod event;
|
||||
pub mod mer;
|
||||
pub mod message;
|
||||
pub mod queue;
|
||||
pub mod scheduler;
|
||||
|
||||
pub fn auth_header(
|
||||
access_token: &str,
|
||||
) -> (reqwest::header::HeaderName, reqwest::header::HeaderValue) {
|
||||
let bearer = format!("Bearer {}", access_token);
|
||||
let header_value = reqwest::header::HeaderValue::from_str(&bearer).unwrap();
|
||||
(reqwest::header::AUTHORIZATION, header_value)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
pub struct Queue {
|
||||
pub app: crate::app::App,
|
||||
pub token: textsender_models::token::LoginResult,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub async fn get_queue(
|
||||
&self,
|
||||
) -> Result<textsender_models::message::scheduling::ScheduledMessage, std::io::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
let endpoint = String::from("api/v1/schedule/message/fetch");
|
||||
let api_url = format!("{}/{endpoint}", self.app.api_url);
|
||||
|
||||
println!("Url: {api_url:?}");
|
||||
|
||||
let (key, header) = super::auth_header(&self.token.access_token);
|
||||
|
||||
match client.get(api_url).header(key, header).send().await {
|
||||
Ok(response) => match response.status() {
|
||||
reqwest::StatusCode::OK => {
|
||||
println!("Response: {response:?}");
|
||||
match response.text().await {
|
||||
Ok(val) => match parse_queue_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())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_queue_response(
|
||||
response: &str,
|
||||
) -> Result<textsender_models::message::scheduling::ScheduledMessage, std::io::Error> {
|
||||
match serde_json::from_str::<serde_json::Value>(response) {
|
||||
Ok(j) => {
|
||||
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::message::scheduling::ScheduledMessage =
|
||||
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())),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
pub struct ScheduledMessage {
|
||||
pub app: crate::app::App,
|
||||
pub token: textsender_models::token::LoginResult,
|
||||
}
|
||||
|
||||
impl ScheduledMessage {
|
||||
pub async fn get(
|
||||
&self,
|
||||
scheduled_message_id: &uuid::Uuid,
|
||||
) -> Result<textsender_models::message::scheduling::ScheduledMessage, std::io::Error> {
|
||||
let client = reqwest::Client::new();
|
||||
let endpoint = format!("api/v1/schedule/message?id={scheduled_message_id}");
|
||||
let api_url = format!("{}/{endpoint}", self.app.api_url);
|
||||
|
||||
println!("Url: {api_url:?}");
|
||||
|
||||
let (key, header) = super::auth_header(&self.token.access_token);
|
||||
|
||||
match client.get(api_url).header(key, header).send().await {
|
||||
Ok(response) => match response.status() {
|
||||
reqwest::StatusCode::OK => match response.text().await {
|
||||
Ok(val) => match parse_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 Scheduled Message")),
|
||||
},
|
||||
Err(err) => Err(std::io::Error::other(err.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn parse_response(
|
||||
response: &str,
|
||||
) -> Result<textsender_models::message::scheduling::ScheduledMessage, std::io::Error> {
|
||||
match serde_json::from_str::<serde_json::Value>(response) {
|
||||
Ok(j) => 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 ll: textsender_models::message::scheduling::ScheduledMessage =
|
||||
match serde_json::from_value(lrs[0].clone()) {
|
||||
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())),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
pub fn print_version() {
|
||||
let name = env!("CARGO_PKG_NAME");
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
|
||||
println!("{name:?} {version:?}");
|
||||
}
|
||||
|
||||
pub fn contains_version(args: &Vec<String>) -> bool {
|
||||
let valid_flags = vec!["-v", "--version"];
|
||||
|
||||
for arg in args {
|
||||
for valid_flag in &valid_flags {
|
||||
if valid_flag == arg {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
Reference in New Issue
Block a user