3 Commits
Author SHA1 Message Date
phoenix f9c098b92f Adding license (#18)
catapult PR / Rustfmt (push) Successful in 41s
catapult PR / Clippy (push) Successful in 59s
catapult PR / Check (push) Successful in 1m44s
Reviewed-on: #18
2026-07-14 11:47:05 -04:00
phoenix 6801b1e635 Dependency name change (#17)
Reviewed-on: #17
2026-07-13 16:33:51 -04:00
phoenix 50aa9089f0 Update rust (#16)
catapult PR / Rustfmt (pull_request) Successful in 48s
catapult PR / Clippy (pull_request) Successful in 1m55s
catapult PR / Check (pull_request) Successful in 2m21s
Reviewed-on: #16
2026-07-10 18:33:46 -04:00
16 changed files with 160 additions and 121 deletions
+6 -3
View File
@@ -4,6 +4,9 @@ on:
pull_request: pull_request:
branches: branches:
- main - main
push:
branches:
- main
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@@ -17,7 +20,7 @@ jobs:
- uses: actions/checkout@v6 - 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.1 toolchain: 1.97
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
@@ -36,7 +39,7 @@ jobs:
- uses: actions/checkout@v6 - 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.1 toolchain: 1.97
- run: rustup component add rustfmt - run: rustup component add rustfmt
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
@@ -56,7 +59,7 @@ jobs:
- uses: actions/checkout@v6 - 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.1 toolchain: 1.97
- run: rustup component add clippy - run: rustup component add clippy
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
Generated
+51 -51
View File
@@ -81,9 +81,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64-ng" name = "base64-ng"
version = "1.3.5" version = "1.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b87dbd7e45c4885ad3432a2d125ddb155c5ee87046ab23bad043dfe84fedfa2" checksum = "78dbdaa3c8250efc13282f483f2ae92733e407c9cf6ffc2fe7918ce1ee420724"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
@@ -126,18 +126,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.12.0" version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
[[package]] [[package]]
name = "catapult" name = "catapult"
version = "0.3.3" version = "0.3.5"
dependencies = [ dependencies = [
"reqwest", "reqwest",
"schedtxt_models",
"serde_json", "serde_json",
"swoosh", "swoosh",
"textsender_models",
"time", "time",
"tokio", "tokio",
"uuid", "uuid",
@@ -145,9 +145,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.66" version = "1.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@@ -734,9 +734,9 @@ dependencies = [
[[package]] [[package]]
name = "http-body" name = "http-body"
version = "1.0.1" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http",
@@ -744,9 +744,9 @@ dependencies = [
[[package]] [[package]]
name = "http-body-util" name = "http-body-util"
version = "0.1.3" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
@@ -1121,9 +1121,9 @@ dependencies = [
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.2" version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]] [[package]]
name = "mime" name = "mime"
@@ -1153,9 +1153,9 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.2.1" version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427"
dependencies = [ dependencies = [
"libc", "libc",
"wasi", "wasi",
@@ -1423,9 +1423,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.12.4" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -1435,9 +1435,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.14" version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -1540,9 +1540,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.41" version = "0.23.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138"
dependencies = [ dependencies = [
"aws-lc-rs", "aws-lc-rs",
"once_cell", "once_cell",
@@ -1643,6 +1643,22 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "schedtxt_models"
version = "0.5.3"
source = "git+ssh://git@git.kundeng.us/phoenix/schedtxt_models.git?tag=v0.5.3#597af4e84c082bb437cc94817bb19592614681a5"
dependencies = [
"const_format",
"dotenvy",
"josekit",
"serde",
"serde_json",
"sqlx",
"time",
"utoipa",
"uuid",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@@ -1822,9 +1838,9 @@ dependencies = [
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.6.4" version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.61.2", "windows-sys 0.61.2",
@@ -1832,9 +1848,9 @@ dependencies = [
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.9.8" version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e"
dependencies = [ dependencies = [
"lock_api", "lock_api",
] ]
@@ -2044,14 +2060,14 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "swoosh" name = "swoosh"
version = "0.5.2" version = "0.5.4"
source = "git+ssh://git@git.kundeng.us/phoenix/swoosh.git?tag=v0.5.2#50e4b209f521d8985d73a33b4a8f1db69334100a" source = "git+ssh://git@git.kundeng.us/phoenix/swoosh.git?tag=v0.5.4#84ba4c21ec721662d76bb21ef67062d51f31f719"
dependencies = [ dependencies = [
"base64-ng", "base64-ng",
"reqwest", "reqwest",
"schedtxt_models",
"serde", "serde",
"serde_json", "serde_json",
"textsender_models",
"time", "time",
] ]
@@ -2120,22 +2136,6 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "textsender_models"
version = "0.5.1"
source = "git+ssh://git@git.kundeng.us/phoenix/textsender_models.git?tag=v0.5.1#151eeaacf64e255bde56a48df03f4c46ec77c235"
dependencies = [
"const_format",
"dotenvy",
"josekit",
"serde",
"serde_json",
"sqlx",
"time",
"utoipa",
"uuid",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.18" version = "2.0.18"
@@ -2198,9 +2198,9 @@ dependencies = [
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.11.0" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f"
dependencies = [ dependencies = [
"tinyvec_macros", "tinyvec_macros",
] ]
@@ -2451,9 +2451,9 @@ dependencies = [
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.23.4" version = "1.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" checksum = "ea5fab0d6c3c01ae70085a09cb03d4c7a1d6314e2b3e075392783396d724ca0a"
dependencies = [ dependencies = [
"getrandom 0.4.3", "getrandom 0.4.3",
"js-sys", "js-sys",
@@ -2818,6 +2818,6 @@ dependencies = [
[[package]] [[package]]
name = "zmij" name = "zmij"
version = "1.0.21" version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
+7 -5
View File
@@ -1,7 +1,9 @@
[package] [package]
name = "catapult" name = "catapult"
version = "0.3.3" version = "0.3.5"
rust-version = "1.96.1" rust-version = "1.97"
license = "MIT"
description = "Service to carry out text message scheduling"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
@@ -9,8 +11,8 @@ tokio = { version = "1.52.3", features = ["full"] }
reqwest = { version = "0.13.4", features = ["json", "stream", "multipart"] } reqwest = { version = "0.13.4", features = ["json", "stream", "multipart"] }
serde_json = { version = "1.0.150" } serde_json = { version = "1.0.150" }
time = { version = "0.3.53", 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.5", features = ["v4", "serde"] }
textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender_models.git", tag = "v0.5.1" } schedtxt_models = { git = "ssh://git@git.kundeng.us/phoenix/schedtxt_models.git", tag = "v0.5.3" }
swoosh = { git = "ssh://git@git.kundeng.us/phoenix/swoosh.git", tag = "v0.5.2" } swoosh = { git = "ssh://git@git.kundeng.us/phoenix/swoosh.git", tag = "v0.5.4" }
[dev-dependencies] [dev-dependencies]
+1 -18
View File
@@ -1,5 +1,4 @@
# Stage 1: Build the application FROM rust:1.97 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
@@ -11,35 +10,23 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
openssh-client git \ openssh-client git \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# << --- ADD HOST KEY HERE --- >>
# Replace 'yourgithost.com' with the actual hostname (e.g., github.com)
RUN mkdir -p -m 0700 ~/.ssh && \ RUN mkdir -p -m 0700 ~/.ssh && \
ssh-keyscan git.kundeng.us >> ~/.ssh/known_hosts ssh-keyscan git.kundeng.us >> ~/.ssh/known_hosts
# Copy Cargo manifests
COPY Cargo.toml Cargo.lock ./ COPY Cargo.toml Cargo.lock ./
# Build *only* dependencies to leverage Docker cache
# This dummy build caches dependencies as a separate layer
RUN --mount=type=ssh mkdir src && \ RUN --mount=type=ssh mkdir src && \
echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs && \ echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs && \
cargo build --release --quiet && \ cargo build --release --quiet && \
rm -rf src target/release/deps/catapult* rm -rf src target/release/deps/catapult*
# Copy the actual source code
COPY src ./src COPY src ./src
# If you have other directories like `templates` or `static`, copy them too # If you have other directories like `templates` or `static`, copy them too
COPY .env ./.env COPY .env ./.env
# << --- SSH MOUNT ADDED HERE --- >>
# Build *only* dependencies to leverage Docker cache
# This dummy build caches dependencies as a separate layer
# Mount the SSH agent socket for this command
RUN --mount=type=ssh \ RUN --mount=type=ssh \
cargo build --release --quiet cargo build --release --quiet
# Stage 2: Create the final, smaller runtime image
# Use a minimal base image like debian-slim or even distroless for security/size
FROM debian:trixie-slim FROM debian:trixie-slim
# Install runtime dependencies if needed (e.g., SSL certificates) # Install runtime dependencies if needed (e.g., SSL certificates)
@@ -48,12 +35,8 @@ RUN apt-get update && apt-get install -y ca-certificates libssl-dev libssl3 && r
# Set the working directory # Set the working directory
WORKDIR /usr/local/bin WORKDIR /usr/local/bin
# Copy the compiled binary from the builder stage
# Replace 'catapult' with the actual name of your binary (usually the crate name)
COPY --from=builder /usr/src/app/target/release/catapult . COPY --from=builder /usr/src/app/target/release/catapult .
# Copy other necessary files like .env (if used for runtime config) or static assets
# It's generally better to configure via environment variables in Docker though
COPY --from=builder /usr/src/app/.env . COPY --from=builder /usr/src/app/.env .
# Set the command to run your application # Set the command to run your application
+22
View File
@@ -0,0 +1,22 @@
Copyright (c) 2026 Kun Deng.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
+29
View File
@@ -0,0 +1,29 @@
# catapult
A service that manages scheduling text messages.
## Getting started
Docker isn't required, but it is the quickest way to get started.
Copy over the `.env.docker.sample` to `.env`. From that point, make edits to the
file to get it working.
### Messaging configuration
The service vendor used to send the messages is `twilio`. After signing up and being
provided credentials, update the `TWILIO_*` variables.
### Client-Server interaction
In order for `catapult` to function properly, credentials need to be provided via
`SERVICE_USERNAME` and `SERVICE_PASSPHRASE`. The credentials are created from making
an API call to register a service user in `textsender_auth`. So, you need to have credentials
set in the `.env` file and use those same credentials to create the account in the
API call.
### API sources
The `AUTH_URL` and `API_URL` variables need to be set for the base URL for the
`textsender_auth` and `textsender_api` respectively.
Since this is meant to run along with `textsender_auth` and `textsender_api`, it isn't
meant to be run by itself. So no need to build or run the container in isolation, but
that capability is present.
+2 -2
View File
@@ -4,8 +4,8 @@ services:
songparser: songparser:
build: build:
context: . context: .
ssh: ["default"] # Uses host's SSH agent ssh: ["default"]
container_name: catapult container_name: catapult
env_file: env_file:
- .env - .env
restart: unless-stopped # Optional: Restart policy restart: unless-stopped
+3 -3
View File
@@ -9,11 +9,11 @@ pub struct App {
pub auth_url: String, pub auth_url: String,
pub service_username: String, pub service_username: String,
pub service_passphrase: String, pub service_passphrase: String,
pub twilio_config: textsender_models::config::auxiliary::TwilioConfig, pub twilio_config: schedtxt_models::config::auxiliary::TwilioConfig,
} }
pub fn load_app() -> Result<App, std::io::Error> { pub fn load_app() -> Result<App, std::io::Error> {
use textsender_models::envy; use schedtxt_models::envy;
let auth_url_env = envy::environment::get_env("AUTH_URL"); let auth_url_env = envy::environment::get_env("AUTH_URL");
let api_url_env = envy::environment::get_env("API_URL"); let api_url_env = envy::environment::get_env("API_URL");
let service_username_env = envy::environment::get_env("SERVICE_USERNAME"); let service_username_env = envy::environment::get_env("SERVICE_USERNAME");
@@ -41,7 +41,7 @@ pub fn load_app() -> Result<App, std::io::Error> {
let api_url: String = api_url_env.value; let api_url: String = api_url_env.value;
let service_username: String = service_username_env.value; let service_username: String = service_username_env.value;
let service_passphrase: String = service_passphrase_env.value; let service_passphrase: String = service_passphrase_env.value;
match textsender_models::config::auxiliary::load_config() { match schedtxt_models::config::auxiliary::load_config() {
Ok(twilio_config) => Ok(App { Ok(twilio_config) => Ok(App {
api_url, api_url,
auth_url, auth_url,
+6 -6
View File
@@ -3,7 +3,7 @@ pub struct Auth {
} }
impl Auth { impl Auth {
pub async fn get_token(&self) -> Result<textsender_models::token::Login, std::io::Error> { pub async fn get_token(&self) -> Result<schedtxt_models::token::Login, std::io::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let endpoint = String::from("api/v1/service/login"); let endpoint = String::from("api/v1/service/login");
let api_url = format!("{}/{endpoint}", self.app.auth_url); let api_url = format!("{}/{endpoint}", self.app.auth_url);
@@ -37,8 +37,8 @@ impl Auth {
pub async fn get_refresh_token( pub async fn get_refresh_token(
&self, &self,
login_result: &textsender_models::token::Login, login_result: &schedtxt_models::token::Login,
) -> Result<textsender_models::token::Login, std::io::Error> { ) -> Result<schedtxt_models::token::Login, std::io::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let endpoint = String::from("api/v1/token/refresh"); let endpoint = String::from("api/v1/token/refresh");
let api_url = format!("{}/{endpoint}", self.app.auth_url); let api_url = format!("{}/{endpoint}", self.app.auth_url);
@@ -70,7 +70,7 @@ impl Auth {
async fn parse_token_response( async fn parse_token_response(
response: &str, response: &str,
) -> Result<textsender_models::token::LoginResult, std::io::Error> { ) -> Result<schedtxt_models::token::LoginResult, std::io::Error> {
match serde_json::from_str::<serde_json::Value>(response) { match serde_json::from_str::<serde_json::Value>(response) {
Ok(j) => { Ok(j) => {
println!("Good"); println!("Good");
@@ -85,7 +85,7 @@ async fn parse_token_response(
Err(std::io::Error::other("Error response is empty")) Err(std::io::Error::other("Error response is empty"))
} else { } else {
let lr = lrs[0].clone(); let lr = lrs[0].clone();
let ll: textsender_models::token::LoginResult = let ll: schedtxt_models::token::LoginResult =
match serde_json::from_value(lr) { match serde_json::from_value(lr) {
Ok(lr) => lr, Ok(lr) => lr,
Err(err) => { Err(err) => {
@@ -102,7 +102,7 @@ async fn parse_token_response(
} }
} }
pub async fn has_token_expired(token: &textsender_models::token::LoginResult) -> bool { pub async fn has_token_expired(token: &schedtxt_models::token::LoginResult) -> bool {
let now = time::OffsetDateTime::now_utc(); let now = time::OffsetDateTime::now_utc();
let expire = match time::OffsetDateTime::from_unix_timestamp(token.expires_in) { let expire = match time::OffsetDateTime::from_unix_timestamp(token.expires_in) {
Ok(res) => res, Ok(res) => res,
+5 -5
View File
@@ -1,13 +1,13 @@
pub struct Contact { pub struct Contact {
pub app: std::sync::Arc<crate::app::App>, pub app: std::sync::Arc<crate::app::App>,
pub token: std::sync::Arc<textsender_models::token::LoginResult>, pub token: std::sync::Arc<schedtxt_models::token::LoginResult>,
} }
impl Contact { impl Contact {
pub async fn get( pub async fn get(
&self, &self,
contact_id: &uuid::Uuid, contact_id: &uuid::Uuid,
) -> Result<Vec<textsender_models::contact::Contact>, std::io::Error> { ) -> Result<Vec<schedtxt_models::contact::Contact>, std::io::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let endpoint = format!("api/v1/contact?id={contact_id}"); let endpoint = format!("api/v1/contact?id={contact_id}");
let api_url = format!("{}/{endpoint}", self.app.api_url); let api_url = format!("{}/{endpoint}", self.app.api_url);
@@ -34,17 +34,17 @@ impl Contact {
async fn parse_response( async fn parse_response(
response: &str, response: &str,
) -> Result<Vec<textsender_models::contact::Contact>, std::io::Error> { ) -> Result<Vec<schedtxt_models::contact::Contact>, std::io::Error> {
match serde_json::from_str::<serde_json::Value>(response) { match serde_json::from_str::<serde_json::Value>(response) {
Ok(j) => match j.get("data") { Ok(j) => match j.get("data") {
Some(serde_json::Value::Array(lrs)) => { Some(serde_json::Value::Array(lrs)) => {
if lrs.is_empty() { if lrs.is_empty() {
Err(std::io::Error::other("Error response is empty")) Err(std::io::Error::other("Error response is empty"))
} else { } else {
let mut events: Vec<textsender_models::contact::Contact> = Vec::new(); let mut events: Vec<schedtxt_models::contact::Contact> = Vec::new();
for event in lrs.iter() { for event in lrs.iter() {
let ll: textsender_models::contact::Contact = let ll: schedtxt_models::contact::Contact =
match serde_json::from_value(event.clone()) { match serde_json::from_value(event.clone()) {
Ok(lr) => lr, Ok(lr) => lr,
Err(err) => { Err(err) => {
+4 -4
View File
@@ -1,13 +1,13 @@
pub struct Service { pub struct Service {
pub app: std::sync::Arc<crate::app::App>, pub app: std::sync::Arc<crate::app::App>,
pub token: std::sync::Arc<textsender_models::token::Login>, pub token: std::sync::Arc<schedtxt_models::token::Login>,
} }
impl Service { impl Service {
pub async fn do_the_work(&mut self) { pub async fn do_the_work(&mut self) {
println!("Checking queue"); println!("Checking queue");
use textsender_models::message::scheduling::ScheduledMessage; use schedtxt_models::message::scheduling::ScheduledMessage;
let queue = super::queue::Queue { let queue = super::queue::Queue {
app: std::sync::Arc::clone(&self.app), app: std::sync::Arc::clone(&self.app),
@@ -120,7 +120,7 @@ impl Service {
println!("Message scheduled"); println!("Message scheduled");
// MER response // MER response
let result = swoosh::twilio::api::response_to_json(resp).await; let result = swoosh::twilio::api::response_to_json(resp).await;
let mer = textsender_models::message::event::MessageEventResponse { let mer = schedtxt_models::message::event::MessageEventResponse {
contact_id: contact.id.unwrap(), contact_id: contact.id.unwrap(),
scheduled_message_event_id: Some(event.id), scheduled_message_event_id: Some(event.id),
response: result, response: result,
@@ -151,7 +151,7 @@ impl Service {
fn is_schedulable( fn is_schedulable(
&self, &self,
queue_item: &textsender_models::message::scheduling::ScheduledMessage, queue_item: &schedtxt_models::message::scheduling::ScheduledMessage,
) -> bool { ) -> bool {
match queue_item.scheduled { match queue_item.scheduled {
Some(date) => date > time::OffsetDateTime::now_utc(), Some(date) => date > time::OffsetDateTime::now_utc(),
+5 -5
View File
@@ -1,13 +1,13 @@
pub struct Event { pub struct Event {
pub app: std::sync::Arc<crate::app::App>, pub app: std::sync::Arc<crate::app::App>,
pub token: std::sync::Arc<textsender_models::token::LoginResult>, pub token: std::sync::Arc<schedtxt_models::token::LoginResult>,
} }
impl Event { impl Event {
pub async fn get( pub async fn get(
&self, &self,
scheduled_message_id: &uuid::Uuid, scheduled_message_id: &uuid::Uuid,
) -> Result<Vec<textsender_models::message::scheduling::ScheduledMessageEvent>, std::io::Error> ) -> Result<Vec<schedtxt_models::message::scheduling::ScheduledMessageEvent>, std::io::Error>
{ {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let endpoint = let endpoint =
@@ -38,7 +38,7 @@ impl Event {
async fn parse_response( async fn parse_response(
response: &str, response: &str,
) -> Result<Vec<textsender_models::message::scheduling::ScheduledMessageEvent>, std::io::Error> { ) -> Result<Vec<schedtxt_models::message::scheduling::ScheduledMessageEvent>, std::io::Error> {
match serde_json::from_str::<serde_json::Value>(response) { match serde_json::from_str::<serde_json::Value>(response) {
Ok(j) => match j.get("data") { Ok(j) => match j.get("data") {
Some(serde_json::Value::Array(lrs)) => { Some(serde_json::Value::Array(lrs)) => {
@@ -46,11 +46,11 @@ async fn parse_response(
Err(std::io::Error::other("Error response is empty")) Err(std::io::Error::other("Error response is empty"))
} else { } else {
let mut events: Vec< let mut events: Vec<
textsender_models::message::scheduling::ScheduledMessageEvent, schedtxt_models::message::scheduling::ScheduledMessageEvent,
> = Vec::new(); > = Vec::new();
for event in lrs.iter() { for event in lrs.iter() {
let ll: textsender_models::message::scheduling::ScheduledMessageEvent = let ll: schedtxt_models::message::scheduling::ScheduledMessageEvent =
match serde_json::from_value(event.clone()) { match serde_json::from_value(event.clone()) {
Ok(lr) => lr, Ok(lr) => lr,
Err(err) => { Err(err) => {
+6 -6
View File
@@ -1,13 +1,13 @@
pub struct MessageEventResponse { pub struct MessageEventResponse {
pub app: std::sync::Arc<crate::app::App>, pub app: std::sync::Arc<crate::app::App>,
pub token: std::sync::Arc<textsender_models::token::LoginResult>, pub token: std::sync::Arc<schedtxt_models::token::LoginResult>,
} }
impl MessageEventResponse { impl MessageEventResponse {
pub async fn record_message_event_response( pub async fn record_message_event_response(
&self, &self,
mer: &textsender_models::message::event::MessageEventResponse, mer: &schedtxt_models::message::event::MessageEventResponse,
) -> Result<textsender_models::message::event::MessageEventResponse, std::io::Error> { ) -> Result<schedtxt_models::message::event::MessageEventResponse, std::io::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let endpoint = String::from("api/v1/schedule/message/event/response/record"); let endpoint = String::from("api/v1/schedule/message/event/response/record");
let api_url = format!("{}/{endpoint}", self.app.api_url); let api_url = format!("{}/{endpoint}", self.app.api_url);
@@ -27,7 +27,7 @@ impl MessageEventResponse {
"response": mer.response, "response": mer.response,
"user_id": mer.user_id, "user_id": mer.user_id,
"sent": sent, "sent": sent,
"status": textsender_models::message::event::MESSAGE_EVENT_RESPONSE_STATUS_SCHEDULED, "status": schedtxt_models::message::event::MESSAGE_EVENT_RESPONSE_STATUS_SCHEDULED,
"contact_id": mer.contact_id, "contact_id": mer.contact_id,
"message_id": mer.message_id "message_id": mer.message_id
}); });
@@ -79,7 +79,7 @@ impl MessageEventResponse {
async fn parse_response( async fn parse_response(
response: &str, response: &str,
) -> Result<textsender_models::message::event::MessageEventResponse, std::io::Error> { ) -> Result<schedtxt_models::message::event::MessageEventResponse, std::io::Error> {
match serde_json::from_str::<serde_json::Value>(response) { match serde_json::from_str::<serde_json::Value>(response) {
Ok(j) => { Ok(j) => {
println!("Good"); println!("Good");
@@ -94,7 +94,7 @@ async fn parse_response(
Err(std::io::Error::other("Error response is empty")) Err(std::io::Error::other("Error response is empty"))
} else { } else {
let lr = lrs[0].clone(); let lr = lrs[0].clone();
let ll: textsender_models::message::event::MessageEventResponse = let ll: schedtxt_models::message::event::MessageEventResponse =
match serde_json::from_value(lr) { match serde_json::from_value(lr) {
Ok(lr) => lr, Ok(lr) => lr,
Err(err) => { Err(err) => {
+5 -5
View File
@@ -1,13 +1,13 @@
pub struct Message { pub struct Message {
pub app: std::sync::Arc<crate::app::App>, pub app: std::sync::Arc<crate::app::App>,
pub token: std::sync::Arc<textsender_models::token::LoginResult>, pub token: std::sync::Arc<schedtxt_models::token::LoginResult>,
} }
impl Message { impl Message {
pub async fn get( pub async fn get(
&self, &self,
message_id: &uuid::Uuid, message_id: &uuid::Uuid,
) -> Result<Vec<textsender_models::message::Message>, std::io::Error> { ) -> Result<Vec<schedtxt_models::message::Message>, std::io::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let endpoint = format!("api/v1/message?id={message_id}"); let endpoint = format!("api/v1/message?id={message_id}");
let api_url = format!("{}/{endpoint}", self.app.api_url); let api_url = format!("{}/{endpoint}", self.app.api_url);
@@ -34,17 +34,17 @@ impl Message {
async fn parse_response( async fn parse_response(
response: &str, response: &str,
) -> Result<Vec<textsender_models::message::Message>, std::io::Error> { ) -> Result<Vec<schedtxt_models::message::Message>, std::io::Error> {
match serde_json::from_str::<serde_json::Value>(response) { match serde_json::from_str::<serde_json::Value>(response) {
Ok(j) => match j.get("data") { Ok(j) => match j.get("data") {
Some(serde_json::Value::Array(lrs)) => { Some(serde_json::Value::Array(lrs)) => {
if lrs.is_empty() { if lrs.is_empty() {
Err(std::io::Error::other("Error response is empty")) Err(std::io::Error::other("Error response is empty"))
} else { } else {
let mut events: Vec<textsender_models::message::Message> = Vec::new(); let mut events: Vec<schedtxt_models::message::Message> = Vec::new();
for event in lrs.iter() { for event in lrs.iter() {
let ll: textsender_models::message::Message = let ll: schedtxt_models::message::Message =
match serde_json::from_value(event.clone()) { match serde_json::from_value(event.clone()) {
Ok(lr) => lr, Ok(lr) => lr,
Err(err) => { Err(err) => {
+4 -4
View File
@@ -1,12 +1,12 @@
pub struct Queue { pub struct Queue {
pub app: std::sync::Arc<crate::app::App>, pub app: std::sync::Arc<crate::app::App>,
pub token: std::sync::Arc<textsender_models::token::LoginResult>, pub token: std::sync::Arc<schedtxt_models::token::LoginResult>,
} }
impl Queue { impl Queue {
pub async fn get_queue( pub async fn get_queue(
&self, &self,
) -> Result<textsender_models::message::scheduling::ScheduledMessage, std::io::Error> { ) -> Result<schedtxt_models::message::scheduling::ScheduledMessage, std::io::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let endpoint = String::from("api/v1/schedule/message/fetch"); let endpoint = String::from("api/v1/schedule/message/fetch");
let api_url = format!("{}/{endpoint}", self.app.api_url); let api_url = format!("{}/{endpoint}", self.app.api_url);
@@ -36,7 +36,7 @@ impl Queue {
async fn parse_queue_response( async fn parse_queue_response(
response: &str, response: &str,
) -> Result<textsender_models::message::scheduling::ScheduledMessage, std::io::Error> { ) -> Result<schedtxt_models::message::scheduling::ScheduledMessage, std::io::Error> {
match serde_json::from_str::<serde_json::Value>(response) { match serde_json::from_str::<serde_json::Value>(response) {
Ok(j) => { Ok(j) => {
let message = &j["message"]; let message = &j["message"];
@@ -50,7 +50,7 @@ async fn parse_queue_response(
Err(std::io::Error::other("Error response is empty")) Err(std::io::Error::other("Error response is empty"))
} else { } else {
let lr = lrs[0].clone(); let lr = lrs[0].clone();
let ll: textsender_models::message::scheduling::ScheduledMessage = let ll: schedtxt_models::message::scheduling::ScheduledMessage =
match serde_json::from_value(lr) { match serde_json::from_value(lr) {
Ok(lr) => lr, Ok(lr) => lr,
Err(err) => { Err(err) => {
+4 -4
View File
@@ -1,13 +1,13 @@
pub struct ScheduledMessage { pub struct ScheduledMessage {
pub app: std::sync::Arc<crate::app::App>, pub app: std::sync::Arc<crate::app::App>,
pub token: std::sync::Arc<textsender_models::token::LoginResult>, pub token: std::sync::Arc<schedtxt_models::token::LoginResult>,
} }
impl ScheduledMessage { impl ScheduledMessage {
pub async fn get( pub async fn get(
&self, &self,
scheduled_message_id: &uuid::Uuid, scheduled_message_id: &uuid::Uuid,
) -> Result<textsender_models::message::scheduling::ScheduledMessage, std::io::Error> { ) -> Result<schedtxt_models::message::scheduling::ScheduledMessage, std::io::Error> {
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let endpoint = format!("api/v1/schedule/message?id={scheduled_message_id}"); let endpoint = format!("api/v1/schedule/message?id={scheduled_message_id}");
let api_url = format!("{}/{endpoint}", self.app.api_url); let api_url = format!("{}/{endpoint}", self.app.api_url);
@@ -34,14 +34,14 @@ impl ScheduledMessage {
async fn parse_response( async fn parse_response(
response: &str, response: &str,
) -> Result<textsender_models::message::scheduling::ScheduledMessage, std::io::Error> { ) -> Result<schedtxt_models::message::scheduling::ScheduledMessage, std::io::Error> {
match serde_json::from_str::<serde_json::Value>(response) { match serde_json::from_str::<serde_json::Value>(response) {
Ok(j) => match j.get("data") { Ok(j) => match j.get("data") {
Some(serde_json::Value::Array(lrs)) => { Some(serde_json::Value::Array(lrs)) => {
if lrs.is_empty() { if lrs.is_empty() {
Err(std::io::Error::other("Error response is empty")) Err(std::io::Error::other("Error response is empty"))
} else { } else {
let ll: textsender_models::message::scheduling::ScheduledMessage = let ll: schedtxt_models::message::scheduling::ScheduledMessage =
match serde_json::from_value(lrs[0].clone()) { match serde_json::from_value(lrs[0].clone()) {
Ok(lr) => lr, Ok(lr) => lr,
Err(err) => { Err(err) => {