Skip to content

Commit b16ec15

Browse files
committed
fix(dashboard): replace self-calling restart logic with standalone endpoint
1 parent d3e1afd commit b16ec15

9 files changed

Lines changed: 95 additions & 117 deletions

File tree

rustmail/src/api/handler/bot/restart.rs

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,31 @@ use tokio::sync::Mutex;
1111
pub async fn handle_restart_bot(
1212
State(bot_state): State<Arc<Mutex<BotState>>>,
1313
) -> (StatusCode, Json<&'static str>) {
14-
let token = {
15-
let state_lock = bot_state.lock().await;
16-
state_lock.internal_token.clone()
17-
};
18-
1914
let state_lock = bot_state.lock().await;
2015

2116
match state_lock.status {
2217
BotStatus::Stopped => {
2318
drop(state_lock);
2419

25-
let result = ping_internal("/api/bot/start", &token).await.map_err(|_| {
26-
(
27-
StatusCode::INTERNAL_SERVER_ERROR,
28-
Json("Failed to restart bot"),
29-
)
30-
});
31-
32-
println!("Restart result: {:?}", result);
33-
34-
(StatusCode::OK, Json("Bot is starting"))
20+
match start_bot(bot_state).await {
21+
StartBotResponse::Success(status, message) => (status, message),
22+
StartBotResponse::Conflict(status, message) => (status, message),
23+
}
3524
}
3625
BotStatus::Running { .. } => {
3726
drop(state_lock);
3827

39-
let _ = ping_internal("/api/bot/stop", &token).await.map_err(|_| {
40-
(
41-
StatusCode::INTERNAL_SERVER_ERROR,
42-
Json("Failed to stop bot"),
43-
)
44-
});
28+
match stop_bot(bot_state.clone()).await {
29+
StopBotResponse::Success(..) => {}
30+
StopBotResponse::Conflict(status, message) => return (status, message),
31+
}
4532

4633
sleep(Duration::from_secs(2)).await;
4734

48-
let _ = ping_internal("/api/bot/start", &token).await.map_err(|_| {
49-
(
50-
StatusCode::INTERNAL_SERVER_ERROR,
51-
Json("Failed to stop bot"),
52-
)
53-
});
35+
match start_bot(bot_state).await {
36+
StartBotResponse::Success(..) => {}
37+
StartBotResponse::Conflict(status, message) => return (status, message),
38+
}
5439

5540
(StatusCode::OK, Json("Bot is restarting"))
5641
}
Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,16 @@
1-
use crate::bot::run_bot;
2-
use crate::prelude::config::*;
1+
use crate::prelude::api::*;
32
use crate::prelude::types::*;
43
use axum::Json;
54
use axum::extract::State;
65
use axum::http::StatusCode;
76
use std::sync::Arc;
8-
use tokio::spawn;
97
use tokio::sync::Mutex;
108

119
pub async fn handle_start_bot(
1210
State(bot_state): State<Arc<Mutex<BotState>>>,
1311
) -> (StatusCode, Json<&'static str>) {
14-
let mut state_lock = bot_state.lock().await;
15-
match state_lock.status {
16-
BotStatus::Stopped => {
17-
state_lock.config = load_config("config.toml");
18-
19-
if state_lock.config.is_none() {
20-
return (StatusCode::BAD_REQUEST, Json("Missing configuration."));
21-
}
22-
23-
let (shutdown_tx, mut shutdown_rx) = tokio::sync::watch::channel(false);
24-
let (command_tx, command_rx) = tokio::sync::mpsc::channel(32);
25-
let bot_state_clone = bot_state.clone();
26-
27-
let handle = spawn(async move {
28-
run_bot(bot_state_clone.clone(), &mut shutdown_rx, command_rx).await;
29-
let mut s = bot_state_clone.lock().await;
30-
s.status = BotStatus::Stopped;
31-
});
32-
state_lock.status = BotStatus::Running {
33-
handle,
34-
shutdown: shutdown_tx,
35-
};
36-
state_lock.command_tx = command_tx;
37-
38-
drop(state_lock);
39-
(StatusCode::OK, Json("Bot is starting"))
40-
}
41-
BotStatus::Running { .. } => (StatusCode::CONFLICT, Json("Bot is already running")),
12+
match start_bot(bot_state).await {
13+
StartBotResponse::Success(status, message) => (status, message),
14+
StartBotResponse::Conflict(status, message) => (status, message),
4215
}
4316
}
Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::prelude::types::*;
2+
use crate::prelude::api::*;
23
use axum::Json;
34
use axum::extract::State;
45
use axum::http::StatusCode;
@@ -8,21 +9,8 @@ use tokio::sync::Mutex;
89
pub async fn handle_stop_bot(
910
State(bot_state): State<Arc<Mutex<BotState>>>,
1011
) -> (StatusCode, Json<&'static str>) {
11-
let handle_and_shutdown = {
12-
let mut state_lock = bot_state.lock().await;
13-
14-
match std::mem::replace(&mut state_lock.status, BotStatus::Stopped) {
15-
BotStatus::Running { handle, shutdown } => Some((handle, shutdown)),
16-
BotStatus::Stopped => None,
17-
}
18-
};
19-
20-
if let Some((handle, shutdown_tx)) = handle_and_shutdown {
21-
let _ = shutdown_tx.send(true);
22-
handle.await.unwrap();
23-
(StatusCode::OK, Json("Bot stopped"))
24-
} else {
25-
println!("Not Starting bot stop");
26-
(StatusCode::CONFLICT, Json("Bot is not running"))
12+
match stop_bot(bot_state).await {
13+
StopBotResponse::Success(status, message) => (status, message),
14+
StopBotResponse::Conflict(status, message) => (status, message),
2715
}
2816
}

rustmail/src/api/middleware/auth.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
use crate::prelude::api::*;
22
use crate::prelude::types::*;
33
use axum::extract::State;
4-
use axum::extract::{ConnectInfo, Request};
4+
use axum::extract::Request;
55
use axum::middleware::Next;
66
use axum::response::{IntoResponse, Response};
77
use axum_extra::extract::CookieJar;
88
use chrono::Utc;
99
use hyper::StatusCode;
1010
use serenity::all::{GuildId, UserId};
1111
use sqlx::{Row, query};
12-
use std::net::SocketAddr;
1312
use std::sync::Arc;
14-
use subtle::ConstantTimeEq;
1513
use tokio::sync::Mutex;
1614

1715
async fn check_user_with_bot(bot_state: Arc<Mutex<BotState>>, user_id: &str) -> bool {
@@ -84,25 +82,10 @@ async fn verify_user(user_id: &str, guild_id: u64, bot_state: Arc<Mutex<BotState
8482

8583
pub async fn auth_middleware(
8684
State(bot_state): State<Arc<Mutex<BotState>>>,
87-
ConnectInfo(addr): ConnectInfo<SocketAddr>,
8885
jar: CookieJar,
8986
req: Request,
9087
next: Next,
9188
) -> Response {
92-
if addr.ip().is_loopback() {
93-
if let Some(h) = req.headers().get("x-internal-call") {
94-
if let Ok(s) = h.to_str() {
95-
let state_lock = bot_state.lock().await;
96-
let expected = state_lock.internal_token.as_bytes();
97-
98-
if expected.ct_eq(s.as_bytes()).unwrap_u8() == 1 {
99-
drop(state_lock);
100-
return next.run(req).await;
101-
}
102-
}
103-
}
104-
}
105-
10689
let session_cookie = jar.get("session_id");
10790

10891
if session_cookie.is_none() {

rustmail/src/api/utils/bot.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use std::sync::Arc;
2+
use axum::http::StatusCode;
3+
use axum::Json;
4+
use tokio::spawn;
5+
use tokio::sync::Mutex;
6+
use crate::bot::run_bot;
7+
use crate::config::load_config;
8+
use crate::types::{BotState, BotStatus};
9+
10+
pub enum StartBotResponse {
11+
Success(StatusCode, Json<&'static str>),
12+
Conflict(StatusCode, Json<&'static str>),
13+
}
14+
15+
pub enum StopBotResponse {
16+
Success(StatusCode, Json<&'static str>),
17+
Conflict(StatusCode, Json<&'static str>),
18+
}
19+
20+
pub async fn start_bot(bot_state: Arc<Mutex<BotState>>) -> StartBotResponse
21+
{
22+
let mut state_lock = bot_state.lock().await;
23+
match state_lock.status {
24+
BotStatus::Stopped => {
25+
state_lock.config = load_config("config.toml");
26+
27+
if state_lock.config.is_none() {
28+
return StartBotResponse::Conflict(StatusCode::BAD_REQUEST, Json("Missing configuration."));
29+
}
30+
31+
let (shutdown_tx, mut shutdown_rx) = tokio::sync::watch::channel(false);
32+
let (command_tx, command_rx) = tokio::sync::mpsc::channel(32);
33+
let bot_state_clone = bot_state.clone();
34+
35+
let handle = spawn(async move {
36+
run_bot(bot_state_clone.clone(), &mut shutdown_rx, command_rx).await;
37+
let mut s = bot_state_clone.lock().await;
38+
s.status = BotStatus::Stopped;
39+
});
40+
state_lock.status = BotStatus::Running {
41+
handle,
42+
shutdown: shutdown_tx,
43+
};
44+
state_lock.command_tx = command_tx;
45+
46+
drop(state_lock);
47+
StartBotResponse::Success(StatusCode::OK, Json("Bot is starting"))
48+
}
49+
BotStatus::Running { .. } => StartBotResponse::Conflict(StatusCode::BAD_REQUEST, Json("Bot is already running")),
50+
}
51+
}
52+
53+
pub async fn stop_bot(bot_state: Arc<Mutex<BotState>>) -> StopBotResponse {
54+
let handle_and_shutdown = {
55+
let mut state_lock = bot_state.lock().await;
56+
57+
match std::mem::replace(&mut state_lock.status, BotStatus::Stopped) {
58+
BotStatus::Running { handle, shutdown } => Some((handle, shutdown)),
59+
BotStatus::Stopped => None,
60+
}
61+
};
62+
63+
if let Some((handle, shutdown_tx)) = handle_and_shutdown {
64+
let _ = shutdown_tx.send(true);
65+
handle.await.unwrap();
66+
StopBotResponse::Success(StatusCode::OK, Json("Bot stopped"))
67+
} else {
68+
println!("Not Starting bot stop");
69+
StopBotResponse::Conflict(StatusCode::CONFLICT, Json("Bot is not running"))
70+
}
71+
}

rustmail/src/api/utils/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
pub mod get_user_id_from_session;
22
pub mod permissions_cache;
3-
pub mod ping_internal;
43
pub mod user_permissions;
4+
pub mod bot;
55

66
pub use get_user_id_from_session::*;
77
pub use permissions_cache::*;
8-
pub use ping_internal::*;
98
pub use user_permissions::*;
9+
pub use bot::*;

rustmail/src/api/utils/ping_internal.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.

rustmail/src/bot.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ use crate::prelude::errors::*;
55
use crate::prelude::handlers::*;
66
use crate::prelude::panel_commands::*;
77
use crate::prelude::types::*;
8-
use base64::Engine;
9-
use rand::RngCore;
108
use serenity::all::{ClientBuilder, GatewayIntents, ShardManager};
119
use serenity::cache::Settings as CacheSettings;
1210
use serenity::prelude::TypeMapKey;
@@ -24,13 +22,9 @@ impl TypeMapKey for ShardManagerKey {
2422
}
2523

2624
pub async fn init_bot_state() -> Arc<Mutex<BotState>> {
27-
let pool = init_database().await.expect("An error occured!");
25+
let pool = init_database().await.expect("An error occurred!");
2826
println!("Database connected!");
2927

30-
let mut bytes = [0u8; 32];
31-
rand::rng().fill_bytes(&mut bytes);
32-
let token = base64::engine::general_purpose::STANDARD.encode(&bytes);
33-
3428
let config = load_config("config.toml");
3529

3630
let (command_tx, _command_rx) = tokio::sync::mpsc::channel(32);
@@ -41,7 +35,6 @@ pub async fn init_bot_state() -> Arc<Mutex<BotState>> {
4135
db_pool: Some(pool),
4236
command_tx: command_tx.clone(),
4337
bot_http: None,
44-
internal_token: token,
4538
};
4639

4740
Arc::new(Mutex::new(bot_state))

rustmail/src/types/bot.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,4 @@ pub struct BotState {
2525
pub db_pool: Option<sqlx::SqlitePool>,
2626
pub command_tx: tokio::sync::mpsc::Sender<BotCommand>,
2727
pub bot_http: Option<Arc<Http>>,
28-
pub internal_token: String,
2928
}

0 commit comments

Comments
 (0)