Skip to content

Commit

Permalink
remote api: implement rcon
Browse files Browse the repository at this point in the history
  • Loading branch information
Macil committed Mar 18, 2023
1 parent 3b22ca4 commit 6a4bef6
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 6 deletions.
24 changes: 20 additions & 4 deletions rust/src/adapters/actual/game.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::raw_bindings::{cmd_source_t_src_command, svs, Cmd_ExecuteString};
use super::raw_bindings::{cmd_source_t_src_command, svs, Cmd_ExecuteString, Con_Redirect};
use crate::tracing_init;
use once_cell::sync::Lazy;
use std::cell::RefCell;
use std::ffi::CString;
use tokio::sync::mpsc;
use tokio::sync::mpsc::error::{SendError, TryRecvError};
Expand All @@ -12,6 +13,10 @@ static mut FRAME_QUEUE: Lazy<(mpsc::Sender<FrameCallback>, mpsc::Receiver<FrameC
Lazy::new(|| mpsc::channel(200));
static FRAME_QUEUE_TX: Lazy<&mpsc::Sender<FrameCallback>> = Lazy::new(|| unsafe { &FRAME_QUEUE.0 });

thread_local! {
static REDIRECTED_CONSOLE_OUTPUT: RefCell<Vec<String>> = RefCell::default();
}

#[no_mangle]
pub unsafe extern "C" fn Rust_Frame() {
let mut game = Game { _field: () };
Expand Down Expand Up @@ -120,13 +125,24 @@ impl Game {
}
}

#[allow(dead_code)]
pub fn rcon(&mut self, cmd: &str) {
// TODO return output string
// TODO create rcon_tab_autocomplete function that returns a list of possible completions
pub fn rcon(&mut self, cmd: &str) -> String {
unsafe extern "C" fn rcon_redirect(s: *const std::ffi::c_char) {
let s = unsafe { std::ffi::CStr::from_ptr(s) };
REDIRECTED_CONSOLE_OUTPUT.with(|r| {
r.borrow_mut().push(s.to_string_lossy().into_owned());
});
}

assert!(REDIRECTED_CONSOLE_OUTPUT.with(|r| r.borrow().is_empty()));

let cmd = CString::new(cmd).unwrap();
unsafe {
Con_Redirect(Some(rcon_redirect));
Cmd_ExecuteString(cmd.as_ptr(), cmd_source_t_src_command);
Con_Redirect(None);
}
REDIRECTED_CONSOLE_OUTPUT.with(|r| r.take()).concat()
}
}

Expand Down
2 changes: 1 addition & 1 deletion rust/src/adapters/mock/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl Game {

pub fn set_player_health(&mut self, health: f32) {}

pub fn rcon(&mut self, cmd: &str) {
pub fn rcon(&mut self, cmd: &str) -> String {
unimplemented!();
}
}
Expand Down
23 changes: 22 additions & 1 deletion rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use adapters::{
};
use axum::{
extract,
routing::{get, patch},
routing::{get, patch, post},
Json, Router,
};
use axum_helpers::QuakeAPIResponseError;
Expand Down Expand Up @@ -108,6 +108,7 @@ fn create_app(is_unix_socket: bool) -> Router {
let mut app = Router::new()
.route("/", get(root))
.route("/entities", get(entities))
.route("/rcon", post(rcon))
.route("/player", get(player))
.route("/player", patch(patch_player))
.layer(
Expand Down Expand Up @@ -141,6 +142,16 @@ struct PatchPlayerEntity {
health: Option<f32>,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
struct PostRconRequestBody {
command: String,
}

#[derive(Serialize, Debug, Clone, PartialEq)]
struct PostRconResponse {
output: String,
}

async fn player() -> Result<Json<Option<PlayerEntity>>, QuakeAPIResponseError> {
let player_health =
adapters::game::Game::run_in_game_thread_with_result(|game| game.player_health()).await?;
Expand All @@ -164,3 +175,13 @@ async fn patch_player(
async fn entities() -> &'static str {
"TODO all entities in JSON form"
}

async fn rcon(
extract::Json(body): extract::Json<PostRconRequestBody>,
) -> Result<Json<PostRconResponse>, QuakeAPIResponseError> {
let output = adapters::game::Game::run_in_game_thread_mut_with_result(move |game| {
game.rcon(&body.command)
})
.await?;
Ok(Json(PostRconResponse { output }))
}

0 comments on commit 6a4bef6

Please sign in to comment.