Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: pd-controller
- uses: actions/checkout@v4
with:
repository: rustscript-lang/pd-edge
path: pd-edge
- uses: actions/checkout@v4
with:
repository: rustscript-lang/rustscript
path: rustscript
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Format check
working-directory: pd-controller
run: cargo fmt --all -- --check
- name: Clippy
working-directory: pd-controller
run: cargo clippy --workspace --all-targets --all-features
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- name: Tests
working-directory: pd-controller
run: cargo test --workspace
run: cargo test --workspace -- --test-threads=1
- name: Tests with mqtt
run: cargo test --workspace --features mqtt -- --test-threads=1

controller:
name: pd-controller binary (${{ matrix.os }})
Expand All @@ -51,13 +40,10 @@ jobs:
- uses: actions/checkout@v4
with:
path: pd-controller
- uses: actions/checkout@v4
with:
repository: rustscript-lang/pd-edge
path: pd-edge
- uses: actions/checkout@v4
with:
repository: rustscript-lang/rustscript
ref: b1d6cffede77f49410bf63525f30b9a46b02dc01
path: rustscript
- uses: dtolnay/rust-toolchain@stable
- uses: oven-sh/setup-bun@v2
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/publish-crates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ jobs:
uses: actions/checkout@v4
with:
repository: rustscript-lang/rustscript
ref: b1d6cffede77f49410bf63525f30b9a46b02dc01
path: rustscript
- name: Checkout pd-edge dependency
uses: actions/checkout@v4
with:
repository: rustscript-lang/pd-edge
ref: 5f4f889e349bdfbd5534deb42bd13b616a6114f5
path: pd-edge
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
Expand Down Expand Up @@ -105,7 +107,7 @@ jobs:
if section in ('[workspace.package]', '[package]') and stripped.startswith('version = '):
line = re.sub(r'version\s*=\s*"[^"]*"', f'version = "{manifest_version}"', line)
match = dep_re.match(line)
if match and 'path' in match.group(3):
if match and ('path' in match.group(3) or 'git' in match.group(3)):
prefix, key, body, suffix = match.groups()
package_match = re.search(r'package\s*=\s*"([^"]+)"', body)
dep_name = package_match.group(1) if package_match else key
Expand All @@ -118,6 +120,10 @@ jobs:
if body and not body.endswith(','):
body += ','
body += f' version = "{dep_version}"'
body = re.sub(r'\s*,?\s*path\s*=\s*"[^"]*"', '', body)
body = re.sub(r'\s*,?\s*git\s*=\s*"[^"]*"', '', body)
body = re.sub(r'\s*,?\s*rev\s*=\s*"[^"]*"', '', body)
body = body.strip().strip(',')
line = prefix + body + suffix
out.append(line)
path.write_text('\n'.join(out) + '\n')
Expand Down
24 changes: 23 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@ homepage = "https://rustscript.org/"
repository = "https://github.com/rustscript-lang/pd-controller"
build = "build.rs"

[features]
mqtt = ["edge/mqtt"]

