Skip to content

Commit 03aee07

Browse files
Merge pull request #118 from j-mie6/dev
Merge breakpoint interactivity to main
2 parents f66ba17 + d45e0e0 commit 03aee07

29 files changed

+249
-52
lines changed

backend/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "dill"
3-
version = "0.3.0"
3+
version = "0.4.0"
44
description = "A cross-platform debugging UI for `parsley-debug`"
55
authors = ["Jamie Willis (@j-mie6)", "Josh Walker (@josh-ja-walker)", "Aniket Gupta (@aniket1101)", "Priyansh Chugh (@PriyanshC)", "Alejandro Perez Fadon (@Aito0)", "Riley Horrix (@Riley-horrix)", "Adam Watson (@AdamW1087)"]
66
license = "BSD 3-Clause"

backend/src/commands.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod fetch;
22
mod save;
3+
mod breakpoint;
34

45
/* Expose command handlers for Tauri setup */
56
pub fn handlers() -> impl Fn(tauri::ipc::Invoke) -> bool {
@@ -9,6 +10,7 @@ pub fn handlers() -> impl Fn(tauri::ipc::Invoke) -> bool {
910
save::save_tree,
1011
save::fetch_saved_tree_names,
1112
save::load_saved_tree,
12-
save::delete_tree
13+
save::delete_tree,
14+
breakpoint::skip_breakpoints,
1315
]
1416
}

backend/src/commands/breakpoint.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use crate::state::{StateError, StateManager};
2+
use crate::AppState;
3+
4+
#[tauri::command]
5+
pub fn skip_breakpoints(state: tauri::State<'_, AppState>, skips: i32) -> Result<(), SkipBreakpointError> {
6+
state.transmit_breakpoint_skips(skips).map_err(SkipBreakpointError::from)
7+
}
8+
9+
#[derive(Debug, serde::Serialize)]
10+
pub enum SkipBreakpointError {
11+
ChannelError,
12+
}
13+
14+
impl From<StateError> for SkipBreakpointError {
15+
fn from(err: StateError) -> Self {
16+
match err {
17+
StateError::ChannelError => Self::ChannelError,
18+
_ => panic!("Unexpected error on skip_breakpoints"),
19+
}
20+
}
21+
}

backend/src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use tauri::Manager;
22
use tauri::RunEvent;
33

4+
use rocket::tokio::sync::{Mutex, mpsc};
5+
6+
mod server;
47
mod state;
58
mod commands;
69
mod events;
710
mod trees;
8-
mod server;
911
mod files;
1012

1113
use state::AppState;
@@ -22,14 +24,16 @@ fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
2224
)?;
2325
}
2426

27+
let (tx, rx): (state::SkipsSender, server::SkipsReceiver) = mpsc::channel::<i32>(1);
28+
2529
/* Manage the app state using Tauri */
26-
let app_state: AppState = AppState::new(app.app_handle().clone());
30+
let app_state: AppState = AppState::new(app.app_handle().clone(), Mutex::new(tx));
2731
app.manage(app_state);
2832

2933
files::create_saved_trees_dir().expect("Error occured while making saved_trees folder");
3034

3135
/* Clone the app handle and use to create a ServerState */
32-
let server_state: ServerState = ServerState::new(app.handle().clone());
36+
let server_state: ServerState = ServerState::new(app.handle().clone(), Mutex::new(rx));
3337

