From f22e4a67d8917b3e4ff6ddbaae9cd821ebf193db Mon Sep 17 00:00:00 2001 From: 112batuhan Date: Sun, 22 Dec 2024 02:34:20 +0300 Subject: [PATCH] feat: basic websocket client (plus sidetracked into router setup, wasted hours and then found an easier solution lmao) --- Cargo.lock | 130 ++++++++++++++++++++++++++++++++++------- Cargo.toml | 1 + src/discord_webhook.rs | 32 ++++++++++ src/error.rs | 4 ++ src/lib.rs | 1 + tests/common/mod.rs | 95 ++---------------------------- 6 files changed, 154 insertions(+), 109 deletions(-) create mode 100644 src/discord_webhook.rs diff --git a/Cargo.lock b/Cargo.lock index b5392d7..4b3b6a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -481,9 +481,9 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-util", "itoa", "matchit", @@ -516,7 +516,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", @@ -539,7 +539,7 @@ dependencies = [ "cookie", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", @@ -584,7 +584,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-util", "mime", "pretty_assertions", @@ -774,7 +774,7 @@ dependencies = [ "home", "http 1.1.0", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-named-pipe", "hyper-rustls", "hyper-util", @@ -2002,6 +2002,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.6" @@ -2196,6 +2215,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -2215,7 +2245,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body", + "http-body 1.0.1", "pin-project-lite", ] @@ -2237,6 +2267,30 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.5.0" @@ -2246,9 +2300,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", + "h2 0.4.6", "http 1.1.0", - "http-body", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -2265,7 +2319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" dependencies = [ "hex", - "hyper", + "hyper 1.5.0", "hyper-util", "pin-project-lite", "tokio", @@ -2281,7 +2335,7 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper", + "hyper 1.5.0", "hyper-util", "rustls", "rustls-pki-types", @@ -2291,6 +2345,19 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -2299,7 +2366,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -2317,8 +2384,8 @@ dependencies = [ "futures-channel", "futures-util", "http 1.1.0", - "http-body", - "hyper", + "http-body 1.0.1", + "hyper 1.5.0", "pin-project-lite", "socket2", "tokio", @@ -2334,7 +2401,7 @@ checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" dependencies = [ "hex", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-util", "pin-project-lite", "tokio", @@ -2705,6 +2772,7 @@ dependencies = [ "tracing", "tracing-subscriber", "uuid", + "webhook", ] [[package]] @@ -3105,6 +3173,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.4.1+3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.103" @@ -3113,6 +3190,7 @@ checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -3803,13 +3881,13 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.4.6", "http 1.1.0", - "http-body", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.5.0", "hyper-rustls", - "hyper-tls", + "hyper-tls 0.6.0", "hyper-util", "ipnet", "js-sys", @@ -5315,7 +5393,7 @@ dependencies = [ "bytes", "futures-core", "http 1.1.0", - "http-body", + "http-body 1.0.1", "pin-project-lite", "tokio", "tokio-util", @@ -5776,6 +5854,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webhook" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d801ea0225da29d32c85b21d0cb12ed628783f5fa1fbe226e586a3ef6ca96f" +dependencies = [ + "hyper 0.14.32", + "hyper-tls 0.5.0", + "serde", + "serde_json", +] + [[package]] name = "webpki-roots" version = "0.26.6" diff --git a/Cargo.toml b/Cargo.toml index 737ebc7..1b4f6fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ tower-http = { version = "0.6.1", features = [ ] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +webhook = { version = "2.1.2", features = ["models"] } [patch.crates-io] serde = { git = "https://github.com/frederik-uni/serde" } diff --git a/src/discord_webhook.rs b/src/discord_webhook.rs new file mode 100644 index 0000000..ac53766 --- /dev/null +++ b/src/discord_webhook.rs @@ -0,0 +1,32 @@ +use http::StatusCode; +use webhook::models::Message; + +use crate::error::AppError; + +pub struct WebhookClient { + client: reqwest::Client, + url: String, +} + +impl WebhookClient { + pub fn new(url: &str) -> WebhookClient { + WebhookClient { + client: reqwest::Client::new(), + url: url.to_owned(), + } + } + + /// Basically a simple recreation of webhook-rs client send implementation with reqwest + pub async fn send(&self, message: &Message) -> Result<(), AppError> { + let res = self.client.post(&self.url).json(message).send().await?; + if res.status() == StatusCode::NO_CONTENT { + Ok(()) + } else { + let err_msg = match res.text().await { + Ok(msg) => msg, + Err(err) => format!("Webhook reqwest client error: {}", err), + }; + Err(AppError::Webhook(err_msg)) + } + } +} diff --git a/src/error.rs b/src/error.rs index a5249c6..d226ec8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -73,6 +73,9 @@ pub enum AppError { #[error("Parse int: {0}")] ParseInt(#[from] ParseIntError), + + #[error("Discord webhook error:{0}")] + Webhook(String), } #[derive(Serialize)] @@ -97,6 +100,7 @@ impl IntoResponse for AppError { | AppError::ActivityStreamClosed | AppError::SurrealDbSerialization(_) | AppError::StdIO(_) + | AppError::Webhook(_) | AppError::ActivityPreferencesQuery | AppError::SephomoreError(_) => StatusCode::INTERNAL_SERVER_ERROR, AppError::MissingTokenCookie diff --git a/src/lib.rs b/src/lib.rs index 0991866..2a43040 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ use osu_api::request::Requester; pub mod custom_cache; pub mod daily_update; pub mod database; +pub mod discord_webhook; pub mod documentation; pub mod error; pub mod handlers; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 2baa333..3443bb0 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,16 +1,10 @@ -use std::sync::Arc; +use std::{net::SocketAddr, sync::Arc}; -use axum::{ - middleware, - routing::{any, delete, get, patch, post}, - Router, -}; use axum_test::TestServer; use mapper_influences_backend_rs::{ database::DatabaseClient, - handlers, osu_api::{credentials_grant::CredentialsGrantClient, request::OsuApiRequestClient}, - AppState, + routes, AppState, }; use osu_test_client::OsuApiTestClient; use surrealdb_migrations::MigrationRunner; @@ -21,86 +15,6 @@ use testcontainers_modules::{ pub mod osu_test_client; -/// TODO: make it different so that we can have one place we have to change. -/// Redefining routes because aide and axum_test is not compatible -pub fn test_routes(state: Arc) -> Router> { - Router::new() - .route("/search/map", get(handlers::osu_search::osu_beatmap_search)) - .route( - "/search/map/:beatmap_id", - get(handlers::osu_search::osu_singular_beatmap_serch), - ) - .route( - "/search/user/:query", - get(handlers::osu_search::osu_user_search), - ) - .route( - "/influence/:influenced_to", - post(handlers::influence::add_influence), - ) - .route( - "/influence/influences/:user_id", - get(handlers::influence::get_user_influences), - ) - .route( - "/influence/mentions/:user_id", - get(handlers::influence::get_user_mentions), - ) - .route( - "/influence/:influenced_to", - delete(handlers::influence::delete_influence), - ) - .route( - "/influence/:influenced_to/map/:beatmap_id", - patch(handlers::influence::add_influence_beatmap), - ) - .route( - "/influence/:influenced_to/map/:beatmap_id", - delete(handlers::influence::remove_influence_beatmap), - ) - .route( - "/influence/:influenced_to/description", - patch(handlers::influence::update_influence_description), - ) - .route( - "/influence/:influenced_to/type/:type_id", - patch(handlers::influence::update_influence_type), - ) - .route("/users/me", get(handlers::user::get_me)) - .route("/users/:user_id", get(handlers::user::get_user)) - .route("/users/bio", patch(handlers::user::update_user_bio)) - .route("/users/map", patch(handlers::user::add_user_beatmap)) - .route( - "/users/map/:beatmap_id", - delete(handlers::user::delete_user_beatmap), - ) - .route( - "/users/influence-order", - post(handlers::user::set_influence_order), - ) - .layer(middleware::from_fn_with_state( - state, - handlers::auth::check_jwt_token, - )) - .route("/activity", get(handlers::activity::get_latest_activities)) - .route("/ws", any(handlers::activity::ws_handler)) - .route( - "/oauth/osu-redirect", - get(handlers::auth::osu_oauth2_redirect), - ) - .route("/oauth/logout", get(handlers::auth::logout)) - .route("/oauth/admin", post(handlers::auth::admin_login)) - .route( - "/leaderboard/user", - get(handlers::leaderboard::get_user_leaderboard), - ) - .route( - "/leaderboard/beatmap", - get(handlers::leaderboard::get_beatmap_leaderboard), - ) - .route("/graph", get(handlers::graph_vizualizer::get_graph_data)) -} - pub async fn init_test_env( label: &str, ) -> (TestServer, Arc, ContainerAsync) { @@ -147,7 +61,10 @@ pub async fn init_test_env( .unwrap(); state.db.upsert_user(test_initial_user).await.unwrap(); - let routes = test_routes(state.clone()).with_state(state); + let routes = routes(state.clone()) + .with_state(state) + .into_make_service_with_connect_info::(); + let test_server = TestServer::new(routes).expect("failed to initialize test server"); (test_server, test_request_client, surrealdb_container) }