Fix broken v2 bambulab schema refs, wire up v2 dispatchers, fix PrintJobStatus JSON mismatch
- v2/common/device/device.schema.json: stray backtick in bed $ref broke resolution - v2/report/print/print.schema.json: ams $ref pointed at wrong path (missing ams/ subdir) - v2/common/device/plate.schema.json: $id was copy-pasted from bed.schema.json - Add v2/request.schema.json and v2/report.schema.json dispatchers - v2's leaf schemas were unreachable without them, same oneOf convention as v1 - Rewrite schemas/bambulab/README.md layout section, which still described v1's pre-rename paths and claimed v2 was removed - PrintJob.status serialized as a raw i32 in Rust (prost stores proto3 enums as i32) while ts-types' TypeBox schema validates full enum name strings - add serde with= on the field so Rust JSON matches TS and protobuf's own canonical JSON enum mapping, plus a regression test
This commit is contained in:
@@ -13,3 +13,6 @@ serde = { version = "1", features = ["derive"] }
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = "0.13"
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1"
|
||||
|
||||
@@ -21,6 +21,17 @@ fn main() {
|
||||
config.type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]");
|
||||
config.type_attribute(".", "#[serde(rename_all = \"camelCase\")]");
|
||||
|
||||
// prost stores proto3 enums as plain `i32` fields (not the generated
|
||||
// enum type), so the blanket type_attribute above never actually runs
|
||||
// for `status` - it'd serialize as a bare number, disagreeing with
|
||||
// TypeBox's full-name string literals in ts-types. Route the field
|
||||
// through PrintJobStatus's own as_str_name()/from_str_name() instead,
|
||||
// matching protobuf's own canonical JSON enum representation.
|
||||
config.field_attribute(
|
||||
".continuum.v1.PrintJob.status",
|
||||
"#[serde(with = \"crate::print_job_status_serde\")]",
|
||||
);
|
||||
|
||||
config
|
||||
.compile_protos(&proto_files, &[proto_root])
|
||||
.expect("failed to compile continuum .proto sources");
|
||||
|
||||
@@ -8,6 +8,27 @@ pub use continuum::v1::{
|
||||
MaterialProfile, PrintJob, PrintJobStatus, PrintParameters, Template,
|
||||
};
|
||||
|
||||
// PrintJob.status is generated as a plain i32 (see build.rs's comment) -
|
||||
// (de)serialize it via PrintJobStatus's full proto name strings
|
||||
// (e.g. "PRINT_JOB_STATUS_QUEUED") so Rust's JSON matches ts-types'
|
||||
// TypeBox schema and protobuf's own canonical JSON enum mapping.
|
||||
mod print_job_status_serde {
|
||||
use super::PrintJobStatus;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
pub fn serialize<S: Serializer>(value: &i32, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let status = PrintJobStatus::try_from(*value).unwrap_or(PrintJobStatus::Unspecified);
|
||||
status.as_str_name().serialize(serializer)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<i32, D::Error> {
|
||||
let name = String::deserialize(deserializer)?;
|
||||
PrintJobStatus::from_str_name(&name)
|
||||
.map(|status| status as i32)
|
||||
.ok_or_else(|| serde::de::Error::custom(format!("unknown PrintJobStatus: {name}")))
|
||||
}
|
||||
}
|
||||
|
||||
// Bambu's raw MQTT command/report structs are NOT modeled here - they're
|
||||
// plain hand-written Rust + serde in continuum-proxy's
|
||||
// src/printer/bambu_commands/, not proto. That data is JSON-over-MQTT
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
use continuum_types::{PrintJob, PrintJobStatus};
|
||||
|
||||
fn sample(status: PrintJobStatus) -> PrintJob {
|
||||
PrintJob {
|
||||
id: "job-1".into(),
|
||||
farm_id: "farm-1".into(),
|
||||
printer_id: "printer-1".into(),
|
||||
template_id: "template-1".into(),
|
||||
status: status as i32,
|
||||
progress_percent: 50.0,
|
||||
started_at_unix: 0,
|
||||
completed_at_unix: 0,
|
||||
gcode_file_key: "key".into(),
|
||||
}
|
||||
}
|
||||
|
||||
// Regression test: PrintJob.status must serialize as the full proto enum
|
||||
// name (matching ts-types' TypeBox schema), not the raw i32 prost stores
|
||||
// it as internally.
|
||||
#[test]
|
||||
fn status_serializes_as_full_proto_enum_name() {
|
||||
let json = serde_json::to_value(sample(PrintJobStatus::Printing)).unwrap();
|
||||
assert_eq!(json["status"], "PRINT_JOB_STATUS_PRINTING");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn status_round_trips_through_json() {
|
||||
let original = sample(PrintJobStatus::Completed);
|
||||
let json = serde_json::to_string(&original).unwrap();
|
||||
let restored: PrintJob = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(restored.status, PrintJobStatus::Completed as i32);
|
||||
}
|
||||
+42
-12
@@ -11,7 +11,8 @@ any Rust to do it.
|
||||
|
||||
```
|
||||
bambulab/
|
||||
envelope.schema.json the base - sequence_id + command, shared by
|
||||
common/
|
||||
envelope.schema.json the base - sequence_id + command, shared by
|
||||
every command in every generation, so it lives
|
||||
here unversioned, not duplicated under v1/v2
|
||||
v1/
|
||||
@@ -19,6 +20,18 @@ bambulab/
|
||||
("info", "pushing", ...), each a oneOf (a
|
||||
category can have more than one request shape)
|
||||
report.schema.json BambuReport dispatcher, same idea
|
||||
common/ shapes shared across v1's request/ and report/
|
||||
ams/
|
||||
ams.schema.json
|
||||
ams_unit.schema.json
|
||||
ams_tray.schema.json
|
||||
vt_tray.schema.json shared base for AmsTray + the virtual/
|
||||
external spool slot, via allOf + $ref
|
||||
module_info.schema.json
|
||||
hms.schema.json, net.schema.json, online.schema.json,
|
||||
upload.schema.json, upgrade_state.schema.json, xcam.schema.json,
|
||||
ipcam.schema.json, lights_report.schema.json, nozzle_type.schema.json,
|
||||
nozzle_diameter.schema.json
|
||||
request/
|
||||
info/
|
||||
get_version.schema.json
|
||||
@@ -27,21 +40,38 @@ bambulab/
|
||||
report/
|
||||
info/
|
||||
get_version.schema.json
|
||||
_module_info.schema.json
|
||||
print/
|
||||
print.schema.json the ongoing print-state push
|
||||
_ams.schema.json
|
||||
_ams_unit.schema.json
|
||||
_ams_tray.schema.json
|
||||
_vt_tray.schema.json shared base for AmsTray + the virtual/
|
||||
external spool slot, via allOf + $ref
|
||||
_upgrade_state.schema.json
|
||||
_xcam.schema.json
|
||||
v2/ add the same split once V2's wire format is
|
||||
known to differ from V1's - removed for now
|
||||
rather than leave broken copy-pasted stubs
|
||||
v2/ same split as v1, once the wire format actually
|
||||
diverges per field - built out below as that's
|
||||
been confirmed, not copy-pasted speculatively
|
||||
request.schema.json dispatcher, same shape as v1's
|
||||
report.schema.json dispatcher, same shape as v1's
|
||||
common/ v2 grew a much larger shared shape set than v1
|
||||
(device/, job/, care, info, ...) because more
|
||||
of the wire format has been captured/confirmed
|
||||
ams/, device/, job/, and the same flat common/*.schema.json files
|
||||
as v1 (hms, net, online, upload, upgrade_state, xcam, ipcam,
|
||||
lights_report, nozzle_type, nozzle_diameter, vt_tray)
|
||||
request/
|
||||
info/
|
||||
get_version.schema.json
|
||||
report/
|
||||
info/
|
||||
get_version.schema.json
|
||||
_module_info.schema.json
|
||||
print/
|
||||
print.schema.json the ongoing print-state push (command
|
||||
"push_status")
|
||||
_2d_report.schema.json, _3d_report.schema.json,
|
||||
_nozzle_type.schema.json
|
||||
```
|
||||
|
||||
Add a category to a dispatcher (`v1|v2/request.schema.json` or
|
||||
`report.schema.json`) whenever a new `request/<category>/` or
|
||||
`report/<category>/` schema is added on disk - an unwired leaf schema is
|
||||
unreachable from validation even though it parses fine on its own.
|
||||
|
||||
**One real correction baked into this layout**: the report category for
|
||||
whatever a `pushall` request triggers is `report/print/`, not
|
||||
`report/pushing/`. Sending `pushall` (which *does* go to the `pushing` key
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"airduct": { "$ref": "./airduct.schema.json" },
|
||||
"bed": { "$ref": "./bed.schema.json`" },
|
||||
"bed": { "$ref": "./bed.schema.json" },
|
||||
"cam": { "$ref": "./cam.schema.json" },
|
||||
"ctc": { "$ref": "./ctc.schema.json" },
|
||||
"ext_tool": { "$ref": "./ext_tool.schema.json" },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.octoturge.com/Continuum/continuum-schemas/raw/branch/main/schemas/bambulab/v2/common/device/bed.schema.json",
|
||||
"$id": "https://git.octoturge.com/Continuum/continuum-schemas/raw/branch/main/schemas/bambulab/v2/common/device/plate.schema.json",
|
||||
"title": "DevicePlate",
|
||||
"description": "Detailed info about Plate",
|
||||
"type": "object",
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.octoturge.com/Continuum/continuum-schemas/raw/branch/main/schemas/bambulab/v2/report.schema.json",
|
||||
"title": "BambuReportV2",
|
||||
"description": "V2 equivalent of v1/report.schema.json - same 'what root key does this arrive under' convention (see v1/report.schema.json for the print-vs-pushing rationale). Only wires categories that actually have a v2 schema on disk; add a property here when a new v2/report/<category>/ schema is added.",
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"maxProperties": 1,
|
||||
"properties": {
|
||||
"info": {
|
||||
"oneOf": [
|
||||
{ "$ref": "report/info/get_version.schema.json" }
|
||||
]
|
||||
},
|
||||
"print": {
|
||||
"oneOf": [
|
||||
{ "$ref": "report/print/print.schema.json" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
"2D": { "$ref": "./_2d_report.schema.json" },
|
||||
"3D": { "$ref": "./_3d_report.schema.json" },
|
||||
"ams": { "$ref": "../../common/ams.schema.json" },
|
||||
"ams": { "$ref": "../../common/ams/ams.schema.json" },
|
||||
"hms": { "$ref": "../../common/hms.schema.json" },
|
||||
"lights_report": { "$ref": "../../common/lights_report.schema.json" },
|
||||
"upgrade_state": { "$ref": "../../common/upgrade_state.schema.json" },
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.octoturge.com/Continuum/continuum-schemas/raw/branch/main/schemas/bambulab/v2/request.schema.json",
|
||||
"title": "BambuRequestV2",
|
||||
"description": "V2 equivalent of v1/request.schema.json - one JSON key naming the category, each a oneOf to leave room for more than one request shape per category. Only wires categories that actually have a v2 schema on disk; add a property here when a new v2/request/<category>/ schema is added.",
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"maxProperties": 1,
|
||||
"properties": {
|
||||
"info": {
|
||||
"oneOf": [
|
||||
{ "$ref": "request/info/get_version.schema.json" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
Reference in New Issue
Block a user