3438
/* Mount the Rocket server to the running instance of Tauri */
3539
tauri::async_runtime::spawn(async move {

backend/src/server.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ mod request;
33
mod server_state;
44

55
pub use launch::launch;
6-
pub use server_state::ServerState;
6+
pub use server_state::{ServerState, SkipsReceiver};
7+
8+
pub type TokioMutex<T> = rocket::tokio::sync::Mutex<T>;
79

810
#[cfg(test)]
911
pub mod test {
1012

1113
use mockall::predicate;
1214
use rocket::{http, local::blocking};
15+
use rocket::tokio::sync::mpsc;
1316

1417
use super::{launch, ServerState};
1518
use crate::events::Event;
@@ -22,10 +25,16 @@ pub mod test {
2225
/* Start a blocking, tracked client for rocket
2326
The mock should already be set with expectations */
2427
pub fn tracked_client(mock: MockStateManager) -> blocking::Client {
25-
let state = ServerState::new(mock);
28+
let rx = empty_channel::<i32>();
29+
let state = ServerState::new(mock, super::TokioMutex::new(rx));
2630
blocking::Client::tracked(launch::build(state)).expect("Could not launch rocket")
2731
}
2832

33+
pub fn empty_channel<T>() -> mpsc::Receiver<T> {
34+
let (_, rx) = mpsc::channel::<T>(1);
35+
rx
36+
}
37+
2938
#[test]
3039
fn server_handles_many_requests() {
3140
const NUM_REPEATS: usize = 1000;

backend/src/server/launch.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ mod test {
4242
#[test]
4343
fn rocket_client_launches_successfully() {
4444
let mock = MockStateManager::new();
45-
let state = ServerState::new(mock);
45+
let rx = server::test::empty_channel::<i32>();
46+
let state = ServerState::new(mock, rocket::tokio::sync::Mutex::new(rx));
4647

4748
let rocket: Rocket<Build> = super::build(state);
4849

backend/src/server/request.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,28 @@ pub fn routes() -> Vec<rocket::Route> {
1313
rocket::routes![get_index, get_tree, post_tree]
1414
}
1515

16+
#[derive(Debug, serde::Serialize)]
17+
struct PostTreeResponse {
18+
message: String,
19+
#[serde(skip_serializing_if = "Option::is_none")] skip_breakpoint: Option<i32>,
20+
}
21+
22+
impl PostTreeResponse {
23+
fn new(msg: impl Into<String>, skips: i32) -> Json<PostTreeResponse> {
24+
Json(PostTreeResponse {
25+
message: msg.into(),
26+
skip_breakpoint: Some(skips),
27+
})
28+
}
29+
30+
fn no_skips(msg: impl Into<String>) -> Json<PostTreeResponse> {
31+
Json(PostTreeResponse {
32+
message: msg.into(),
33+
skip_breakpoint: None,
34+
})
35+
}
36+
}
37+
1638
/* Placeholder GET request handler to print 'Hello world!' */
1739
#[get("/")]
1840
fn get_index() -> String {
@@ -21,14 +43,15 @@ fn get_index() -> String {
2143

2244
/* Post request handler to accept debug tree */
2345
#[post("/api/remote/tree", format = "application/json", data = "<data>")]
24-
fn post_tree(data: Json<ParsleyTree>, state: &rocket::State<ServerState>) -> (http::Status, String) {
46+
async fn post_tree(data: Json<ParsleyTree>, state: &rocket::State<ServerState>) -> (http::Status, Json<PostTreeResponse>) {
2547
/* Deserialise and unwrap json data */
2648
let parsley_tree: ParsleyTree = data.into_inner();
49+
let is_debugging: bool = parsley_tree.is_debugging();
2750
let debug_tree: DebugTree = parsley_tree.into();
2851

2952
/* Format informative response for RemoteView */
3053
let input: &str = debug_tree.get_input();
31-
let response: String = format!(
54+
let message: String = format!(
3255
"Posted parser tree handling input: \"{}{}\" to Dill",
3356
/* Include first few chars of input */
3457
&input[..std::cmp::min(input.len(), RESPONSE_INPUT_LEN)],
@@ -41,13 +64,23 @@ fn post_tree(data: Json<ParsleyTree>, state: &rocket::State<ServerState>) -> (ht
4164

4265
/* Update state with new debug_tree and return response */
4366
match state.set_tree(debug_tree).and(state.emit(Event::NewTree)) {
44-
Ok(()) => (http::Status::Ok, response),
45-
46-
Err(StateError::EventEmitFailed) =>
47-
(http::Status::InternalServerError, String::from("New Tree event could not be emitted - try again")),
67+
Ok(()) => {
68+
if !is_debugging {
69+
return (http::Status::Ok, PostTreeResponse::no_skips(message))
70+
};
71+
72+
match state.receive_breakpoint_skips().await {
73+
Some(skips) => (http::Status::Ok, PostTreeResponse::new(message, skips)),
74+
None => (http::Status::InternalServerError, PostTreeResponse::no_skips(message)),
75+
}
4876

77+
},
78+
4979
Err(StateError::LockFailed) =>
50-
(http::Status::InternalServerError, String::from("Locking state mutex failed - try again")),
80+
(http::Status::InternalServerError, PostTreeResponse::no_skips("Locking state mutex failed - try again")),
81+
82+
Err(StateError::ChannelError) =>
83+
(http::Status::InternalServerError, PostTreeResponse::no_skips("Failed to receive value from channel - try again")),
5184

5285
Err(_) => panic!("Unexpected error on post_tree"),
5386
}
@@ -64,6 +97,7 @@ fn get_tree(state: &rocket::State<ServerState>) -> String {
6497
}
6598
}
6699

100+
67101
#[cfg(test)]
68102
pub mod test {
69103

backend/src/server/server_state.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ use crate::events::Event;
22
use crate::state::{StateError, StateManager};
33
use crate::trees::{DebugTree, DebugNode};
44

5+
use super::TokioMutex;
6+
7+
pub type SkipsReceiver = rocket::tokio::sync::mpsc::Receiver<i32>;
8+
59

610
/* Wrapper for StateManager implementation used for Rocket server state management */
7-
pub struct ServerState(Box<dyn StateManager>);
11+
pub struct ServerState(Box<dyn StateManager>, TokioMutex<SkipsReceiver>);
812

913
impl ServerState {
10-
pub fn new<S: StateManager>(state: S) -> Self {
11-
ServerState(Box::new(state))
14+
pub fn new<S: StateManager>(state: S, rx: TokioMutex<SkipsReceiver>) -> Self {
15+
ServerState(Box::new(state), rx)
1216
}
1317

1418
/* Get wrapped StateManager implementation */
@@ -34,4 +38,14 @@ impl StateManager for ServerState {
3438
fn emit<'a>(&self, event: Event<'a>) -> Result<(), StateError> {
3539
self.inner().emit(event)
3640
}
41+
42+
fn transmit_breakpoint_skips(&self, skips: i32) -> Result<(),StateError> {
43+
self.0.as_ref().transmit_breakpoint_skips(skips)
44+
}
45+
}
46+
47+
impl ServerState {
48+
pub async fn receive_breakpoint_skips(&self) -> Option<i32> {
49+
self.1.lock().await.recv().await
50+
}
3751
}

backend/src/state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ mod app_state;
22
mod state_manager;
33
mod app_handle;
44

5-
pub use app_state::AppState;
5+
pub use app_state::{AppState, SkipsSender};
66
pub use app_handle::AppHandle;
77

88
pub use state_manager::{StateManager, StateError};

0 commit comments

Comments
 (0)