printobserver_sdk/contract.rs
1//! Generated by `contract-codegen` from the checked-in contract schemas.
2//!
3//! This file is the Rust client's request and response types.
4//!
5//! Do not edit by hand: change the contracts, regenerate with `just
6//! generate-clients`, and commit what that writes.
7
8use std::collections::BTreeMap;
9
10use serde::{Deserialize, Serialize};
11
12use crate::{Client, ClientError};
13
14/// The version of the server contract these types were generated from: the
15/// version of the workspace this crate is compiled from. A published crate
16/// reports the release version it was built at, and a crate compiled from a
17/// checkout reports that checkout's workspace version.
18pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
19
20/// Every operation this client exposes a method for, which is every operation
21/// the server declares and no other.
22pub const OPERATION_NAMES: [&str; 27] = [
23 "prints",
24 "status",
25 "context",
26 "image",
27 "history",
28 "manifest_get",
29 "look",
30 "manifest_set",
31 "spools",
32 "spool",
33 "printer_history",
34 "preflight",
35 "pause",
36 "resume",
37 "cancel",
38 "start_print",
39 "set_feedrate_factor",
40 "set_flowrate_factor",
41 "set_tool_target_c",
42 "set_bed_target_c",
43 "set_fan_percent",
44 "acknowledge_failure",
45 "register_spool",
46 "load_spool",
47 "unload_spool",
48 "adjust_spool",
49 "retire_spool",
50];
51
52/// What an operator's acknowledgement of a failure event asks for next.
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
54pub enum AcknowledgementDisposition {
55 /// Carry on printing.
56 #[serde(rename = "continue")]
57 Continue,
58 /// Carry on printing, watched more closely.
59 #[serde(rename = "watch")]
60 Watch,
61 /// The print should stop. Recorded for whoever may cancel it: the
62 /// acknowledgement itself asks nothing of the machine.
63 #[serde(rename = "stop")]
64 Stop,
65}
66
67/// What one mutating request left behind it.
68#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
69pub struct ActionAnswer {
70 /// The bounded intervention it opened, when it opened one.
71 #[serde(default, skip_serializing_if = "Option::is_none")]
72 pub intervention: Option<Intervention>,
73 /// What the printer said, when the request reached it and it refused.
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub printer_refusal: Option<String>,
76 /// The record of the request and the decision taken on it. A rejected
77 /// request's rejection is here, carrying its reason, the value asked for
78 /// and the range allowed, so a caller can ask again inside the range.
79 pub record: ActionRecord,
80}
81
82/// An accepted action reached the printer.
83#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
84pub struct ActionExecutedPayload {
85 /// The action's identifier.
86 pub action_id: ActionId,
87 /// The bounded intervention it opened, when it opened one.
88 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub intervention_id: Option<InterventionId>,
90}
91
92/// A lowercase hyphenated version 7 UUID identifying one requested action.
93pub type ActionId = String;
94
95/// One action of the closed vocabulary, named without its payload.
96///
97/// This is what a safety envelope grants and what a policy rejection names;
98/// the
99/// payload lives on `PrintAction` itself.
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
101pub enum ActionKind {
102 /// Pause the print.
103 #[serde(rename = "pause")]
104 Pause,
105 /// Resume the print.
106 #[serde(rename = "resume")]
107 Resume,
108 /// Cancel the print.
109 #[serde(rename = "cancel")]
110 Cancel,
111 /// Start a print of a named file.
112 #[serde(rename = "start_print")]
113 StartPrint,
114 /// Set the feedrate factor.
115 #[serde(rename = "set_feedrate_factor")]
116 SetFeedrateFactor,
117 /// Set the flowrate factor.
118 #[serde(rename = "set_flowrate_factor")]
119 SetFlowrateFactor,
120 /// Set a tool's target temperature.
121 #[serde(rename = "set_tool_target_c")]
122 SetToolTargetC,
123 /// Set the bed's target temperature.
124 #[serde(rename = "set_bed_target_c")]
125 SetBedTargetC,
126 /// Set the fan percentage.
127 #[serde(rename = "set_fan_percent")]
128 SetFanPercent,
129 /// Acknowledge a failure event.
130 #[serde(rename = "acknowledge_failure")]
131 AcknowledgeFailure,
132 /// Register a spool.
133 #[serde(rename = "register_spool")]
134 RegisterSpool,
135 /// Load a spool onto a tool.
136 #[serde(rename = "load_spool")]
137 LoadSpool,
138 /// Unload a spool from its tool.
139 #[serde(rename = "unload_spool")]
140 UnloadSpool,
141 /// Correct a spool's remaining figure.
142 #[serde(rename = "adjust_spool")]
143 AdjustSpool,
144 /// Retire a spool.
145 #[serde(rename = "retire_spool")]
146 RetireSpool,
147}
148
149/// One request, the decision taken on it, and what became of it.
150///
151/// `executed_at` and `outcome` are both optional and are absent together: a
152/// record is written when the decision is taken, which is before — and, for a
153/// rejected request, instead of — anything reaching the printer.
154#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
155pub struct ActionRecord {
156 /// The decision policy took on it.
157 pub decision: PolicyDecision,
158 /// When it reached the printer, if it did.
159 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub executed_at: Option<Timestamp>,
161 /// This record's identifier, minted by the store.
162 pub id: ActionId,
163 /// What the printer made of it, if it reached the printer.
164 #[serde(default, skip_serializing_if = "Option::is_none")]
165 pub outcome: Option<ExecutionOutcome>,
166 /// The print this request was made against.
167 pub print_id: PrintId,
168 /// The request itself.
169 pub request: ActionRequest,
170}
171
172/// Policy refused an action.
173#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
174pub struct ActionRejectedPayload {
175 /// The action's identifier.
176 pub action_id: ActionId,
177 /// The whole decision, carrying which rejection it was.
178 pub decision: PolicyDecision,
179}
180
181/// One request an actor made, at the instant it made it.
182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
183pub struct ActionRequest {
184 /// What was asked for.
185 pub action: PrintAction,
186 /// Who asked.
187 pub actor: Actor,
188 /// When they asked.
189 pub requested_at: Timestamp,
190}
191
192/// An actor asked for an action.
193#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
194pub struct ActionRequestedPayload {
195 /// What was asked for.
196 pub action: PrintAction,
197 /// The action's identifier.
198 pub action_id: ActionId,
199 /// Who asked.
200 pub actor: Actor,
201}
202
203/// Who asked for something.
204#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
205pub enum Actor {
206 /// The supervising agent, naming its session.
207 #[serde(rename = "agent")]
208 Agent {
209 /// The supervision session the agent is acting in.
210 session_name: String,
211 },
212 /// A person.
213 #[serde(rename = "operator")]
214 Operator,
215 /// The supervisor itself.
216 #[serde(rename = "system")]
217 System,
218}
219
220/// An actor class, which is what a safety envelope grants actions to.
221#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
222pub enum ActorClass {
223 /// The supervising agent.
224 #[serde(rename = "agent")]
225 Agent,
226 /// A person.
227 #[serde(rename = "operator")]
228 Operator,
229 /// The supervisor itself.
230 #[serde(rename = "system")]
231 System,
232}
233
234/// One thing an adjustment may change.
235pub type Adjustable = String;
236
237/// The agent's written record of one supervision turn.
238///
239/// This is deliberately not how the agent acts: acting is a
240/// `PrintAction` that policy rules on.
241#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
242pub struct AgentAssessment {
243 /// How sure the agent is.
244 pub confidence: Confidence,
245 /// What the agent did.
246 pub did: String,
247 /// Whether the agent is escalating to a person.
248 pub escalating: bool,
249 /// Whether the print should carry on.
250 pub should_continue: bool,
251 /// One line saying what is happening.
252 pub summary: String,
253 /// Why it did it.
254 pub why: String,
255}
256
257/// The agent wrote down what it made of a turn.
258#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
259pub struct AgentAssessmentPayload {
260 /// What the agent answered with.
261 pub assessment: AgentAssessment,
262 /// The session the turn ran in.
263 pub session_name: String,
264}
265
266/// Somebody took a fresh look at the print.
267///
268/// Written down before the camera is asked for a frame, so that a frame the
269/// camera would not give is recorded against a look that is already in the
270/// history; the frame itself, when there is one, is this event's image.
271#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
272pub struct CameraLookPayload {
273 /// The events for the print that arrived while it waited, and that it
274 /// handed to whoever looked, oldest first.
275 #[serde(default, skip_serializing_if = "Option::is_none")]
276 pub delivered: Option<Vec<EventId>>,
277 /// How long the look waited for something to happen before it was taken,
278 /// in whole seconds.
279 pub waited_s: i64,
280}
281
282/// The durable identity of one debit, so that a replay can never debit twice.
283#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
284#[serde(tag = "key")]
285pub enum ChargeKey {
286 /// One segment of a print this system watched, on one tool.
287 #[serde(rename = "print")]
288 Print {
289 /// The print.
290 print_id: PrintId,
291 /// Which segment: zero from the print's start, and one more each time
292 /// a mid-print swap or a filament-change signal closes the current
293 /// one.
294 segment: i64,
295 /// The tool, in the printer's own numbering.
296 tool: i64,
297 },
298 /// One print this system never saw, on one tool.
299 #[serde(rename = "unobserved")]
300 Unobserved {
301 /// The file that was printed.
302 file_name: String,
303 /// The file's tally generation, which advances each time the
304 /// printer's
305 /// tally for the file is reset.
306 generation: i64,
307 /// Where the file lives, in the printer's own vocabulary.
308 origin: String,
309 /// The print's ordinal in the file's tally — completed and failed
310 /// prints counted up to and including this one — within that
311 /// generation.
312 print_number: i64,
313 /// The tool, in the printer's own numbering.
314 tool: i64,
315 },
316}
317
318/// How the length a charge debits was worked out.
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
320pub enum ChargeMethod {
321 /// A completed print: the length the file's analysis gives.
322 #[serde(rename = "slicer_estimate")]
323 SlicerEstimate,
324 /// The extrusion the file's own moves add up to, up to a position in it.
325 #[serde(rename = "gcode_extrusion")]
326 GcodeExtrusion,
327 /// The analysed length scaled by how far into the file the print got; the
328 /// fallback used only when the file itself could not be read.
329 #[serde(rename = "file_fraction")]
330 FileFraction,
331 /// A completed print this system never saw: the file's analysed length.
332 #[serde(rename = "unobserved_estimate")]
333 UnobservedEstimate,
334}
335
336/// Filament a tool fed after an unconfirmed filament change was held for the
337/// next spool loaded onto that tool, or confirmed on it.
338#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
339pub struct ChargePendedPayload {
340 /// What was held.
341 pub pending: PendingCharge,
342}
343
344/// One mark a spool command cleared, and the spool it was cleared from.
345#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
346pub struct ClearedMark {
347 /// The reason that no longer stands.
348 pub reason: UnverifiedReason,
349 /// The spool the mark was cleared from.
350 pub spool_id: SpoolId,
351}
352
353/// How sure the agent is.
354///
355/// A closed vocabulary rather than a number, because a number invites a
356/// precision the agent does not have.
357#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
358pub enum Confidence {
359 /// Not sure.
360 #[serde(rename = "low")]
361 Low,
362 /// Fairly sure.
363 #[serde(rename = "medium")]
364 Medium,
365 /// Sure.
366 #[serde(rename = "high")]
367 High,
368}
369
370/// What a context read answers.
371///
372/// The latest image is **materialized** here rather than left as the handle
373/// `PrintContext` carries: the one thing a supervision turn does with an
374/// image is look at it, and a handle is not something anything can open. The
375/// path is absolute on this server's own filesystem, exactly as
376/// `ImageAnswer`'s is, and is absent when there is no image or when the
377/// record is intact and the file is not.
378#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
379pub struct ContextAnswer {
380 /// Everything a supervision turn is given about the print.
381 pub context: PrintContext,
382 /// Where the latest image's bytes are, absolute on this host.
383 #[serde(default, skip_serializing_if = "Option::is_none")]
384 pub image_path: Option<String>,
385}
386
387/// The envelope intersected with the print's manifest.
388///
389/// This is what context reports, so that the agent can see its own limits
390/// before it asks. Computing one is the supervision core's; this crate
391/// declares
392/// the shape and nothing that produces it.
393#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
394pub struct EffectiveBounds {
395 /// The range each adjustable may be set to, inclusive.
396 pub allowed: BTreeMap<String, Range>,
397}
398
399/// What this server answers when it will not do what it was asked.
400#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
401pub struct ErrorAnswer {
402 /// One line saying why, in the words of whatever refused it.
403 pub error: String,
404}
405
406/// A lowercase hyphenated version 7 UUID identifying one event.
407pub type EventId = String;
408
409/// The name one kind of event is written down under: lowercase `snake_case`,
410/// declared by the domain that owns the event.
411pub type EventKind = String;
412
413/// One event, as the store holds it and the server serves it.
414///
415/// `raw` holds the bytes exactly as received for an externally sourced event
416/// and is absent for an internally raised one — it is what makes the history
417/// auditable when a normalization turns out to be wrong. `print_id` is
418/// optional, because an externally sourced event may name no print this
419/// system
420/// knows.
421#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
422pub struct EventRecord {
423 /// This event's identifier, minted by the store.
424 pub id: EventId,
425 /// The image it arrived with, when it arrived with one.
426 #[serde(default, skip_serializing_if = "Option::is_none")]
427 pub image: Option<ImageRef>,
428 /// Which event this is.
429 pub kind: EventKind,
430 /// What it carries, in the form its kind declares.
431 pub payload: serde_json::Value,
432 /// The print it belongs to, when it belongs to one.
433 #[serde(default, skip_serializing_if = "Option::is_none")]
434 pub print_id: Option<PrintId>,
435 /// The bytes exactly as received, for an externally sourced event.
436 #[serde(default, skip_serializing_if = "Option::is_none")]
437 pub raw: Option<RawBytes>,
438 /// When it was received.
439 pub received_at: Timestamp,
440 /// Where it came from.
441 pub source: EventSource,
442}
443
444/// Where an event came from, as the bare string the domain that raised it
445/// declares for itself.
446pub type EventSource = String;
447
448/// What happened when an accepted action reached the printer.
449#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
450pub enum ExecutionOutcome {
451 /// The printer took it.
452 #[serde(rename = "succeeded")]
453 Succeeded,
454 /// The printer did not, for this reason.
455 #[serde(rename = "failed")]
456 Failed {
457 /// Why it failed.
458 reason: String,
459 },
460}
461
462/// A filament change was signalled during a print.
463#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
464pub struct FilamentChangeSignalledPayload {
465 /// The position the spool was charged up to, when one was known.
466 #[serde(default, skip_serializing_if = "Option::is_none")]
467 pub position: Option<FilePosition>,
468 /// Whether that position was read when the signal was handled, rather
469 /// than
470 /// being the last one recorded; never with no position at all.
471 pub position_read_at_signal: bool,
472 /// The kind of the alert that carried the signal.
473 pub source_kind: EventKind,
474 /// The spool that was on it, when one was tracked.
475 #[serde(default, skip_serializing_if = "Option::is_none")]
476 pub spool_id: Option<SpoolId>,
477 /// The tool the change was signalled for, when it is known.
478 #[serde(default, skip_serializing_if = "Option::is_none")]
479 pub tool: Option<i64>,
480}
481
482/// Filament was charged against a spool, or recorded uncharged.
483#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
484pub struct FilamentConsumedPayload {
485 /// The file's analysed length for the tool, in millimetres, when it had
486 /// one.
487 #[serde(default, skip_serializing_if = "Option::is_none")]
488 pub analysed_length_mm: Option<f64>,
489 /// The durable identity of this debit.
490 pub charge_key: ChargeKey,
491 /// The density the grams were worked out with, in grams per cubic
492 /// centimetre.
493 #[serde(default, skip_serializing_if = "Option::is_none")]
494 pub density_g_cm3: Option<f64>,
495 /// The diameter the grams were worked out with, in millimetres.
496 #[serde(default, skip_serializing_if = "Option::is_none")]
497 pub diameter_mm: Option<f64>,
498 /// What that length weighs, in grams, when a spool gave its diameter and
499 /// density.
500 #[serde(default, skip_serializing_if = "Option::is_none")]
501 pub grams: Option<f64>,
502 /// How much was fed, in millimetres.
503 pub length_mm: f64,
504 /// How the length was worked out.
505 pub method: ChargeMethod,
506 /// Anything a reader needs to make sense of the figure.
507 #[serde(default, skip_serializing_if = "Option::is_none")]
508 pub note: Option<String>,
509 /// How far into the file the charge runs, when that was read.
510 #[serde(default, skip_serializing_if = "Option::is_none")]
511 pub position: Option<FilePosition>,
512 /// The spool's figure after it, in grams.
513 #[serde(default, skip_serializing_if = "Option::is_none")]
514 pub remaining_after_g: Option<f64>,
515 /// The spool's figure before the charge, in grams.
516 #[serde(default, skip_serializing_if = "Option::is_none")]
517 pub remaining_before_g: Option<f64>,
518 /// The spool charged; absent when nothing was tracked on the tool, and
519 /// the
520 /// filament was recorded uncharged.
521 #[serde(default, skip_serializing_if = "Option::is_none")]
522 pub spool_id: Option<SpoolId>,
523 /// The tool that fed it.
524 pub tool: i64,
525}
526
527/// A file name a printer's own file API can be asked for: no path separator,
528/// no NUL byte, no `.` or `..` segment, no drive prefix, and not empty.
529pub type FileName = String;
530
531/// How far into its file a print had got, and when that was read.
532#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
533pub struct FilePosition {
534 /// The byte the printer had read the file up to.
535 pub bytes: i64,
536 /// When the position was read.
537 pub observed_at: Timestamp,
538 /// The file's size in bytes, when it was known.
539 #[serde(default, skip_serializing_if = "Option::is_none")]
540 pub size_bytes: Option<i64>,
541}
542
543/// The printer's tally for a file went down — the file was deleted and
544/// uploaded again — so the file's tally generation advanced, and the new
545/// count
546/// is that generation's growth from zero.
547///
548/// The rebaseline itself marks no spool; only an `unverified` disposition
549/// does.
550#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
551pub struct FileTallyRebaselinedPayload {
552 /// What became of the prints the new generation counts.
553 pub disposition: RebaselineDisposition,
554 /// The file whose tally went down.
555 pub file_name: String,
556 /// The failed prints the new tally counts.
557 pub new_failures: i64,
558 /// The generation it is in now.
559 pub new_generation: i64,
560 /// The completed prints the new tally counts.
561 pub new_successes: i64,
562 /// The failed prints the old tally counted.
563 pub old_failures: i64,
564 /// The generation the tally was in.
565 pub old_generation: i64,
566 /// The completed prints the old tally counted.
567 pub old_successes: i64,
568 /// Where it lives, in the printer's own vocabulary.
569 pub origin: String,
570}
571
572/// One heater, as a source reported it.
573///
574/// Every field is optional, because a source that reports no heater at all
575/// reports none of these; each is a plausibility-ranged reported value in
576/// degrees Celsius.
577#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
578pub struct HeaterSnapshot {
579 /// The temperature the heater is at.
580 #[serde(default, skip_serializing_if = "Option::is_none")]
581 pub actual_c: Option<Reported>,
582 /// The offset applied to this heater's target.
583 #[serde(default, skip_serializing_if = "Option::is_none")]
584 pub offset_c: Option<Reported>,
585 /// The temperature the heater is driving towards.
586 #[serde(default, skip_serializing_if = "Option::is_none")]
587 pub target_c: Option<Reported>,
588}
589
590/// What a history read answers.
591#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
592pub struct HistoryAnswer {
593 /// The print's events, newest first.
594 pub events: Vec<EventRecord>,
595}
596
597/// What an image read answers.
598///
599/// The path is absolute on this server's own filesystem, and is the whole of
600/// the answer about the bytes: nothing here renders them, encodes them or
601/// serves them. It is absent when the record is intact and the file is not,
602/// which is a different answer from there being no such image.
603#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
604pub struct ImageAnswer {
605 /// Where its bytes are, absolute on this host.
606 #[serde(default, skip_serializing_if = "Option::is_none")]
607 pub path: Option<String>,
608 /// The record.
609 pub record: ImageRecord,
610}
611
612/// A lowercase hyphenated version 7 UUID identifying one image.
613pub type ImageId = String;
614
615/// One image, stored beside the event it arrived with.
616///
617/// `relative_path` is relative to the configured state directory, so that the
618/// store stays portable. Materializing an image resolves that to an absolute
619/// path; nothing in this system renders image bytes into JSON.
620#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
621pub struct ImageRecord {
622 /// How many bytes it is.
623 pub byte_len: i64,
624 /// The content type it was served as.
625 pub content_type: String,
626 /// The event it arrived with.
627 pub event_id: EventId,
628 /// When it was fetched.
629 pub fetched_at: Timestamp,
630 /// This image's identifier, minted by the store.
631 pub id: ImageId,
632 /// The print it belongs to.
633 pub print_id: PrintId,
634 /// Where it lives, relative to the configured state directory.
635 pub relative_path: String,
636 /// The SHA-256 of its bytes, lowercase hexadecimal.
637 pub sha256: String,
638 /// Where it was fetched from, when it was fetched from somewhere.
639 #[serde(default, skip_serializing_if = "Option::is_none")]
640 pub source_url: Option<String>,
641}
642
643/// The handle an image travels in context under.
644#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
645pub struct ImageRef {
646 /// The image's identifier.
647 pub id: ImageId,
648 /// The SHA-256 of its bytes, lowercase hexadecimal.
649 pub sha256: String,
650}
651
652/// One adjustment made for a bounded time.
653///
654/// `prior_value` is read from the printer snapshot taken before the change,
655/// and
656/// is absent when the printer reported none — in which case expiry restores
657/// nothing and the outcome says so rather than guessing a default.
658#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
659pub struct Intervention {
660 /// The action that asked for it.
661 pub action_id: ActionId,
662 /// What it changed.
663 pub adjustable: Adjustable,
664 /// When it was applied.
665 pub applied_at: Timestamp,
666 /// What it was changed to.
667 pub applied_value: f64,
668 /// When it stops standing.
669 pub expires_at: Timestamp,
670 /// This intervention's identifier, minted by the store.
671 pub id: InterventionId,
672 /// What became of it.
673 pub outcome: InterventionOutcome,
674 /// The print it was made against.
675 pub print_id: PrintId,
676 /// What the printer reported before the change, if it reported anything.
677 #[serde(default, skip_serializing_if = "Option::is_none")]
678 pub prior_value: Option<f64>,
679 /// When the prior value was put back, if it was.
680 #[serde(default, skip_serializing_if = "Option::is_none")]
681 pub restored_at: Option<Timestamp>,
682}
683
684/// A bounded intervention expired.
685#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
686pub struct InterventionExpiredPayload {
687 /// What it had changed.
688 pub adjustable: Adjustable,
689 /// The intervention's identifier.
690 pub intervention_id: InterventionId,
691 /// What became of it.
692 pub outcome: InterventionOutcome,
693}
694
695/// A lowercase hyphenated version 7 UUID identifying one bounded
696/// intervention.
697pub type InterventionId = String;
698
699/// What became of a bounded change.
700#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
701pub enum InterventionOutcome {
702 /// It is still in force.
703 #[serde(rename = "still_active")]
704 StillActive,
705 /// The prior value was put back.
706 #[serde(rename = "restored")]
707 Restored,
708 /// There was no prior value to put back.
709 #[serde(rename = "restore_unavailable")]
710 RestoreUnavailable,
711 /// Putting the prior value back failed.
712 #[serde(rename = "restore_failed")]
713 RestoreFailed {
714 /// Why it failed.
715 reason: String,
716 },
717 /// Another intervention replaced it before it expired.
718 #[serde(rename = "superseded")]
719 Superseded {
720 /// The intervention that replaced it.
721 by: InterventionId,
722 },
723}
724
725/// What a sliced job declares about itself and about what may be adjusted.
726///
727/// An adjustable the manifest does not name takes the envelope's own range; a
728/// manifest range wider than the envelope's is narrowed to the envelope's and
729/// the narrowing is recorded on the print. A manifest may only narrow.
730#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
731pub struct JobManifest {
732 /// The range each named adjustable may take, inclusive.
733 pub allowed: BTreeMap<String, Range>,
734 /// The file this manifest is about, as the slicer named it.
735 pub file_name: String,
736 /// The material the job is sliced for.
737 pub material: String,
738 /// Whatever else the slicer recorded.
739 pub metadata: BTreeMap<String, String>,
740 /// The nozzle the job is sliced for, in millimetres.
741 pub nozzle_diameter_mm: f64,
742 /// The slicer profile the job was sliced with.
743 pub slicer_profile: String,
744}
745
746/// The job a printer reports it is running.
747///
748/// Every field but `state` is optional: an absent one means the source did
749/// not
750/// report it.
751#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
752pub struct JobSnapshot {
753 /// How far through the print is, as a fraction from zero to one.
754 ///
755 /// Normalized to a fraction here regardless of how the source expresses
756 /// it.
757 #[serde(default, skip_serializing_if = "Option::is_none")]
758 pub completion: Option<Reported>,
759 /// The error the source reports, when it reports one.
760 #[serde(default, skip_serializing_if = "Option::is_none")]
761 pub error: Option<String>,
762 /// The whole print's estimated duration, in whole seconds.
763 #[serde(default, skip_serializing_if = "Option::is_none")]
764 pub estimated_print_time_s: Option<i64>,
765 /// The filament the source's analysis of the file says each tool uses;
766 /// empty when the source reported none.
767 #[serde(default, skip_serializing_if = "Option::is_none")]
768 pub filament: Option<Vec<ToolFilament>>,
769 /// The name of the file being printed, as the source reported it.
770 #[serde(default, skip_serializing_if = "Option::is_none")]
771 pub file_name: Option<String>,
772 /// Where the file lives, in the source's own vocabulary.
773 #[serde(default, skip_serializing_if = "Option::is_none")]
774 pub file_origin: Option<String>,
775 /// How far into the file the printer has read, in bytes, when the source
776 /// reported it.
777 #[serde(default, skip_serializing_if = "Option::is_none")]
778 pub file_position_bytes: Option<i64>,
779 /// How long the print has left, in whole seconds.
780 #[serde(default, skip_serializing_if = "Option::is_none")]
781 pub print_time_left_s: Option<i64>,
782 /// How long the print has been running, in whole seconds.
783 #[serde(default, skip_serializing_if = "Option::is_none")]
784 pub print_time_s: Option<i64>,
785 /// The file's size in bytes.
786 #[serde(default, skip_serializing_if = "Option::is_none")]
787 pub size_bytes: Option<i64>,
788 /// The state the source reports the job to be in.
789 pub state: PrinterState,
790}
791
792/// One spool loaded on one tool, as a print started.
793#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
794pub struct LoadedSpool {
795 /// The spool loaded on it.
796 pub spool_id: SpoolId,
797 /// The tool, in the printer's own numbering.
798 pub tool: i64,
799}
800
801/// One fresh look at a print.
802///
803/// An answer rather than a record, so it admits fields beside its own the way
804/// every answer of the server does: a client that could not open the frame's
805/// path says so in a field of its own beside the rest of the answer.
806#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
807pub struct Look {
808 /// The events for this print that arrived while the look waited, oldest
809 /// first; the look returned early when there were any.
810 #[serde(default, skip_serializing_if = "Option::is_none")]
811 pub arrived: Option<Vec<EventRecord>>,
812 /// Whether the print is paused and the pause is the detector's, which is
813 /// what an adjustment asked for now would be applied under.
814 pub detector_paused: bool,
815 /// The look itself, as it was written into the print's history, carrying
816 /// the frame as its image when there is one.
817 pub event: EventRecord,
818 /// The frame the camera gave, absent when no camera is configured or it
819 /// gave none — which the history records as a port failure.
820 #[serde(default, skip_serializing_if = "Option::is_none")]
821 pub frame: Option<ImageRef>,
822 /// The absolute path the frame's bytes are at, on the supervisor's host.
823 #[serde(default, skip_serializing_if = "Option::is_none")]
824 pub image_path: Option<String>,
825 /// The job the printer reports now, absent when it could not be read.
826 #[serde(default, skip_serializing_if = "Option::is_none")]
827 pub job: Option<JobSnapshot>,
828 /// The printer's state now, absent when it could not be read.
829 #[serde(default, skip_serializing_if = "Option::is_none")]
830 pub printer: Option<PrinterSnapshot>,
831}
832
833/// An external body arrived that could not be read.
834///
835/// This kind always carries its `raw` bytes, and it exists so that an alert
836/// this system cannot read is written down rather than dropped.
837#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
838pub struct MalformedExternalEventPayload {
839 /// One line saying why the body could not be read.
840 pub detail: String,
841}
842
843/// What a manifest read or write answers.
844#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
845pub struct ManifestAnswer {
846 /// The manifest, when the print has one.
847 #[serde(default, skip_serializing_if = "Option::is_none")]
848 pub manifest: Option<JobManifest>,
849 /// Every range this manifest asked wider than the envelope allows,
850 /// narrowed
851 /// to the envelope's — recorded on the print, so nobody has to wonder
852 /// later
853 /// which bound applied.
854 pub narrowings: Vec<ManifestNarrowing>,
855}
856
857/// One adjustable whose manifest range was wider than the envelope's.
858#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
859pub struct ManifestNarrowing {
860 /// The adjustable that was narrowed.
861 pub adjustable: Adjustable,
862 /// The range that stands.
863 pub applied: Range,
864 /// The range the manifest asked for.
865 pub requested: Range,
866}
867
868/// Obico reported a print failure.
869///
870/// The two instants are optional because Obico's own field for each is a Unix
871/// timestamp number, an empty string, or absent, and the last two both mean
872/// the
873/// producer reported no instant. An absent field here is that, never an epoch
874/// date standing in for it.
875#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
876pub struct ObicoFailureAlertPayload {
877 /// When the print ended, when Obico reported an instant for it.
878 #[serde(default, skip_serializing_if = "Option::is_none")]
879 pub ended_at: Option<Timestamp>,
880 /// The file being printed, when Obico named one.
881 #[serde(default, skip_serializing_if = "Option::is_none")]
882 pub file_name: Option<String>,
883 /// Whether Obico called it a warning rather than a failure.
884 pub is_warning: bool,
885 /// Obico's own identifier for the print, when it named one.
886 #[serde(default, skip_serializing_if = "Option::is_none")]
887 pub obico_print_id: Option<i64>,
888 /// Whether Obico paused the print itself.
889 pub print_paused: bool,
890 /// When the print started, when Obico reported an instant for it.
891 #[serde(default, skip_serializing_if = "Option::is_none")]
892 pub started_at: Option<Timestamp>,
893}
894
895/// The kind of printer notification Obico sent, normalized.
896#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
897pub enum ObicoNotificationType {
898 /// A print started.
899 #[serde(rename = "started")]
900 Started,
901 /// A print finished.
902 #[serde(rename = "done")]
903 Done,
904 /// A print was cancelled.
905 #[serde(rename = "cancelled")]
906 Cancelled,
907 /// A print was paused.
908 #[serde(rename = "paused")]
909 Paused,
910 /// A print was resumed.
911 #[serde(rename = "resumed")]
912 Resumed,
913 /// The printer is waiting for a filament change.
914 #[serde(rename = "filament_change")]
915 FilamentChange,
916 /// A heater cooled down.
917 #[serde(rename = "heater_cooled")]
918 HeaterCooled,
919 /// A heater reached its target.
920 #[serde(rename = "heater_target")]
921 HeaterTarget,
922}
923
924/// Obico sent a printer notification.
925///
926/// The two instants are optional for the same reason
927/// `ObicoFailureAlertPayload`'s are, and are absent along with the rest of
928/// the print's fields when the notification is about no print at all.
929#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
930pub struct ObicoPrinterNotificationPayload {
931 /// When the print ended, when Obico reported an instant for it.
932 #[serde(default, skip_serializing_if = "Option::is_none")]
933 pub ended_at: Option<Timestamp>,
934 /// The file being printed, when the notification is about one.
935 #[serde(default, skip_serializing_if = "Option::is_none")]
936 pub file_name: Option<String>,
937 /// Which notification it is.
938 pub notification_type: ObicoNotificationType,
939 /// Obico's own identifier for the print, when the notification is about
940 /// one.
941 #[serde(default, skip_serializing_if = "Option::is_none")]
942 pub obico_print_id: Option<i64>,
943 /// When the print started, when Obico reported an instant for it.
944 #[serde(default, skip_serializing_if = "Option::is_none")]
945 pub started_at: Option<Timestamp>,
946}
947
948/// An operator acknowledged an event.
949#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
950pub struct OperatorAcknowledgementPayload {
951 /// The event being acknowledged.
952 pub acknowledged_event_id: EventId,
953 /// What the operator asked for next.
954 pub disposition: AcknowledgementDisposition,
955}
956
957/// Filament a tool fed after a filament change nobody has confirmed, held
958/// until
959/// somebody says which spool fed it.
960///
961/// A length rather than grams, because the grams follow the spool that takes
962/// it.
963#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
964pub struct PendingCharge {
965 /// The file's analysed length for the tool, in millimetres, when it had
966 /// one.
967 #[serde(default, skip_serializing_if = "Option::is_none")]
968 pub analysed_length_mm: Option<f64>,
969 /// The key of the print segment the filament was fed in.
970 pub charge_key: ChargeKey,
971 /// How much was fed, in millimetres.
972 pub length_mm: f64,
973 /// How that length was worked out.
974 pub method: ChargeMethod,
975 /// Anything a reader needs to make sense of the figure.
976 #[serde(default, skip_serializing_if = "Option::is_none")]
977 pub note: Option<String>,
978 /// When it was held.
979 pub pended_at: Timestamp,
980 /// How far into the file the segment ran, when that was read.
981 #[serde(default, skip_serializing_if = "Option::is_none")]
982 pub position: Option<FilePosition>,
983 /// The print it was fed in.
984 pub print_id: PrintId,
985 /// The tool that fed it.
986 pub tool: i64,
987}
988
989/// One pending charge a spool command took.
990#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
991pub struct PendingTaken {
992 /// The key it is charged under.
993 pub charge_key: ChargeKey,
994 /// The print it was fed in.
995 pub print_id: PrintId,
996}
997
998/// The supervisor looked in on an active print on its own schedule, with no
999/// detector having said anything about it.
1000///
1001/// What a failure detector never alerts on — a progress that stopped moving,
1002/// a
1003/// heater whose target fell to nothing mid-print, a fan cut at a bridge, a
1004/// wall
1005/// going thin — is still on the machine and in the camera's frame, so every
1006/// active print is given one of these each interval and a turn on it. It
1007/// carries what the printer reported as it was taken; the frame the camera
1008/// gave
1009/// at the same moment, untagged by any detector, is this event's image.
1010#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1011pub struct PeriodicObservationPayload {
1012 /// How often these are taken, in whole seconds.
1013 pub interval_s: i64,
1014 /// The job the printer reported as the observation was taken, absent when
1015 /// it could not be read.
1016 #[serde(default, skip_serializing_if = "Option::is_none")]
1017 pub job: Option<JobSnapshot>,
1018 /// The printer's state as the observation was taken, absent when it could
1019 /// not be read — which the history records as a port failure.
1020 #[serde(default, skip_serializing_if = "Option::is_none")]
1021 pub printer: Option<PrinterSnapshot>,
1022}
1023
1024/// The decision policy took on one request.
1025#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1026pub enum PolicyDecision {
1027 /// The request may proceed.
1028 #[serde(rename = "accepted")]
1029 Accepted,
1030 /// The request may not, for this reason.
1031 #[serde(rename = "rejected")]
1032 Rejected(RejectionReason),
1033}
1034
1035/// A port failed while one event was being handled.
1036///
1037/// The event is named rather than implied, so that a reader holding an
1038/// event's
1039/// identifier reaches every failure recorded while that event was being
1040/// handled. A failure recorded here is one the handling survived: the event
1041/// is
1042/// already in the history by the time any of these sites is reached, and the
1043/// loop goes on to handle the next event.
1044#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1045pub struct PortFailurePayload {
1046 /// What the port said about it, in the port's own words.
1047 pub detail: String,
1048 /// The event whose handling reached the failing call.
1049 pub event_id: EventId,
1050 /// Where it failed.
1051 pub site: PortFailureSite,
1052}
1053
1054/// Where a port failed while an event was being handled.
1055///
1056/// A closed set of exactly the sites at which a failure has nowhere else to
1057/// be
1058/// recorded. The printer's action methods record theirs on the
1059/// `ActionRecord` the request minted, and a restoring
1060/// call records its own on the `Intervention` it was
1061/// expiring; those are not sites here, because a second record of them would
1062/// be
1063/// a second version of one fact.
1064#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1065pub enum PortFailureSite {
1066 /// Reading the printer's own state.
1067 #[serde(rename = "printer_snapshot")]
1068 PrinterSnapshot,
1069 /// Reading the job the printer reports it is running.
1070 #[serde(rename = "printer_job")]
1071 PrinterJob,
1072 /// Writing the image the event arrived with.
1073 #[serde(rename = "image_write")]
1074 ImageWrite,
1075 /// Running the supervision turn the event prompted.
1076 #[serde(rename = "supervision_turn")]
1077 SupervisionTurn,
1078 /// Taking a fresh frame from the camera, for a look at the print or for a
1079 /// periodic observation of it.
1080 #[serde(rename = "camera_look")]
1081 CameraLook,
1082 /// Telling the detector that paused the print its detection was handled.
1083 #[serde(rename = "detector_acknowledgement")]
1084 DetectorAcknowledgement,
1085}
1086
1087/// What a filament check found for one print.
1088#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1089pub struct Preflight {
1090 /// When the check was made.
1091 pub checked_at: Timestamp,
1092 /// The file the print is of.
1093 pub file_name: String,
1094 /// What it found for each tool.
1095 pub tools: Vec<PreflightTool>,
1096 /// The worst of the tools' verdicts, in the order insufficient,
1097 /// unverified spool, no analysis, warned, overridden, unchecked, passed.
1098 pub verdict: PreflightVerdict,
1099}
1100
1101/// What a filament check answers.
1102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1103pub struct PreflightAnswer {
1104 /// What the check found, read now.
1105 pub preflight: Preflight,
1106}
1107
1108/// The filament check before a start was made.
1109#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1110pub struct PreflightCheckedPayload {
1111 /// The start it was made for, when it was made for one.
1112 #[serde(default, skip_serializing_if = "Option::is_none")]
1113 pub action_id: Option<ActionId>,
1114 /// What the check found.
1115 pub preflight: Preflight,
1116}
1117
1118/// What a filament check found for one tool.
1119#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1120pub struct PreflightTool {
1121 /// The margin asked for beyond that, in grams.
1122 #[serde(default, skip_serializing_if = "Option::is_none")]
1123 pub buffer_g: Option<f64>,
1124 /// The loaded spool's marks at the check, oldest first, whatever the
1125 /// verdict, so a spool both short and unverified says both.
1126 #[serde(default, skip_serializing_if = "Option::is_none")]
1127 pub marks: Option<Vec<UnverifiedMark>>,
1128 /// What the spool holds, in grams.
1129 #[serde(default, skip_serializing_if = "Option::is_none")]
1130 pub remaining_g: Option<f64>,
1131 /// What the print needs from it, in grams, when the file's analysis says.
1132 #[serde(default, skip_serializing_if = "Option::is_none")]
1133 pub required_g: Option<f64>,
1134 /// The spool loaded on it, when one is.
1135 #[serde(default, skip_serializing_if = "Option::is_none")]
1136 pub spool_id: Option<SpoolId>,
1137 /// That spool's name, beside its identifier, so a reader need not look it
1138 /// up.
1139 #[serde(default, skip_serializing_if = "Option::is_none")]
1140 pub spool_name: Option<String>,
1141 /// The tool, in the printer's own numbering.
1142 pub tool: i64,
1143 /// What the check found for this tool.
1144 pub verdict: PreflightVerdict,
1145}
1146
1147/// What a filament check found, for one tool or for a whole print.
1148#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1149pub enum PreflightVerdict {
1150 /// The spool holds what the print needs and its buffer.
1151 #[serde(rename = "passed")]
1152 Passed,
1153 /// No tracked spool is loaded on the tool, so nothing was checked.
1154 #[serde(rename = "unchecked")]
1155 Unchecked,
1156 /// The spool holds less than the print needs and its buffer.
1157 #[serde(rename = "insufficient")]
1158 Insufficient,
1159 /// The spool's figure is in doubt.
1160 #[serde(rename = "unverified_spool")]
1161 UnverifiedSpool,
1162 /// `OctoPrint`'s analysis of the file had still not appeared when the
1163 /// start's wait for it elapsed, or has not appeared yet when the check is
1164 /// only read.
1165 #[serde(rename = "no_analysis")]
1166 NoAnalysis,
1167 /// The start went ahead despite the check, because the actor said so.
1168 #[serde(rename = "overridden")]
1169 Overridden,
1170 /// The check is set to warn, and let an insufficient, unverified or
1171 /// unanalysed start go ahead.
1172 #[serde(rename = "warned")]
1173 Warned,
1174}
1175
1176/// The whole vocabulary an actor may ask for, and there is no other.
1177#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1178#[serde(tag = "action")]
1179pub enum PrintAction {
1180 /// Pause the print.
1181 #[serde(rename = "pause")]
1182 Pause {
1183 /// Who is asking.
1184 actor: Actor,
1185 /// Why the actor is asking for this.
1186 reason: String,
1187 },
1188 /// Resume the print.
1189 #[serde(rename = "resume")]
1190 Resume {
1191 /// Who is asking.
1192 actor: Actor,
1193 /// Why the actor is asking for this.
1194 reason: String,
1195 },
1196 /// Cancel the print.
1197 #[serde(rename = "cancel")]
1198 Cancel {
1199 /// Who is asking.
1200 actor: Actor,
1201 /// Why the actor is asking for this.
1202 reason: String,
1203 },
1204 /// Start a print of a named file, with a manifest.
1205 #[serde(rename = "start_print")]
1206 StartPrint {
1207 /// Who is asking.
1208 actor: Actor,
1209 /// The file to print, validated as a name a file API can be asked
1210 /// for.
1211 file_name: FileName,
1212 /// The manifest this print is bounded by.
1213 manifest: JobManifest,
1214 /// Start despite an insufficient or unverified spool, or a file
1215 /// `OctoPrint` has not analysed; the start's own reason is the
1216 /// override's reason.
1217 #[serde(default, skip_serializing_if = "Option::is_none")]
1218 override_filament_check: Option<bool>,
1219 /// Why the actor is asking for this.
1220 reason: String,
1221 },
1222 /// Set the feedrate factor, where one means one hundred percent.
1223 #[serde(rename = "set_feedrate_factor")]
1224 SetFeedrateFactor {
1225 /// Who is asking.
1226 actor: Actor,
1227 /// How long the change stands for, in whole seconds.
1228 #[serde(default, skip_serializing_if = "Option::is_none")]
1229 duration_s: Option<i64>,
1230 /// The multiplier asked for.
1231 factor: f64,
1232 /// Why the actor is asking for this.
1233 reason: String,
1234 },
1235 /// Set the flowrate factor, where one means one hundred percent.
1236 #[serde(rename = "set_flowrate_factor")]
1237 SetFlowrateFactor {
1238 /// Who is asking.
1239 actor: Actor,
1240 /// How long the change stands for, in whole seconds.
1241 #[serde(default, skip_serializing_if = "Option::is_none")]
1242 duration_s: Option<i64>,
1243 /// The multiplier asked for.
1244 factor: f64,
1245 /// Why the actor is asking for this.
1246 reason: String,
1247 },
1248 /// Set one tool's target temperature.
1249 #[serde(rename = "set_tool_target_c")]
1250 SetToolTargetC {
1251 /// Who is asking.
1252 actor: Actor,
1253 /// How long the change stands for, in whole seconds.
1254 #[serde(default, skip_serializing_if = "Option::is_none")]
1255 duration_s: Option<i64>,
1256 /// Why the actor is asking for this.
1257 reason: String,
1258 /// The target temperature asked for, in degrees Celsius.
1259 target_c: f64,
1260 /// The tool, in the printer's own numbering.
1261 tool: i64,
1262 },
1263 /// Set the bed's target temperature.
1264 #[serde(rename = "set_bed_target_c")]
1265 SetBedTargetC {
1266 /// Who is asking.
1267 actor: Actor,
1268 /// How long the change stands for, in whole seconds.
1269 #[serde(default, skip_serializing_if = "Option::is_none")]
1270 duration_s: Option<i64>,
1271 /// Why the actor is asking for this.
1272 reason: String,
1273 /// The target temperature asked for, in degrees Celsius.
1274 target_c: f64,
1275 },
1276 /// Set the part-cooling fan percentage.
1277 #[serde(rename = "set_fan_percent")]
1278 SetFanPercent {
1279 /// Who is asking.
1280 actor: Actor,
1281 /// How long the change stands for, in whole seconds.
1282 #[serde(default, skip_serializing_if = "Option::is_none")]
1283 duration_s: Option<i64>,
1284 /// The percentage asked for.
1285 percent: f64,
1286 /// Why the actor is asking for this.
1287 reason: String,
1288 },
1289 /// Acknowledge a failure event, with a disposition.
1290 #[serde(rename = "acknowledge_failure")]
1291 AcknowledgeFailure {
1292 /// Who is asking.
1293 actor: Actor,
1294 /// What to do next.
1295 disposition: AcknowledgementDisposition,
1296 /// The event being acknowledged.
1297 event_id: EventId,
1298 /// Why the actor is asking for this.
1299 reason: String,
1300 },
1301}
1302
1303/// Everything a supervision turn is given about one print.
1304#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1305pub struct PrintContext {
1306 /// The limits in force, so that the agent can see them before it asks.
1307 pub bounds: EffectiveBounds,
1308 /// The interventions still active.
1309 pub interventions: Vec<Intervention>,
1310 /// The job, when a snapshot could be taken.
1311 #[serde(default, skip_serializing_if = "Option::is_none")]
1312 pub job: Option<JobSnapshot>,
1313 /// The most recent image, when there is one.
1314 #[serde(default, skip_serializing_if = "Option::is_none")]
1315 pub latest_image: Option<ImageRef>,
1316 /// The manifest, when the print has one.
1317 #[serde(default, skip_serializing_if = "Option::is_none")]
1318 pub manifest: Option<JobManifest>,
1319 /// The print itself.
1320 pub print: PrintRecord,
1321 /// The printer, when a snapshot could be taken.
1322 #[serde(default, skip_serializing_if = "Option::is_none")]
1323 pub printer: Option<PrinterSnapshot>,
1324 /// A bounded list of this print's events, newest first.
1325 pub recent_events: Vec<EventRecord>,
1326}
1327
1328/// A print ended.
1329#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1330pub struct PrintEndedPayload {
1331 /// How far into its file it last read, when that was read.
1332 #[serde(default, skip_serializing_if = "Option::is_none")]
1333 pub last_position: Option<FilePosition>,
1334 /// How it ended.
1335 pub outcome: PrintOutcome,
1336 /// Why it ended, in the words the end was recorded with.
1337 pub reason: String,
1338 /// The state the printer was in as it ended.
1339 pub state: PrinterState,
1340}
1341
1342/// A lowercase hyphenated version 7 UUID identifying one print.
1343pub type PrintId = String;
1344
1345/// How a print ended.
1346#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1347pub enum PrintOutcome {
1348 /// It ran to its end.
1349 #[serde(rename = "completed")]
1350 Completed,
1351 /// Somebody cancelled it.
1352 #[serde(rename = "cancelled")]
1353 Cancelled,
1354 /// It stopped on an error.
1355 #[serde(rename = "failed")]
1356 Failed,
1357}
1358
1359/// One print, and the record supervision keys from.
1360///
1361/// The provider's own print id is carried beside this record's identifier
1362/// rather than as it, because a print may be observed before the provider
1363/// that reports it has one.
1364#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1365pub struct PrintRecord {
1366 /// Why it ended, if it has.
1367 #[serde(default, skip_serializing_if = "Option::is_none")]
1368 pub end_reason: Option<String>,
1369 /// When it ended, if it has.
1370 #[serde(default, skip_serializing_if = "Option::is_none")]
1371 pub ended_at: Option<Timestamp>,
1372 /// The file being printed, as the source reported it.
1373 #[serde(default, skip_serializing_if = "Option::is_none")]
1374 pub file_name: Option<String>,
1375 /// This print's identifier, minted by the store.
1376 pub id: PrintId,
1377 /// The longest running time, in whole seconds, the printer reported for
1378 /// this print's job at a read that found it printing rather than paused.
1379 ///
1380 /// The time a job has spent printing only grows, pause or no pause, so a
1381 /// job of this print's file reporting less — by more than
1382 /// `listing::JOB_IDENTITY_TOLERANCE_S` — is a later job. Absent until a
1383 /// read finds the job printing.
1384 #[serde(default, skip_serializing_if = "Option::is_none")]
1385 pub job_print_time_s: Option<i64>,
1386 /// When the printer's job this print records began, as the printer's own
1387 /// running time put it at the latest read that found the job running or
1388 /// paused: the instant of that read, less the running time it reported.
1389 ///
1390 /// `OctoPrint` counts a pause into the running time until the job resumes
1391 /// and then takes the pause back out, so a pause moves this later: a read
1392 /// putting it further than `listing::JOB_IDENTITY_TOLERANCE_S` from the
1393 /// one
1394 /// recorded resets it, rather than it being fixed once. Absent when no
1395 /// read has
1396 /// found this print's job reporting a running time — a print opened by an
1397 /// alert or a start before any read, and every print recorded before this
1398 /// was.
1399 #[serde(default, skip_serializing_if = "Option::is_none")]
1400 pub job_started_at: Option<Timestamp>,
1401 /// Every manifest range this print narrowed to the envelope's.
1402 pub narrowings: Vec<ManifestNarrowing>,
1403 /// When the print was opened.
1404 pub opened_at: Timestamp,
1405 /// The provider's own identifier for the print, whichever provider
1406 /// reported it, when one has.
1407 #[serde(default, skip_serializing_if = "Option::is_none")]
1408 pub provider_print_id: Option<i64>,
1409 /// The state the print is in.
1410 pub state: PrinterState,
1411}
1412
1413/// A print started.
1414#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1415pub struct PrintStartedPayload {
1416 /// The file being printed, when it is known.
1417 #[serde(default, skip_serializing_if = "Option::is_none")]
1418 pub file_name: Option<String>,
1419 /// The spool loaded on each tool as it started.
1420 pub loaded: Vec<LoadedSpool>,
1421 /// The filament check made before it started, when one was.
1422 #[serde(default, skip_serializing_if = "Option::is_none")]
1423 pub preflight: Option<Preflight>,
1424 /// The action that started it; absent when the print was observed rather
1425 /// than started through this system.
1426 #[serde(default, skip_serializing_if = "Option::is_none")]
1427 pub started_by: Option<ActionId>,
1428}
1429
1430/// A print that was already open when spool tracking was installed: it is
1431/// never charged, and this says why it carries no charge.
1432#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1433pub struct PrintUntrackedPayload {
1434 /// Why the print carries no charge.
1435 pub reason: String,
1436}
1437
1438/// A printer, as a source reported it at one instant.
1439#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1440pub struct PrinterSnapshot {
1441 /// The bed heater, when the printer reports one.
1442 #[serde(default, skip_serializing_if = "Option::is_none")]
1443 pub bed: Option<HeaterSnapshot>,
1444 /// The chamber heater, when the printer reports one.
1445 #[serde(default, skip_serializing_if = "Option::is_none")]
1446 pub chamber: Option<HeaterSnapshot>,
1447 /// The state the printer is in.
1448 pub connection: PrinterState,
1449 /// The part-cooling fan, in percent.
1450 #[serde(default, skip_serializing_if = "Option::is_none")]
1451 pub fan_percent: Option<Reported>,
1452 /// The feedrate multiplier, where one means one hundred percent.
1453 #[serde(default, skip_serializing_if = "Option::is_none")]
1454 pub feedrate_factor: Option<Reported>,
1455 /// The flowrate multiplier, where one means one hundred percent.
1456 #[serde(default, skip_serializing_if = "Option::is_none")]
1457 pub flowrate_factor: Option<Reported>,
1458 /// The instant this observation was taken.
1459 pub observed_at: Timestamp,
1460 /// The tool heaters, indexed by tool number.
1461 pub tools: Vec<HeaterSnapshot>,
1462}
1463
1464/// The state a source reports a printer or a print to be in.
1465///
1466/// The `unknown` arm exists so that a state nobody anticipated is recorded
1467/// carrying the source's own word for it rather than lost.
1468#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1469pub enum PrinterState {
1470 /// Connected and idle.
1471 #[serde(rename = "operational")]
1472 Operational,
1473 /// Printing, but paused.
1474 #[serde(rename = "paused")]
1475 Paused,
1476 /// Printing.
1477 #[serde(rename = "printing")]
1478 Printing,
1479 /// Cancelling a print.
1480 #[serde(rename = "cancelling")]
1481 Cancelling,
1482 /// In an error state.
1483 #[serde(rename = "error")]
1484 Error,
1485 /// Not reachable.
1486 #[serde(rename = "offline")]
1487 Offline,
1488 /// A state this vocabulary does not name, in the source's own word for
1489 /// it.
1490 #[serde(rename = "unknown")]
1491 Unknown(String),
1492}
1493
1494/// What the prints read answers: every print, and the one the printer is
1495/// running.
1496///
1497/// An open print's recorded `state` is the state it was opened in, which is
1498/// `printing` whether or not the machine is paused now; what the machine is
1499/// doing is the status read's answer.
1500#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1501pub struct PrintsAnswer {
1502 /// The print the printer's current job belongs to, present exactly when
1503 /// the
1504 /// printer reports a job it is printing or has paused. Absent when the
1505 /// printer could not be read.
1506 #[serde(default, skip_serializing_if = "Option::is_none")]
1507 pub active: Option<PrintId>,
1508 /// Every print this server holds, ended or not, most recently opened
1509 /// first.
1510 pub prints: Vec<PrintRecord>,
1511}
1512
1513/// An inclusive pair of 64-bit floats.
1514#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1515pub struct Range {
1516 /// The highest value the range admits, inclusive.
1517 pub max: f64,
1518 /// The lowest value the range admits, inclusive.
1519 pub min: f64,
1520}
1521
1522/// Bytes exactly as received, base64-encoded.
1523pub type RawBytes = String;
1524
1525/// What became of the prints a file's new tally generation counts.
1526#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1527pub enum RebaselineDisposition {
1528 /// They were accounted as prints this system never saw.
1529 #[serde(rename = "accounted")]
1530 Accounted,
1531 /// It could not be told which of them this system already settled, so the
1532 /// loaded spool was marked unverified rather than charged on a guess.
1533 #[serde(rename = "unverified")]
1534 Unverified,
1535}
1536
1537/// Why a request was refused.
1538///
1539/// Each rejection is a distinct variant, so a consumer distinguishes them by
1540/// matching rather than by reading a message.
1541#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1542pub enum RejectionReason {
1543 /// The value asked for is outside the range allowed for that adjustable.
1544 #[serde(rename = "out_of_bounds")]
1545 OutOfBounds {
1546 /// The adjustable that was asked for.
1547 adjustable: Adjustable,
1548 /// The range that was allowed.
1549 allowed: Range,
1550 /// The value that was asked for.
1551 requested: f64,
1552 },
1553 /// This actor class may not request this action at all.
1554 #[serde(rename = "actor_may_not_request")]
1555 ActorMayNotRequest {
1556 /// The action they asked for.
1557 action: ActionKind,
1558 /// The class of the actor that asked.
1559 actor_class: ActorClass,
1560 },
1561 /// There is no active print to act on.
1562 #[serde(rename = "no_active_print")]
1563 NoActivePrint,
1564 /// The printer is not in a state this action is valid from.
1565 #[serde(rename = "invalid_from_state")]
1566 InvalidFromState {
1567 /// The state the printer is in.
1568 state: PrinterState,
1569 },
1570 /// The agent's minimum interval has not elapsed.
1571 #[serde(rename = "min_interval_not_elapsed")]
1572 MinIntervalNotElapsed {
1573 /// The minimum interval, in whole seconds.
1574 interval_s: i64,
1575 /// How long it has been since the last agent action, in whole
1576 /// seconds.
1577 since_last_s: i64,
1578 },
1579 /// The adjustable is not one this printer has.
1580 #[serde(rename = "unsupported_adjustable")]
1581 UnsupportedAdjustable {
1582 /// The adjustable this printer cannot express.
1583 adjustable: Adjustable,
1584 },
1585 /// A start was refused because the spool on one tool holds less than the
1586 /// print needs and its buffer.
1587 #[serde(rename = "insufficient_filament")]
1588 InsufficientFilament {
1589 /// The margin asked for beyond that, in grams.
1590 buffer_g: f64,
1591 /// What the spool holds, in grams.
1592 remaining_g: f64,
1593 /// What the print needs from it, in grams.
1594 required_g: f64,
1595 /// The spool loaded on it.
1596 spool_id: SpoolId,
1597 /// That spool's name.
1598 spool_name: String,
1599 /// The tool whose spool is short.
1600 tool: i64,
1601 /// The spool's oldest mark, when the short spool is also unverified.
1602 #[serde(default, skip_serializing_if = "Option::is_none")]
1603 unverified: Option<UnverifiedReason>,
1604 },
1605 /// A start was refused because the spool on one tool is unverified.
1606 #[serde(rename = "unverified_spool")]
1607 UnverifiedSpool {
1608 /// The spool's oldest mark.
1609 reason: UnverifiedReason,
1610 /// The spool loaded on it.
1611 spool_id: SpoolId,
1612 /// That spool's name.
1613 spool_name: String,
1614 /// The tool whose spool is unverified.
1615 tool: i64,
1616 },
1617 /// A start was refused because `OctoPrint`'s analysis of the file had not
1618 /// appeared when the start's wait for it elapsed.
1619 #[serde(rename = "analysis_unavailable")]
1620 AnalysisUnavailable {
1621 /// The file that has no analysis.
1622 file_name: String,
1623 /// How long the start waited for one, in whole seconds.
1624 waited_s: i64,
1625 },
1626 /// A spool command could not be carried out.
1627 #[serde(rename = "spool_refused")]
1628 SpoolRefused {
1629 /// Why, in a sentence naming what to do instead.
1630 detail: String,
1631 },
1632}
1633
1634/// A value as a source reported it, flagged when it is outside the
1635/// plausibility range this crate declares for its field.
1636#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1637pub struct Reported {
1638 /// One shape of the contracts, which say nothing more about it.
1639 pub out_of_range: bool,
1640 /// One shape of the contracts, which say nothing more about it.
1641 pub value: f64,
1642}
1643
1644/// A spool's remaining figure was corrected.
1645#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1646pub struct SpoolAdjustedPayload {
1647 /// Who corrected it.
1648 pub actor: Actor,
1649 /// Every mark the correction cleared.
1650 #[serde(default, skip_serializing_if = "Option::is_none")]
1651 pub cleared_marks: Option<Vec<ClearedMark>>,
1652 /// The scale reading the figure was worked out from, when it was given as
1653 /// one.
1654 #[serde(default, skip_serializing_if = "Option::is_none")]
1655 pub gross_g: Option<f64>,
1656 /// Why.
1657 pub reason: String,
1658 /// Its figure after, in grams.
1659 pub remaining_after_g: f64,
1660 /// Its figure before, in grams, after any pending charge it took.
1661 pub remaining_before_g: f64,
1662 /// The spool corrected.
1663 pub spool_id: SpoolId,
1664 /// The pending charges the correction took first, each also its own
1665 /// `filament_consumed` event under its key.
1666 #[serde(default, skip_serializing_if = "Option::is_none")]
1667 pub took_pending: Option<Vec<PendingTaken>>,
1668}
1669
1670/// What one spool's read answers: the spool, and the newest of the printer's
1671/// own events that name it.
1672#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1673pub struct SpoolAnswer {
1674 /// The newest timeline events naming it, newest first.
1675 pub recent: Vec<EventRecord>,
1676 /// The spool, retired or not.
1677 pub spool: SpoolRecord,
1678}
1679
1680/// The whole vocabulary of the spool ledger, and there is no other.
1681#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1682#[serde(tag = "command")]
1683pub enum SpoolCommand {
1684 /// Register a spool.
1685 #[serde(rename = "register_spool")]
1686 RegisterSpool {
1687 /// Who is asking.
1688 actor: Actor,
1689 /// The filament's colour.
1690 #[serde(default, skip_serializing_if = "Option::is_none")]
1691 color: Option<String>,
1692 /// The material's density, in grams per cubic centimetre; the known
1693 /// density of the material when absent, and a material with none
1694 /// known
1695 /// is refused.
1696 #[serde(default, skip_serializing_if = "Option::is_none")]
1697 density_g_cm3: Option<f64>,
1698 /// The filament's diameter, in millimetres; 1.75 when absent.
1699 #[serde(default, skip_serializing_if = "Option::is_none")]
1700 diameter_mm: Option<f64>,
1701 /// The net filament on the spool when full, in grams.
1702 initial_g: f64,
1703 /// The material, such as `PLA`.
1704 material: String,
1705 /// The operator's own label for it.
1706 name: String,
1707 /// Why the actor is asking for this.
1708 reason: String,
1709 /// The filament on it now, in grams; the full figure when absent.
1710 #[serde(default, skip_serializing_if = "Option::is_none")]
1711 remaining_g: Option<f64>,
1712 /// The empty spool's own weight, in grams.
1713 #[serde(default, skip_serializing_if = "Option::is_none")]
1714 tare_g: Option<f64>,
1715 },
1716 /// Load a spool onto a tool.
1717 ///
1718 /// Onto an occupied tool it is a swap, and the spool there is unloaded in
1719 /// the same write. Naming the spool already on the tool confirms it was
1720 /// never swapped, which is accepted only while that tool holds a pending
1721 /// charge or that spool holds a filament-change mark.
1722 #[serde(rename = "load_spool")]
1723 LoadSpool {
1724 /// Who is asking.
1725 actor: Actor,
1726 /// Why the actor is asking for this.
1727 reason: String,
1728 /// The spool to load.
1729 spool_id: SpoolId,
1730 /// The tool, in the printer's own numbering.
1731 tool: i64,
1732 },
1733 /// Unload a spool from its tool.
1734 #[serde(rename = "unload_spool")]
1735 UnloadSpool {
1736 /// Who is asking.
1737 actor: Actor,
1738 /// Why the actor is asking for this.
1739 reason: String,
1740 /// The spool to unload.
1741 spool_id: SpoolId,
1742 },
1743 /// Correct a spool's remaining figure, from exactly one of the two; a
1744 /// command naming both or neither is refused as `spool_refused`.
1745 #[serde(rename = "adjust_spool")]
1746 AdjustSpool {
1747 /// Who is asking.
1748 actor: Actor,
1749 /// A scale reading of the spool, in grams, which needs its tare.
1750 #[serde(default, skip_serializing_if = "Option::is_none")]
1751 gross_g: Option<f64>,
1752 /// Why the actor is asking for this.
1753 reason: String,
1754 /// The filament left, in grams.
1755 #[serde(default, skip_serializing_if = "Option::is_none")]
1756 remaining_g: Option<f64>,
1757 /// The spool to correct.
1758 spool_id: SpoolId,
1759 },
1760 /// Retire a spool, after which it refuses every command.
1761 #[serde(rename = "retire_spool")]
1762 RetireSpool {
1763 /// Who is asking.
1764 actor: Actor,
1765 /// Why the actor is asking for this.
1766 reason: String,
1767 /// The spool to retire.
1768 spool_id: SpoolId,
1769 },
1770}
1771
1772/// What a spool command answers, accepted or refused.
1773///
1774/// A refusal is the same shape and deliberately so: the decision carries the
1775/// grant or the ledger's own reason, and the events are the record the
1776/// refusal
1777/// wrote.
1778#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1779pub struct SpoolCommandAnswer {
1780 /// The decision taken on the command.
1781 pub decision: PolicyDecision,
1782 /// Every event it wrote, in the order they were written.
1783 pub events: Vec<EventRecord>,
1784 /// The spool it was about, as the command left it, when there is one.
1785 #[serde(default, skip_serializing_if = "Option::is_none")]
1786 pub spool: Option<SpoolRecord>,
1787}
1788
1789/// A spool command was refused.
1790#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1791pub struct SpoolCommandRejectedPayload {
1792 /// The command, as it was asked for.
1793 pub command: SpoolCommand,
1794 /// The whole decision, carrying which refusal it was.
1795 pub decision: PolicyDecision,
1796}
1797
1798/// A lowercase hyphenated version 7 UUID identifying one registered spool.
1799pub type SpoolId = String;
1800
1801/// A spool was loaded onto a tool, or confirmed as never having left it.
1802#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1803pub struct SpoolLoadedPayload {
1804 /// Who loaded it.
1805 pub actor: Actor,
1806 /// Every mark the load cleared, on either spool.
1807 #[serde(default, skip_serializing_if = "Option::is_none")]
1808 pub cleared_marks: Option<Vec<ClearedMark>>,
1809 /// Why.
1810 pub reason: String,
1811 /// The spool the load swapped off the tool, when it was occupied.
1812 #[serde(default, skip_serializing_if = "Option::is_none")]
1813 pub replaced: Option<SpoolId>,
1814 /// The spool loaded.
1815 pub spool_id: SpoolId,
1816 /// The pending charges the load took, each also its own
1817 /// `filament_consumed` event under its key.
1818 #[serde(default, skip_serializing_if = "Option::is_none")]
1819 pub took_pending: Option<Vec<PendingTaken>>,
1820 /// The tool, in the printer's own numbering.
1821 pub tool: i64,
1822}
1823
1824/// One spool the operator registered, and what is known of it now.
1825#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1826pub struct SpoolRecord {
1827 /// The filament's colour, when the operator gave one.
1828 #[serde(default, skip_serializing_if = "Option::is_none")]
1829 pub color: Option<String>,
1830 /// The material's density, in grams per cubic centimetre; above zero.
1831 pub density_g_cm3: f64,
1832 /// The filament's diameter, in millimetres; above zero.
1833 pub diameter_mm: f64,
1834 /// This spool's identifier, minted when it was registered.
1835 pub id: SpoolId,
1836 /// The net filament on the spool when it was full, in grams; above zero.
1837 pub initial_g: f64,
1838 /// The tool the spool is loaded on, when it is loaded.
1839 #[serde(default, skip_serializing_if = "Option::is_none")]
1840 pub loaded_on_tool: Option<i64>,
1841 /// The material, as given and trimmed, such as `PLA`; never empty.
1842 pub material: String,
1843 /// The operator's own label for the spool; never empty.
1844 pub name: String,
1845 /// When the spool was registered.
1846 pub registered_at: Timestamp,
1847 /// The filament left, in grams.
1848 ///
1849 /// Always the initial figure less every charge plus every correction. A
1850 /// charge is never refused or clamped, so this may go below zero.
1851 pub remaining_g: f64,
1852 /// When the spool was retired, if it has been.
1853 #[serde(default, skip_serializing_if = "Option::is_none")]
1854 pub retired_at: Option<Timestamp>,
1855 /// The empty spool's own weight, in grams, when the operator gave it.
1856 #[serde(default, skip_serializing_if = "Option::is_none")]
1857 pub tare_g: Option<f64>,
1858 /// How far the remaining figure can be trusted.
1859 pub trust: SpoolTrust,
1860 /// When anything about the spool last changed.
1861 pub updated_at: Timestamp,
1862}
1863
1864/// A spool was registered.
1865#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1866pub struct SpoolRegisteredPayload {
1867 /// Who registered it.
1868 pub actor: Actor,
1869 /// Why.
1870 pub reason: String,
1871 /// The spool, as it was registered.
1872 pub spool: SpoolRecord,
1873}
1874
1875/// A spool was retired.
1876#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1877pub struct SpoolRetiredPayload {
1878 /// Who retired it.
1879 pub actor: Actor,
1880 /// Why.
1881 pub reason: String,
1882 /// Its figure as it was retired, in grams.
1883 pub remaining_g: f64,
1884 /// The spool retired.
1885 pub spool_id: SpoolId,
1886}
1887
1888/// How far a spool's remaining figure can be trusted.
1889#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1890#[serde(tag = "state")]
1891pub enum SpoolTrust {
1892 /// Every charge against the spool was taken exactly.
1893 #[serde(rename = "verified")]
1894 Verified,
1895 /// At least one thing happened that could not be charged exactly.
1896 #[serde(rename = "unverified")]
1897 Unverified {
1898 /// Every reason the figure is in doubt, oldest first, at most one per
1899 /// distinct reason; never empty.
1900 marks: Vec<UnverifiedMark>,
1901 },
1902}
1903
1904/// A spool was unloaded from its tool.
1905#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1906pub struct SpoolUnloadedPayload {
1907 /// Who unloaded it.
1908 pub actor: Actor,
1909 /// Why.
1910 pub reason: String,
1911 /// The spool unloaded.
1912 pub spool_id: SpoolId,
1913 /// The tool it left.
1914 pub tool: i64,
1915}
1916
1917/// A spool was marked as one whose figure is in doubt.
1918#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1919pub struct SpoolUnverifiedPayload {
1920 /// Why its figure is in doubt.
1921 pub reason: UnverifiedReason,
1922 /// The spool marked.
1923 pub spool_id: SpoolId,
1924}
1925
1926/// What the spools read answers.
1927///
1928/// `at_a_glance` is one line per spool, in the order `spools` lists them,
1929/// composed here so that what is left on each spool is the first thing a
1930/// reader of either rendering meets rather than a figure inside a whole
1931/// record. Its name is what puts it first: both renderings walk an answer's
1932/// fields in name order, ahead of `pending` and `spools`.
1933#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1934pub struct SpoolsAnswer {
1935 /// One line per spool in `spools`, in the same order.
1936 pub at_a_glance: Vec<String>,
1937 /// Every charge held after a filament change nobody has confirmed, oldest
1938 /// first: what the next spool loaded on that tool is charged.
1939 pub pending: Vec<PendingCharge>,
1940 /// Every spool, retired ones only when asked for, most recently
1941 /// registered
1942 /// first.
1943 pub spools: Vec<SpoolRecord>,
1944}
1945
1946/// What one restart put back the way it found it.
1947///
1948/// A supervisor that has been restarted adopts whatever the store holds
1949/// rather
1950/// than starting empty, and each of these is one of those adoptions. They are
1951/// recorded rather than merely done, because a print that carried on across a
1952/// restart and one that was started again look identical afterwards unless
1953/// the
1954/// history says which happened.
1955#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1956pub enum StartupOutcome {
1957 /// A print left open was adopted as the print this supervisor is
1958 /// watching.
1959 #[serde(rename = "print_adopted")]
1960 PrintAdopted,
1961 /// A session left open was resumed rather than replaced.
1962 #[serde(rename = "session_resumed")]
1963 SessionResumed {
1964 /// The session's own name in the harness.
1965 session_name: String,
1966 },
1967 /// An intervention already past its expiry was expired on start.
1968 #[serde(rename = "intervention_expired")]
1969 InterventionExpired {
1970 /// What it had changed.
1971 adjustable: Adjustable,
1972 /// The intervention that had outlived its bound.
1973 intervention_id: InterventionId,
1974 /// What became of putting the prior value back.
1975 outcome: InterventionOutcome,
1976 },
1977}
1978
1979/// A supervisor reconciled one thing the store held when it started.
1980#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1981pub struct StartupReconciliationPayload {
1982 /// What was reconciled.
1983 pub outcome: StartupOutcome,
1984 /// The print it is about.
1985 pub print_id: PrintId,
1986}
1987
1988/// What a status read answers.
1989#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1990pub struct StatusAnswer {
1991 /// The bounded interventions still in force.
1992 pub interventions: Vec<Intervention>,
1993 /// The job, when a snapshot could be taken.
1994 #[serde(default, skip_serializing_if = "Option::is_none")]
1995 pub job: Option<JobSnapshot>,
1996 /// The print.
1997 pub print: PrintRecord,
1998 /// The printer, when a snapshot could be taken.
1999 #[serde(default, skip_serializing_if = "Option::is_none")]
2000 pub printer: Option<PrinterSnapshot>,
2001 /// The supervision session watching it, when one is.
2002 #[serde(default, skip_serializing_if = "Option::is_none")]
2003 pub session: Option<SupervisionSession>,
2004}
2005
2006/// The supervision session keyed to one print.
2007#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2008pub struct SupervisionSession {
2009 /// Why it was closed, if it was.
2010 #[serde(default, skip_serializing_if = "Option::is_none")]
2011 pub close_reason: Option<String>,
2012 /// When the session was closed, if it was.
2013 #[serde(default, skip_serializing_if = "Option::is_none")]
2014 pub closed_at: Option<Timestamp>,
2015 /// When the session was opened.
2016 pub created_at: Timestamp,
2017 /// The identity the harness ran the session under.
2018 pub harness_identity: String,
2019 /// When the last turn ran.
2020 pub last_turn_at: Timestamp,
2021 /// The print this session watches.
2022 pub print_id: PrintId,
2023 /// The session's own name in the harness.
2024 pub session_name: String,
2025}
2026
2027/// A supervision session was closed.
2028#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2029pub struct SupervisionSessionClosedPayload {
2030 /// Why it was closed.
2031 pub close_reason: String,
2032 /// The session's own name in the harness.
2033 pub session_name: String,
2034}
2035
2036/// A supervision session was opened.
2037#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2038pub struct SupervisionSessionOpenedPayload {
2039 /// The identity the harness ran it under.
2040 pub harness_identity: String,
2041 /// The session's own name in the harness.
2042 pub session_name: String,
2043}
2044
2045/// What a printer history read answers: one page of the printer's own events.
2046#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2047pub struct TimelineAnswer {
2048 /// The events, newest first.
2049 pub events: Vec<EventRecord>,
2050 /// The cursor for the following, older page, given as `before`; absent
2051 /// when there is none.
2052 #[serde(default, skip_serializing_if = "Option::is_none")]
2053 pub next: Option<EventId>,
2054}
2055
2056/// An instant in UTC, as an RFC 3339 string with a zero offset.
2057pub type Timestamp = String;
2058
2059/// The filament one tool feeds, as a length and, when it is known, a volume.
2060#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2061pub struct ToolFilament {
2062 /// The length of filament fed, in millimetres.
2063 pub length_mm: f64,
2064 /// The tool, in the printer's own numbering.
2065 pub tool: i64,
2066 /// The volume of filament fed, in cubic centimetres, when the source
2067 /// reported one.
2068 #[serde(default, skip_serializing_if = "Option::is_none")]
2069 pub volume_cm3: Option<f64>,
2070}
2071
2072/// A print this system never saw was found in the printer's own tally.
2073#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2074pub struct UnaccountedPrintPayload {
2075 /// Whether it was charged against a spool.
2076 pub charged: bool,
2077 /// The file that was printed.
2078 pub file_name: String,
2079 /// When it was printed, when the printer says.
2080 #[serde(default, skip_serializing_if = "Option::is_none")]
2081 pub printed_at: Option<Timestamp>,
2082 /// Whether it completed.
2083 pub success: bool,
2084}
2085
2086/// One reason a spool's figure is in doubt, and since when.
2087#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2088pub struct UnverifiedMark {
2089 /// Why the figure is in doubt.
2090 pub reason: UnverifiedReason,
2091 /// When the spool was marked for it.
2092 pub since: Timestamp,
2093}
2094
2095/// Why a spool's figure is in doubt.
2096#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2097#[serde(tag = "reason")]
2098pub enum UnverifiedReason {
2099 /// A print ran on the spool's tool and nothing could be charged, because
2100 /// the file had no analysis — an SD-card file, for one.
2101 #[serde(rename = "uncharged_print")]
2102 UnchargedPrint {
2103 /// The print nothing could be charged for.
2104 print_id: PrintId,
2105 },
2106 /// A print this system never saw ran and did not complete.
2107 #[serde(rename = "unaccounted_print")]
2108 UnaccountedPrint {
2109 /// The file that was printed.
2110 file_name: String,
2111 /// When it was printed.
2112 printed_at: Timestamp,
2113 },
2114 /// A filament change was signalled and nobody has said which spool is now
2115 /// loaded. The spool was charged up to a position read when the signal
2116 /// was
2117 /// handled.
2118 #[serde(rename = "filament_change_unconfirmed")]
2119 FilamentChangeUnconfirmed {
2120 /// The print the change was signalled during.
2121 print_id: PrintId,
2122 },
2123 /// A filament change was signalled, nobody has said which spool is now
2124 /// loaded, and no fresh position could be read at the signal: the spool
2125 /// was
2126 /// charged only up to the last recorded position, so its figure may be
2127 /// overstated.
2128 #[serde(rename = "filament_change_unconfirmed_position")]
2129 FilamentChangeUnconfirmedPosition {
2130 /// The print the change was signalled during.
2131 print_id: PrintId,
2132 },
2133 /// A file's print tally was reset, and it cannot be told which of the
2134 /// prints since the re-upload were already settled.
2135 #[serde(rename = "tally_reset")]
2136 TallyReset {
2137 /// The file whose tally was reset.
2138 file_name: String,
2139 /// Where the file lives, in the printer's own vocabulary.
2140 origin: String,
2141 },
2142}
2143
2144/// One payload type declared under a kind name, by the domain that owns it.
2145///
2146/// The table from kind name to payload type, as the server declares it: every
2147/// kind below has exactly one implementation here, and a kind this client
2148/// does not know flows through `EventRecord` untouched.
2149pub trait EventPayloadKind: serde::de::DeserializeOwned {
2150 /// The name this payload's events are written down under.
2151 const KIND: &'static str;
2152}
2153
2154impl EventPayloadKind for ActionExecutedPayload {
2155 const KIND: &'static str = "action_executed";
2156}
2157
2158impl EventPayloadKind for ActionRejectedPayload {
2159 const KIND: &'static str = "action_rejected";
2160}
2161
2162impl EventPayloadKind for ActionRequestedPayload {
2163 const KIND: &'static str = "action_requested";
2164}
2165
2166impl EventPayloadKind for AgentAssessmentPayload {
2167 const KIND: &'static str = "agent_assessment";
2168}
2169
2170impl EventPayloadKind for CameraLookPayload {
2171 const KIND: &'static str = "camera_look";
2172}
2173
2174impl EventPayloadKind for ChargePendedPayload {
2175 const KIND: &'static str = "charge_pended";
2176}
2177
2178impl EventPayloadKind for FilamentChangeSignalledPayload {
2179 const KIND: &'static str = "filament_change_signalled";
2180}
2181
2182impl EventPayloadKind for FilamentConsumedPayload {
2183 const KIND: &'static str = "filament_consumed";
2184}
2185
2186impl EventPayloadKind for FileTallyRebaselinedPayload {
2187 const KIND: &'static str = "file_tally_rebaselined";
2188}
2189
2190impl EventPayloadKind for InterventionExpiredPayload {
2191 const KIND: &'static str = "intervention_expired";
2192}
2193
2194impl EventPayloadKind for MalformedExternalEventPayload {
2195 const KIND: &'static str = "malformed_external_event";
2196}
2197
2198impl EventPayloadKind for ObicoFailureAlertPayload {
2199 const KIND: &'static str = "obico_failure_alert";
2200}
2201
2202impl EventPayloadKind for ObicoPrinterNotificationPayload {
2203 const KIND: &'static str = "obico_printer_notification";
2204}
2205
2206impl EventPayloadKind for OperatorAcknowledgementPayload {
2207 const KIND: &'static str = "operator_acknowledgement";
2208}
2209
2210impl EventPayloadKind for PeriodicObservationPayload {
2211 const KIND: &'static str = "periodic_observation";
2212}
2213
2214impl EventPayloadKind for PortFailurePayload {
2215 const KIND: &'static str = "port_failure";
2216}
2217
2218impl EventPayloadKind for PreflightCheckedPayload {
2219 const KIND: &'static str = "preflight_checked";
2220}
2221
2222impl EventPayloadKind for PrintEndedPayload {
2223 const KIND: &'static str = "print_ended";
2224}
2225
2226impl EventPayloadKind for PrintStartedPayload {
2227 const KIND: &'static str = "print_started";
2228}
2229
2230impl EventPayloadKind for PrintUntrackedPayload {
2231 const KIND: &'static str = "print_untracked";
2232}
2233
2234impl EventPayloadKind for SpoolAdjustedPayload {
2235 const KIND: &'static str = "spool_adjusted";
2236}
2237
2238impl EventPayloadKind for SpoolCommandRejectedPayload {
2239 const KIND: &'static str = "spool_command_rejected";
2240}
2241
2242impl EventPayloadKind for SpoolLoadedPayload {
2243 const KIND: &'static str = "spool_loaded";
2244}
2245
2246impl EventPayloadKind for SpoolRegisteredPayload {
2247 const KIND: &'static str = "spool_registered";
2248}
2249
2250impl EventPayloadKind for SpoolRetiredPayload {
2251 const KIND: &'static str = "spool_retired";
2252}
2253
2254impl EventPayloadKind for SpoolUnloadedPayload {
2255 const KIND: &'static str = "spool_unloaded";
2256}
2257
2258impl EventPayloadKind for SpoolUnverifiedPayload {
2259 const KIND: &'static str = "spool_unverified";
2260}
2261
2262impl EventPayloadKind for StartupReconciliationPayload {
2263 const KIND: &'static str = "startup_reconciliation";
2264}
2265
2266impl EventPayloadKind for SupervisionSessionClosedPayload {
2267 const KIND: &'static str = "supervision_session_closed";
2268}
2269
2270impl EventPayloadKind for SupervisionSessionOpenedPayload {
2271 const KIND: &'static str = "supervision_session_opened";
2272}
2273
2274impl EventPayloadKind for UnaccountedPrintPayload {
2275 const KIND: &'static str = "unaccounted_print";
2276}
2277
2278/// Every kind the server declares a payload type for, in name order.
2279pub const EVENT_KINDS: [&str; 31] = [
2280 "action_executed",
2281 "action_rejected",
2282 "action_requested",
2283 "agent_assessment",
2284 "camera_look",
2285 "charge_pended",
2286 "filament_change_signalled",
2287 "filament_consumed",
2288 "file_tally_rebaselined",
2289 "intervention_expired",
2290 "malformed_external_event",
2291 "obico_failure_alert",
2292 "obico_printer_notification",
2293 "operator_acknowledgement",
2294 "periodic_observation",
2295 "port_failure",
2296 "preflight_checked",
2297 "print_ended",
2298 "print_started",
2299 "print_untracked",
2300 "spool_adjusted",
2301 "spool_command_rejected",
2302 "spool_loaded",
2303 "spool_registered",
2304 "spool_retired",
2305 "spool_unloaded",
2306 "spool_unverified",
2307 "startup_reconciliation",
2308 "supervision_session_closed",
2309 "supervision_session_opened",
2310 "unaccounted_print",
2311];
2312
2313impl EventRecord {
2314 /// The payload as `P`, when this event is under the kind `P` declares.
2315 ///
2316 /// Answers `None` for an event of any other kind — one this client knows
2317 /// or one it does not — and the parse failure for an event under the
2318 /// right kind whose payload is not of the type.
2319 #[must_use]
2320 pub fn payload_as<P: EventPayloadKind>(&self) -> Option<Result<P, serde_json::Error>> {
2321 (self.kind == P::KIND).then(|| serde_json::from_value(self.payload.clone()))
2322 }
2323}
2324
2325impl Client {
2326 /// Call `prints` on the configured supervisor.
2327 ///
2328 /// # Errors
2329 ///
2330 /// Returns `ClientError` when the supervisor could not be reached, when
2331 /// it answered something this client cannot read.
2332 // llmlint: ignore[names_match_behavior] See suppressions.toml.
2333 pub fn prints(&self) -> Result<PrintsAnswer, ClientError> {
2334 let target = String::from("/v1/prints");
2335 let asked: Vec<(String, String)> = Vec::new();
2336 let sending: Option<serde_json::Value> = None;
2337 self.call("GET", &target, &asked, sending.as_ref())
2338 }
2339
2340 /// Call `status` on the configured supervisor.
2341 ///
2342 /// # Errors
2343 ///
2344 /// Returns `ClientError` when the supervisor could not be reached, when
2345 /// it answered something this client cannot read.
2346 pub fn status(&self, print_id: &str) -> Result<StatusAnswer, ClientError> {
2347 let target = format!("/v1/prints/{print_id}/status");
2348 let asked: Vec<(String, String)> = Vec::new();
2349 let sending: Option<serde_json::Value> = None;
2350 self.call("GET", &target, &asked, sending.as_ref())
2351 }
2352
2353 /// Call `context` on the configured supervisor.
2354 ///
2355 /// # Errors
2356 ///
2357 /// Returns `ClientError` when the supervisor could not be reached, when
2358 /// it answered something this client cannot read.
2359 pub fn context(&self, print_id: &str) -> Result<ContextAnswer, ClientError> {
2360 let target = format!("/v1/prints/{print_id}/context");
2361 let asked: Vec<(String, String)> = Vec::new();
2362 let sending: Option<serde_json::Value> = None;
2363 self.call("GET", &target, &asked, sending.as_ref())
2364 }
2365
2366 /// Call `image` on the configured supervisor.
2367 ///
2368 /// # Errors
2369 ///
2370 /// Returns `ClientError` when the supervisor could not be reached, when
2371 /// it answered something this client cannot read.
2372 pub fn image(&self, image_id: &str) -> Result<ImageAnswer, ClientError> {
2373 let target = format!("/v1/images/{image_id}");
2374 let asked: Vec<(String, String)> = Vec::new();
2375 let sending: Option<serde_json::Value> = None;
2376 self.call("GET", &target, &asked, sending.as_ref())
2377 }
2378
2379 /// Call `history` on the configured supervisor.
2380 ///
2381 /// # Errors
2382 ///
2383 /// Returns `ClientError` when the supervisor could not be reached, when
2384 /// it answered something this client cannot read.
2385 pub fn history(
2386 &self,
2387 print_id: &str,
2388 limit: Option<i64>,
2389 ) -> Result<HistoryAnswer, ClientError> {
2390 let target = format!("/v1/prints/{print_id}/history");
2391 let mut asked: Vec<(String, String)> = Vec::new();
2392 if let Some(value) = limit {
2393 asked.push(("limit".to_owned(), value.to_string()));
2394 }
2395 let sending: Option<serde_json::Value> = None;
2396 self.call("GET", &target, &asked, sending.as_ref())
2397 }
2398
2399 /// Call `manifest_get` on the configured supervisor.
2400 ///
2401 /// # Errors
2402 ///
2403 /// Returns `ClientError` when the supervisor could not be reached, when
2404 /// it answered something this client cannot read.
2405 pub fn manifest_get(&self, print_id: &str) -> Result<ManifestAnswer, ClientError> {
2406 let target = format!("/v1/prints/{print_id}/manifest");
2407 let asked: Vec<(String, String)> = Vec::new();
2408 let sending: Option<serde_json::Value> = None;
2409 self.call("GET", &target, &asked, sending.as_ref())
2410 }
2411
2412 /// Call `look` on the configured supervisor.
2413 ///
2414 /// # Errors
2415 ///
2416 /// Returns `ClientError` when the supervisor could not be reached, when
2417 /// it answered something this client cannot read.
2418 pub fn look(&self, print_id: &str, wait_s: Option<i64>) -> Result<Look, ClientError> {
2419 let target = format!("/v1/prints/{print_id}/look");
2420 let mut asked: Vec<(String, String)> = Vec::new();
2421 if let Some(value) = wait_s {
2422 asked.push(("wait_s".to_owned(), value.to_string()));
2423 }
2424 let sending: Option<serde_json::Value> = None;
2425 self.call("GET", &target, &asked, sending.as_ref())
2426 }
2427
2428 /// Call `manifest_set` on the configured supervisor.
2429 ///
2430 /// # Errors
2431 ///
2432 /// Returns `ClientError` when the supervisor could not be reached, when
2433 /// it answered something this client cannot read, when this client
2434 /// refuses the call before making it because the reason is empty, and
2435 /// when the policy refused the action — which arrives as
2436 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2437 /// the range allowed.
2438 pub fn manifest_set(
2439 &self,
2440 print_id: &str,
2441 reason: &str,
2442 manifest: &JobManifest,
2443 ) -> Result<ManifestAnswer, ClientError> {
2444 crate::reason_given(reason)?;
2445 let target = format!("/v1/prints/{print_id}/manifest");
2446 let asked: Vec<(String, String)> = Vec::new();
2447 let mut sending = serde_json::Map::new();
2448 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2449 sending.insert("manifest".to_owned(), crate::as_value(&manifest)?);
2450 let sending = Some(serde_json::Value::Object(sending));
2451 self.call("PUT", &target, &asked, sending.as_ref())
2452 }
2453
2454 /// Call `spools` on the configured supervisor.
2455 ///
2456 /// # Errors
2457 ///
2458 /// Returns `ClientError` when the supervisor could not be reached, when
2459 /// it answered something this client cannot read.
2460 pub fn spools(&self, include_retired: Option<bool>) -> Result<SpoolsAnswer, ClientError> {
2461 let target = String::from("/v1/spools");
2462 let mut asked: Vec<(String, String)> = Vec::new();
2463 if let Some(value) = include_retired {
2464 asked.push(("include_retired".to_owned(), value.to_string()));
2465 }
2466 let sending: Option<serde_json::Value> = None;
2467 self.call("GET", &target, &asked, sending.as_ref())
2468 }
2469
2470 /// Call `spool` on the configured supervisor.
2471 ///
2472 /// # Errors
2473 ///
2474 /// Returns `ClientError` when the supervisor could not be reached, when
2475 /// it answered something this client cannot read.
2476 pub fn spool(&self, spool_id: &str) -> Result<SpoolAnswer, ClientError> {
2477 let target = format!("/v1/spools/{spool_id}");
2478 let asked: Vec<(String, String)> = Vec::new();
2479 let sending: Option<serde_json::Value> = None;
2480 self.call("GET", &target, &asked, sending.as_ref())
2481 }
2482
2483 /// Call `printer_history` on the configured supervisor.
2484 ///
2485 /// # Errors
2486 ///
2487 /// Returns `ClientError` when the supervisor could not be reached, when
2488 /// it answered something this client cannot read.
2489 pub fn printer_history(
2490 &self,
2491 kinds: Option<Vec<String>>,
2492 since: Option<String>,
2493 until: Option<String>,
2494 spool_id: Option<String>,
2495 before: Option<String>,
2496 limit: Option<i64>,
2497 ) -> Result<TimelineAnswer, ClientError> {
2498 let target = String::from("/v1/history");
2499 let mut asked: Vec<(String, String)> = Vec::new();
2500 for value in kinds.into_iter().flatten() {
2501 asked.push(("kinds".to_owned(), value));
2502 }
2503 if let Some(value) = since {
2504 asked.push(("since".to_owned(), value));
2505 }
2506 if let Some(value) = until {
2507 asked.push(("until".to_owned(), value));
2508 }
2509 if let Some(value) = spool_id {
2510 asked.push(("spool_id".to_owned(), value));
2511 }
2512 if let Some(value) = before {
2513 asked.push(("before".to_owned(), value));
2514 }
2515 if let Some(value) = limit {
2516 asked.push(("limit".to_owned(), value.to_string()));
2517 }
2518 let sending: Option<serde_json::Value> = None;
2519 self.call("GET", &target, &asked, sending.as_ref())
2520 }
2521
2522 /// Call `preflight` on the configured supervisor.
2523 ///
2524 /// # Errors
2525 ///
2526 /// Returns `ClientError` when the supervisor could not be reached, when
2527 /// it answered something this client cannot read.
2528 pub fn preflight(&self, file_name: &str) -> Result<PreflightAnswer, ClientError> {
2529 let target = String::from("/v1/preflight");
2530 let asked: Vec<(String, String)> = vec![("file_name".to_owned(), file_name.to_owned())];
2531 let sending: Option<serde_json::Value> = None;
2532 self.call("GET", &target, &asked, sending.as_ref())
2533 }
2534
2535 /// Call `pause` on the configured supervisor.
2536 ///
2537 /// # Errors
2538 ///
2539 /// Returns `ClientError` when the supervisor could not be reached, when
2540 /// it answered something this client cannot read, when this client
2541 /// refuses the call before making it because the reason is empty, and
2542 /// when the policy refused the action — which arrives as
2543 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2544 /// the range allowed.
2545 pub fn pause(&self, print_id: &str, reason: &str) -> Result<ActionAnswer, ClientError> {
2546 crate::reason_given(reason)?;
2547 let target = format!("/v1/prints/{print_id}/actions/pause");
2548 let asked: Vec<(String, String)> = Vec::new();
2549 let mut sending = serde_json::Map::new();
2550 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2551 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2552 let sending = Some(serde_json::Value::Object(sending));
2553 self.call("POST", &target, &asked, sending.as_ref())
2554 }
2555
2556 /// Call `resume` on the configured supervisor.
2557 ///
2558 /// # Errors
2559 ///
2560 /// Returns `ClientError` when the supervisor could not be reached, when
2561 /// it answered something this client cannot read, when this client
2562 /// refuses the call before making it because the reason is empty, and
2563 /// when the policy refused the action — which arrives as
2564 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2565 /// the range allowed.
2566 pub fn resume(&self, print_id: &str, reason: &str) -> Result<ActionAnswer, ClientError> {
2567 crate::reason_given(reason)?;
2568 let target = format!("/v1/prints/{print_id}/actions/resume");
2569 let asked: Vec<(String, String)> = Vec::new();
2570 let mut sending = serde_json::Map::new();
2571 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2572 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2573 let sending = Some(serde_json::Value::Object(sending));
2574 self.call("POST", &target, &asked, sending.as_ref())
2575 }
2576
2577 /// Call `cancel` on the configured supervisor.
2578 ///
2579 /// # Errors
2580 ///
2581 /// Returns `ClientError` when the supervisor could not be reached, when
2582 /// it answered something this client cannot read, when this client
2583 /// refuses the call before making it because the reason is empty, and
2584 /// when the policy refused the action — which arrives as
2585 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2586 /// the range allowed.
2587 pub fn cancel(&self, print_id: &str, reason: &str) -> Result<ActionAnswer, ClientError> {
2588 crate::reason_given(reason)?;
2589 let target = format!("/v1/prints/{print_id}/actions/cancel");
2590 let asked: Vec<(String, String)> = Vec::new();
2591 let mut sending = serde_json::Map::new();
2592 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2593 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2594 let sending = Some(serde_json::Value::Object(sending));
2595 self.call("POST", &target, &asked, sending.as_ref())
2596 }
2597
2598 /// Call `start_print` on the configured supervisor.
2599 ///
2600 /// # Errors
2601 ///
2602 /// Returns `ClientError` when the supervisor could not be reached, when
2603 /// it answered something this client cannot read, when this client
2604 /// refuses the call before making it because the reason is empty, and
2605 /// when the policy refused the action — which arrives as
2606 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2607 /// the range allowed.
2608 pub fn start_print(
2609 &self,
2610 print_id: &str,
2611 file_name: &FileName,
2612 manifest: &JobManifest,
2613 reason: &str,
2614 override_filament_check: Option<bool>,
2615 ) -> Result<ActionAnswer, ClientError> {
2616 crate::reason_given(reason)?;
2617 let target = format!("/v1/prints/{print_id}/actions/start_print");
2618 let asked: Vec<(String, String)> = Vec::new();
2619 let mut sending = serde_json::Map::new();
2620 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2621 sending.insert("file_name".to_owned(), crate::as_value(&file_name)?);
2622 sending.insert("manifest".to_owned(), crate::as_value(&manifest)?);
2623 if let Some(value) = override_filament_check {
2624 sending.insert(
2625 "override_filament_check".to_owned(),
2626 crate::as_value(&value)?,
2627 );
2628 }
2629 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2630 let sending = Some(serde_json::Value::Object(sending));
2631 self.call("POST", &target, &asked, sending.as_ref())
2632 }
2633
2634 /// Call `set_feedrate_factor` on the configured supervisor.
2635 ///
2636 /// # Errors
2637 ///
2638 /// Returns `ClientError` when the supervisor could not be reached, when
2639 /// it answered something this client cannot read, when this client
2640 /// refuses the call before making it because the reason is empty, and
2641 /// when the policy refused the action — which arrives as
2642 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2643 /// the range allowed.
2644 pub fn set_feedrate_factor(
2645 &self,
2646 print_id: &str,
2647 factor: f64,
2648 reason: &str,
2649 duration_s: Option<i64>,
2650 ) -> Result<ActionAnswer, ClientError> {
2651 crate::reason_given(reason)?;
2652 let target = format!("/v1/prints/{print_id}/actions/set_feedrate_factor");
2653 let asked: Vec<(String, String)> = Vec::new();
2654 let mut sending = serde_json::Map::new();
2655 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2656 if let Some(value) = duration_s {
2657 sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
2658 }
2659 sending.insert("factor".to_owned(), crate::as_value(&factor)?);
2660 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2661 let sending = Some(serde_json::Value::Object(sending));
2662 self.call("POST", &target, &asked, sending.as_ref())
2663 }
2664
2665 /// Call `set_flowrate_factor` on the configured supervisor.
2666 ///
2667 /// # Errors
2668 ///
2669 /// Returns `ClientError` when the supervisor could not be reached, when
2670 /// it answered something this client cannot read, when this client
2671 /// refuses the call before making it because the reason is empty, and
2672 /// when the policy refused the action — which arrives as
2673 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2674 /// the range allowed.
2675 pub fn set_flowrate_factor(
2676 &self,
2677 print_id: &str,
2678 factor: f64,
2679 reason: &str,
2680 duration_s: Option<i64>,
2681 ) -> Result<ActionAnswer, ClientError> {
2682 crate::reason_given(reason)?;
2683 let target = format!("/v1/prints/{print_id}/actions/set_flowrate_factor");
2684 let asked: Vec<(String, String)> = Vec::new();
2685 let mut sending = serde_json::Map::new();
2686 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2687 if let Some(value) = duration_s {
2688 sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
2689 }
2690 sending.insert("factor".to_owned(), crate::as_value(&factor)?);
2691 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2692 let sending = Some(serde_json::Value::Object(sending));
2693 self.call("POST", &target, &asked, sending.as_ref())
2694 }
2695
2696 /// Call `set_tool_target_c` on the configured supervisor.
2697 ///
2698 /// # Errors
2699 ///
2700 /// Returns `ClientError` when the supervisor could not be reached, when
2701 /// it answered something this client cannot read, when this client
2702 /// refuses the call before making it because the reason is empty, and
2703 /// when the policy refused the action — which arrives as
2704 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2705 /// the range allowed.
2706 pub fn set_tool_target_c(
2707 &self,
2708 print_id: &str,
2709 reason: &str,
2710 target_c: f64,
2711 tool: i64,
2712 duration_s: Option<i64>,
2713 ) -> Result<ActionAnswer, ClientError> {
2714 crate::reason_given(reason)?;
2715 let target = format!("/v1/prints/{print_id}/actions/set_tool_target_c");
2716 let asked: Vec<(String, String)> = Vec::new();
2717 let mut sending = serde_json::Map::new();
2718 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2719 if let Some(value) = duration_s {
2720 sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
2721 }
2722 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2723 sending.insert("target_c".to_owned(), crate::as_value(&target_c)?);
2724 sending.insert("tool".to_owned(), crate::as_value(&tool)?);
2725 let sending = Some(serde_json::Value::Object(sending));
2726 self.call("POST", &target, &asked, sending.as_ref())
2727 }
2728
2729 /// Call `set_bed_target_c` on the configured supervisor.
2730 ///
2731 /// # Errors
2732 ///
2733 /// Returns `ClientError` when the supervisor could not be reached, when
2734 /// it answered something this client cannot read, when this client
2735 /// refuses the call before making it because the reason is empty, and
2736 /// when the policy refused the action — which arrives as
2737 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2738 /// the range allowed.
2739 pub fn set_bed_target_c(
2740 &self,
2741 print_id: &str,
2742 reason: &str,
2743 target_c: f64,
2744 duration_s: Option<i64>,
2745 ) -> Result<ActionAnswer, ClientError> {
2746 crate::reason_given(reason)?;
2747 let target = format!("/v1/prints/{print_id}/actions/set_bed_target_c");
2748 let asked: Vec<(String, String)> = Vec::new();
2749 let mut sending = serde_json::Map::new();
2750 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2751 if let Some(value) = duration_s {
2752 sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
2753 }
2754 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2755 sending.insert("target_c".to_owned(), crate::as_value(&target_c)?);
2756 let sending = Some(serde_json::Value::Object(sending));
2757 self.call("POST", &target, &asked, sending.as_ref())
2758 }
2759
2760 /// Call `set_fan_percent` on the configured supervisor.
2761 ///
2762 /// # Errors
2763 ///
2764 /// Returns `ClientError` when the supervisor could not be reached, when
2765 /// it answered something this client cannot read, when this client
2766 /// refuses the call before making it because the reason is empty, and
2767 /// when the policy refused the action — which arrives as
2768 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2769 /// the range allowed.
2770 pub fn set_fan_percent(
2771 &self,
2772 print_id: &str,
2773 percent: f64,
2774 reason: &str,
2775 duration_s: Option<i64>,
2776 ) -> Result<ActionAnswer, ClientError> {
2777 crate::reason_given(reason)?;
2778 let target = format!("/v1/prints/{print_id}/actions/set_fan_percent");
2779 let asked: Vec<(String, String)> = Vec::new();
2780 let mut sending = serde_json::Map::new();
2781 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2782 if let Some(value) = duration_s {
2783 sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
2784 }
2785 sending.insert("percent".to_owned(), crate::as_value(&percent)?);
2786 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2787 let sending = Some(serde_json::Value::Object(sending));
2788 self.call("POST", &target, &asked, sending.as_ref())
2789 }
2790
2791 /// Call `acknowledge_failure` on the configured supervisor.
2792 ///
2793 /// # Errors
2794 ///
2795 /// Returns `ClientError` when the supervisor could not be reached, when
2796 /// it answered something this client cannot read, when this client
2797 /// refuses the call before making it because the reason is empty, and
2798 /// when the policy refused the action — which arrives as
2799 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2800 /// the range allowed.
2801 pub fn acknowledge_failure(
2802 &self,
2803 print_id: &str,
2804 disposition: &AcknowledgementDisposition,
2805 event_id: &EventId,
2806 reason: &str,
2807 ) -> Result<ActionAnswer, ClientError> {
2808 crate::reason_given(reason)?;
2809 let target = format!("/v1/prints/{print_id}/actions/acknowledge_failure");
2810 let asked: Vec<(String, String)> = Vec::new();
2811 let mut sending = serde_json::Map::new();
2812 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2813 sending.insert("disposition".to_owned(), crate::as_value(&disposition)?);
2814 sending.insert("event_id".to_owned(), crate::as_value(&event_id)?);
2815 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2816 let sending = Some(serde_json::Value::Object(sending));
2817 self.call("POST", &target, &asked, sending.as_ref())
2818 }
2819
2820 /// Call `register_spool` on the configured supervisor.
2821 ///
2822 /// # Errors
2823 ///
2824 /// Returns `ClientError` when the supervisor could not be reached, when
2825 /// it answered something this client cannot read, when this client
2826 /// refuses the call before making it because the reason is empty, and
2827 /// when the policy refused the action — which arrives as
2828 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2829 /// the range allowed.
2830 // One argument per value the operation declares, as every client takes them; suppressions.toml has the reason.
2831 #[expect(clippy::too_many_arguments)]
2832 pub fn register_spool(
2833 &self,
2834 initial_g: f64,
2835 material: &str,
2836 name: &str,
2837 reason: &str,
2838 color: Option<String>,
2839 density_g_cm3: Option<f64>,
2840 diameter_mm: Option<f64>,
2841 remaining_g: Option<f64>,
2842 tare_g: Option<f64>,
2843 ) -> Result<SpoolCommandAnswer, ClientError> {
2844 crate::reason_given(reason)?;
2845 let target = String::from("/v1/spools/actions/register_spool");
2846 let asked: Vec<(String, String)> = Vec::new();
2847 let mut sending = serde_json::Map::new();
2848 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2849 if let Some(value) = color {
2850 sending.insert("color".to_owned(), crate::as_value(&value)?);
2851 }
2852 if let Some(value) = density_g_cm3 {
2853 sending.insert("density_g_cm3".to_owned(), crate::as_value(&value)?);
2854 }
2855 if let Some(value) = diameter_mm {
2856 sending.insert("diameter_mm".to_owned(), crate::as_value(&value)?);
2857 }
2858 sending.insert("initial_g".to_owned(), crate::as_value(&initial_g)?);
2859 sending.insert("material".to_owned(), crate::as_value(&material)?);
2860 sending.insert("name".to_owned(), crate::as_value(&name)?);
2861 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2862 if let Some(value) = remaining_g {
2863 sending.insert("remaining_g".to_owned(), crate::as_value(&value)?);
2864 }
2865 if let Some(value) = tare_g {
2866 sending.insert("tare_g".to_owned(), crate::as_value(&value)?);
2867 }
2868 let sending = Some(serde_json::Value::Object(sending));
2869 self.call("POST", &target, &asked, sending.as_ref())
2870 }
2871
2872 /// Call `load_spool` on the configured supervisor.
2873 ///
2874 /// # Errors
2875 ///
2876 /// Returns `ClientError` when the supervisor could not be reached, when
2877 /// it answered something this client cannot read, when this client
2878 /// refuses the call before making it because the reason is empty, and
2879 /// when the policy refused the action — which arrives as
2880 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2881 /// the range allowed.
2882 pub fn load_spool(
2883 &self,
2884 spool_id: &str,
2885 reason: &str,
2886 tool: i64,
2887 ) -> Result<SpoolCommandAnswer, ClientError> {
2888 crate::reason_given(reason)?;
2889 let target = format!("/v1/spools/{spool_id}/actions/load_spool");
2890 let asked: Vec<(String, String)> = Vec::new();
2891 let mut sending = serde_json::Map::new();
2892 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2893 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2894 sending.insert("tool".to_owned(), crate::as_value(&tool)?);
2895 let sending = Some(serde_json::Value::Object(sending));
2896 self.call("POST", &target, &asked, sending.as_ref())
2897 }
2898
2899 /// Call `unload_spool` on the configured supervisor.
2900 ///
2901 /// # Errors
2902 ///
2903 /// Returns `ClientError` when the supervisor could not be reached, when
2904 /// it answered something this client cannot read, when this client
2905 /// refuses the call before making it because the reason is empty, and
2906 /// when the policy refused the action — which arrives as
2907 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2908 /// the range allowed.
2909 pub fn unload_spool(
2910 &self,
2911 spool_id: &str,
2912 reason: &str,
2913 ) -> Result<SpoolCommandAnswer, ClientError> {
2914 crate::reason_given(reason)?;
2915 let target = format!("/v1/spools/{spool_id}/actions/unload_spool");
2916 let asked: Vec<(String, String)> = Vec::new();
2917 let mut sending = serde_json::Map::new();
2918 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2919 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2920 let sending = Some(serde_json::Value::Object(sending));
2921 self.call("POST", &target, &asked, sending.as_ref())
2922 }
2923
2924 /// Call `adjust_spool` on the configured supervisor.
2925 ///
2926 /// # Errors
2927 ///
2928 /// Returns `ClientError` when the supervisor could not be reached, when
2929 /// it answered something this client cannot read, when this client
2930 /// refuses the call before making it because the reason is empty, and
2931 /// when the policy refused the action — which arrives as
2932 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2933 /// the range allowed.
2934 pub fn adjust_spool(
2935 &self,
2936 spool_id: &str,
2937 reason: &str,
2938 gross_g: Option<f64>,
2939 remaining_g: Option<f64>,
2940 ) -> Result<SpoolCommandAnswer, ClientError> {
2941 crate::reason_given(reason)?;
2942 let target = format!("/v1/spools/{spool_id}/actions/adjust_spool");
2943 let asked: Vec<(String, String)> = Vec::new();
2944 let mut sending = serde_json::Map::new();
2945 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2946 if let Some(value) = gross_g {
2947 sending.insert("gross_g".to_owned(), crate::as_value(&value)?);
2948 }
2949 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2950 if let Some(value) = remaining_g {
2951 sending.insert("remaining_g".to_owned(), crate::as_value(&value)?);
2952 }
2953 let sending = Some(serde_json::Value::Object(sending));
2954 self.call("POST", &target, &asked, sending.as_ref())
2955 }
2956
2957 /// Call `retire_spool` on the configured supervisor.
2958 ///
2959 /// # Errors
2960 ///
2961 /// Returns `ClientError` when the supervisor could not be reached, when
2962 /// it answered something this client cannot read, when this client
2963 /// refuses the call before making it because the reason is empty, and
2964 /// when the policy refused the action — which arrives as
2965 /// `ClientError::Rejected`, carrying the reason, the value asked for and
2966 /// the range allowed.
2967 pub fn retire_spool(
2968 &self,
2969 spool_id: &str,
2970 reason: &str,
2971 ) -> Result<SpoolCommandAnswer, ClientError> {
2972 crate::reason_given(reason)?;
2973 let target = format!("/v1/spools/{spool_id}/actions/retire_spool");
2974 let asked: Vec<(String, String)> = Vec::new();
2975 let mut sending = serde_json::Map::new();
2976 sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
2977 sending.insert("reason".to_owned(), crate::as_value(&reason)?);
2978 let sending = Some(serde_json::Value::Object(sending));
2979 self.call("POST", &target, &asked, sending.as_ref())
2980 }
2981}