[dependencies]
axum = { version = "0.8", features = ["ws"] }
base64 = "0.22"
edge = { package = "pd-edge", path = "../pd-edge", version = "0.1.0" }
edge = { package = "pd-edge", git = "https://github.com/rustscript-lang/pd-edge.git", rev = "5f4f889e349bdfbd5534deb42bd13b616a6114f5", version = "0.1.0" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
uuid = { version = "1", features = ["v4"] }
vm = { package = "pd-vm", path = "../rustscript", version = "0.1.0" }
vm = { package = "pd-vm", git = "https://github.com/rustscript-lang/rustscript.git", rev = "b1d6cffede77f49410bf63525f30b9a46b02dc01", version = "0.1.0" }

[dev-dependencies]
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
2 changes: 1 addition & 1 deletion src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ impl ControllerState {
.and_then(|session_id| guard.get(session_id).map(DebugSessionRecord::to_detail));
(sessions, selected_session)
};
sessions.sort_by(|lhs, rhs| rhs.updated_unix_ms.cmp(&lhs.updated_unix_ms));
sessions.sort_by_key(|lhs| std::cmp::Reverse(lhs.updated_unix_ms));
DebugSessionsStreamSnapshot {
kind: "snapshot",
sessions,
Expand Down
10 changes: 5 additions & 5 deletions src/server/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ pub(super) async fn list_debug_sessions_handler(
.map(DebugSessionRecord::to_summary)
.collect::<Vec<_>>()
};
sessions.sort_by(|lhs, rhs| rhs.updated_unix_ms.cmp(&lhs.updated_unix_ms));
sessions.sort_by_key(|lhs| std::cmp::Reverse(lhs.updated_unix_ms));
Json(DebugSessionListResponse { sessions })
}

Expand Down Expand Up @@ -1065,10 +1065,10 @@ pub(super) async fn run_debug_command_handler(
debug_sessions_changed = true;
}
}
DebugCommandRequest::ClearLine { line } => {
if session.breakpoints.remove(&line) {
debug_sessions_changed = true;
}
DebugCommandRequest::ClearLine { line }
if session.breakpoints.remove(&line) =>
{
debug_sessions_changed = true;
}
_ => {}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/controller_tests/support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub(crate) use pd_controller::{
};
pub(crate) use tokio::task::JoinHandle;
pub(crate) use uuid::Uuid;
pub(crate) use vm::{SourceFlavor, compile_source_with_flavor, decode_program};
pub(crate) use vm::{SourceFlavor, decode_program};

static TEST_STATE_PATH_SEQUENCE: AtomicU64 = AtomicU64::new(0);

Expand Down
79 changes: 75 additions & 4 deletions tests/controller_tests/ui.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,51 @@
use super::support::*;

fn protocol_import_matches(name: &str, root: &str) -> bool {
name.starts_with(&format!("{root}::")) || name.contains(&format!("::{root}::"))
}

fn assert_default_off_protocol_unbound_or_fail_closed(source: &str, root: &str) {
match edge::compile_edge_source_with_flavor(source, SourceFlavor::RustScript) {
Err(err) => {
let message = err.to_string();
assert!(
message.contains("unknown host function") || message.contains(root),
"fail-closed {root} compile error must identify the omitted host, got: {message}"
);
}
Ok(compiled) => {
let schemas = compiled.program.host_import_schemas();
assert_eq!(
schemas.len(),
compiled.program.imports.len(),
"host import schemas must stay aligned with imports"
);
let mut seen = 0usize;
for (import, schema) in compiled.program.imports.iter().zip(schemas.iter()) {
if !protocol_import_matches(&import.name, root) {
continue;
}
seen += 1;
assert!(
schema.is_none(),
"{} must remain unbound (None schema) when {root} is omitted, got {schema:?}",
import.name
);
}
assert!(
seen > 0,
"compiled source must include {root} imports to prove unbound None schemas; imports={:?}",
compiled
.program
.imports
.iter()
.map(|import| import.name.as_str())
.collect::<Vec<_>>()
);
}
}
}

#[tokio::test]
async fn ui_blocks_and_deploy_endpoints_work() {
let (addr, handle, _state) = spawn_controller(ControllerConfig::default()).await;
Expand Down Expand Up @@ -705,7 +751,7 @@ async fn ui_render_extended_value_blocks_work_with_flow_graph() {
rustscript.contains("vm::http::response::set_body(status_plus_len);"),
"expected data edge into flow action, got: {rustscript}"
);
if let Err(err) = compile_source_with_flavor(rustscript, SourceFlavor::RustScript) {
if let Err(err) = edge::compile_edge_source_with_flavor(rustscript, SourceFlavor::RustScript) {
panic!("expected generated rustscript to compile, got: {err}\nsource:\n{rustscript}");
}

Expand Down Expand Up @@ -1135,16 +1181,41 @@ async fn ui_render_extended_abi_blocks_generate_expected_calls() {
assert!(
rustscript.contains("vm::websocket::connection::set_target(ws, \"ws://127.0.0.1:8081\");")
);
assert!(
rustscript.lines().any(|line| line.trim() == "use vm;"),
"UI rustscript must include production `use vm;`, got:\n{rustscript}"
);
assert!(rustscript.contains("let rtc: int = vm::webrtc::connection::new();"));
assert!(rustscript.contains("let udp: int = vm::udp::socket::new();"));
assert!(
rustscript.contains("let proxy_exchange: int = vm::proxy::stream::exchange(exchange);")
);
assert!(rustscript.contains("let upstream_proxy: int = upstream::as_stream();"));
assert!(rustscript.contains("let upstream_all = upstream_response::read_all();"));
if let Err(err) = edge::compile_edge_source_with_flavor(rustscript, SourceFlavor::RustScript) {
panic!("expected rustscript ABI render to compile, got: {err}\nsource:\n{rustscript}");
let without_webrtc = rustscript
.lines()
.filter(|line| !line.contains("webrtc"))
.collect::<Vec<_>>()
.join("\n");
if let Err(err) =
edge::compile_edge_source_with_flavor(&without_webrtc, SourceFlavor::RustScript)
{
panic!(
"expected rustscript ABI render without webrtc to compile, got: {err}\nsource:\n{without_webrtc}"
);
}
let mut webrtc_ui_source = String::from("use vm;\n");
for line in rustscript.lines() {
if line.contains("webrtc") {
webrtc_ui_source.push_str(line.trim());
webrtc_ui_source.push('\n');
}
}
assert!(
webrtc_ui_source.contains("let rtc: int = vm::webrtc::connection::new();"),
"UI rustscript must emit production webrtc shape with `use vm;`, got:\n{rustscript}"
);
assert_default_off_protocol_unbound_or_fail_closed(&webrtc_ui_source, "webrtc");

let javascript = render_json["source"]["javascript"]
.as_str()
Expand Down Expand Up @@ -1487,7 +1558,7 @@ async fn ui_render_plain_if_and_loop_flow() {
rustscript.contains("vm::http::response::set_status(403);"),
"expected if false branch action in rustscript, got: {rustscript}"
);
if let Err(err) = compile_source_with_flavor(rustscript, SourceFlavor::RustScript) {
if let Err(err) = edge::compile_edge_source_with_flavor(rustscript, SourceFlavor::RustScript) {
panic!("expected flow rustscript to compile, got: {err}\nsource:\n{rustscript}");
}

Expand Down
Loading
Loading