Skip to main content

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; 17] = [
23    "prints",
24    "status",
25    "context",
26    "image",
27    "history",
28    "manifest_get",
29    "manifest_set",
30    "pause",
31    "resume",
32    "cancel",
33    "start_print",
34    "set_feedrate_factor",
35    "set_flowrate_factor",
36    "set_tool_target_c",
37    "set_bed_target_c",
38    "set_fan_percent",
39    "acknowledge_failure",
40];
41
42/// What an operator's acknowledgement of a failure event asks for next.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
44pub enum AcknowledgementDisposition {
45    /// Carry on printing.
46    #[serde(rename = "continue")]
47    Continue,
48    /// Carry on printing, watched more closely.
49    #[serde(rename = "watch")]
50    Watch,
51    /// Stop the print.
52    #[serde(rename = "stop")]
53    Stop,
54}
55
56/// What one mutating request left behind it.
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct ActionAnswer {
59    /// The bounded intervention it opened, when it opened one.
60    #[serde(default, skip_serializing_if = "Option::is_none")]
61    pub intervention: Option<Intervention>,
62    /// What the printer said, when the request reached it and it refused.
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub printer_refusal: Option<String>,
65    /// The record of the request and the decision taken on it. A rejected
66    /// request's rejection is here, carrying its reason, the value asked for
67    /// and the range allowed, so a caller can ask again inside the range.
68    pub record: ActionRecord,
69}
70
71/// An accepted action reached the printer.
72#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
73pub struct ActionExecutedPayload {
74    /// The action's identifier.
75    pub action_id: ActionId,
76    /// The bounded intervention it opened, when it opened one.
77    #[serde(default, skip_serializing_if = "Option::is_none")]
78    pub intervention_id: Option<InterventionId>,
79}
80
81/// A lowercase hyphenated version 7 UUID identifying one requested action.
82pub type ActionId = String;
83
84/// One action of the closed vocabulary, named without its payload.
85///
86/// This is what a safety envelope grants and what a policy rejection names;
87/// the
88/// payload lives on `PrintAction` itself.
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
90pub enum ActionKind {
91    /// Pause the print.
92    #[serde(rename = "pause")]
93    Pause,
94    /// Resume the print.
95    #[serde(rename = "resume")]
96    Resume,
97    /// Cancel the print.
98    #[serde(rename = "cancel")]
99    Cancel,
100    /// Start a print of a named file.
101    #[serde(rename = "start_print")]
102    StartPrint,
103    /// Set the feedrate factor.
104    #[serde(rename = "set_feedrate_factor")]
105    SetFeedrateFactor,
106    /// Set the flowrate factor.
107    #[serde(rename = "set_flowrate_factor")]
108    SetFlowrateFactor,
109    /// Set a tool's target temperature.
110    #[serde(rename = "set_tool_target_c")]
111    SetToolTargetC,
112    /// Set the bed's target temperature.
113    #[serde(rename = "set_bed_target_c")]
114    SetBedTargetC,
115    /// Set the fan percentage.
116    #[serde(rename = "set_fan_percent")]
117    SetFanPercent,
118    /// Acknowledge a failure event.
119    #[serde(rename = "acknowledge_failure")]
120    AcknowledgeFailure,
121}
122
123/// One request, the decision taken on it, and what became of it.
124///
125/// `executed_at` and `outcome` are both optional and are absent together: a
126/// record is written when the decision is taken, which is before — and, for a
127/// rejected request, instead of — anything reaching the printer.
128#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
129pub struct ActionRecord {
130    /// The decision policy took on it.
131    pub decision: PolicyDecision,
132    /// When it reached the printer, if it did.
133    #[serde(default, skip_serializing_if = "Option::is_none")]
134    pub executed_at: Option<Timestamp>,
135    /// This record's identifier, minted by the store.
136    pub id: ActionId,
137    /// What the printer made of it, if it reached the printer.
138    #[serde(default, skip_serializing_if = "Option::is_none")]
139    pub outcome: Option<ExecutionOutcome>,
140    /// The print this request was made against.
141    pub print_id: PrintId,
142    /// The request itself.
143    pub request: ActionRequest,
144}
145
146/// Policy refused an action.
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
148pub struct ActionRejectedPayload {
149    /// The action's identifier.
150    pub action_id: ActionId,
151    /// The whole decision, carrying which rejection it was.
152    pub decision: PolicyDecision,
153}
154
155/// One request an actor made, at the instant it made it.
156#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
157pub struct ActionRequest {
158    /// What was asked for.
159    pub action: PrintAction,
160    /// Who asked.
161    pub actor: Actor,
162    /// When they asked.
163    pub requested_at: Timestamp,
164}
165
166/// An actor asked for an action.
167#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
168pub struct ActionRequestedPayload {
169    /// What was asked for.
170    pub action: PrintAction,
171    /// The action's identifier.
172    pub action_id: ActionId,
173    /// Who asked.
174    pub actor: Actor,
175}
176
177/// Who asked for something.
178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
179pub enum Actor {
180    /// The supervising agent, naming its session.
181    #[serde(rename = "agent")]
182    Agent {
183        /// The supervision session the agent is acting in.
184        session_name: String,
185    },
186    /// A person.
187    #[serde(rename = "operator")]
188    Operator,
189    /// The supervisor itself.
190    #[serde(rename = "system")]
191    System,
192}
193
194/// An actor class, which is what a safety envelope grants actions to.
195#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
196pub enum ActorClass {
197    /// The supervising agent.
198    #[serde(rename = "agent")]
199    Agent,
200    /// A person.
201    #[serde(rename = "operator")]
202    Operator,
203    /// The supervisor itself.
204    #[serde(rename = "system")]
205    System,
206}
207
208/// One thing an adjustment may change.
209pub type Adjustable = String;
210
211/// The agent's written record of one supervision turn.
212///
213/// This is deliberately not how the agent acts: acting is a
214/// `PrintAction` that policy rules on.
215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
216pub struct AgentAssessment {
217    /// How sure the agent is.
218    pub confidence: Confidence,
219    /// What the agent did.
220    pub did: String,
221    /// Whether the agent is escalating to a person.
222    pub escalating: bool,
223    /// Whether the print should carry on.
224    pub should_continue: bool,
225    /// One line saying what is happening.
226    pub summary: String,
227    /// Why it did it.
228    pub why: String,
229}
230
231/// The agent wrote down what it made of a turn.
232#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
233pub struct AgentAssessmentPayload {
234    /// What the agent answered with.
235    pub assessment: AgentAssessment,
236    /// The session the turn ran in.
237    pub session_name: String,
238}
239
240/// How sure the agent is.
241///
242/// A closed vocabulary rather than a number, because a number invites a
243/// precision the agent does not have.
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
245pub enum Confidence {
246    /// Not sure.
247    #[serde(rename = "low")]
248    Low,
249    /// Fairly sure.
250    #[serde(rename = "medium")]
251    Medium,
252    /// Sure.
253    #[serde(rename = "high")]
254    High,
255}
256
257/// What a context read answers.
258///
259/// The latest image is **materialized** here rather than left as the handle
260/// `PrintContext` carries: the one thing a supervision turn does with an
261/// image is look at it, and a handle is not something anything can open. The
262/// path is absolute on this server's own filesystem, exactly as
263/// `ImageAnswer`'s is, and is absent when there is no image or when the
264/// record is intact and the file is not.
265#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
266pub struct ContextAnswer {
267    /// Everything a supervision turn is given about the print.
268    pub context: PrintContext,
269    /// Where the latest image's bytes are, absolute on this host.
270    #[serde(default, skip_serializing_if = "Option::is_none")]
271    pub image_path: Option<String>,
272}
273
274/// The envelope intersected with the print's manifest.
275///
276/// This is what context reports, so that the agent can see its own limits
277/// before it asks. Computing one is the supervision core's; this crate
278/// declares
279/// the shape and nothing that produces it.
280#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
281pub struct EffectiveBounds {
282    /// The range each adjustable may be set to, inclusive.
283    pub allowed: BTreeMap<String, Range>,
284}
285
286/// What this server answers when it will not do what it was asked.
287#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
288pub struct ErrorAnswer {
289    /// One line saying why, in the words of whatever refused it.
290    pub error: String,
291}
292
293/// A lowercase hyphenated version 7 UUID identifying one event.
294pub type EventId = String;
295
296/// The name one kind of event is written down under: lowercase `snake_case`,
297/// declared by the domain that owns the event.
298pub type EventKind = String;
299
300/// One event, as the store holds it and the server serves it.
301///
302/// `raw` holds the bytes exactly as received for an externally sourced event
303/// and is absent for an internally raised one — it is what makes the history
304/// auditable when a normalization turns out to be wrong. `print_id` is
305/// optional, because an externally sourced event may name no print this
306/// system
307/// knows.
308#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
309pub struct EventRecord {
310    /// This event's identifier, minted by the store.
311    pub id: EventId,
312    /// The image it arrived with, when it arrived with one.
313    #[serde(default, skip_serializing_if = "Option::is_none")]
314    pub image: Option<ImageRef>,
315    /// Which event this is.
316    pub kind: EventKind,
317    /// What it carries, in the form its kind declares.
318    pub payload: serde_json::Value,
319    /// The print it belongs to, when it belongs to one.
320    #[serde(default, skip_serializing_if = "Option::is_none")]
321    pub print_id: Option<PrintId>,
322    /// The bytes exactly as received, for an externally sourced event.
323    #[serde(default, skip_serializing_if = "Option::is_none")]
324    pub raw: Option<RawBytes>,
325    /// When it was received.
326    pub received_at: Timestamp,
327    /// Where it came from.
328    pub source: EventSource,
329}
330
331/// Where an event came from, as the bare string the domain that raised it
332/// declares for itself.
333pub type EventSource = String;
334
335/// What happened when an accepted action reached the printer.
336#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
337pub enum ExecutionOutcome {
338    /// The printer took it.
339    #[serde(rename = "succeeded")]
340    Succeeded,
341    /// The printer did not, for this reason.
342    #[serde(rename = "failed")]
343    Failed {
344        /// Why it failed.
345        reason: String,
346    },
347}
348
349/// A file name a printer's own file API can be asked for: no path separator,
350/// no NUL byte, no `.` or `..` segment, no drive prefix, and not empty.
351pub type FileName = String;
352
353/// One heater, as a source reported it.
354///
355/// Every field is optional, because a source that reports no heater at all
356/// reports none of these; each is a plausibility-ranged reported value in
357/// degrees Celsius.
358#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
359pub struct HeaterSnapshot {
360    /// The temperature the heater is at.
361    #[serde(default, skip_serializing_if = "Option::is_none")]
362    pub actual_c: Option<Reported>,
363    /// The offset applied to this heater's target.
364    #[serde(default, skip_serializing_if = "Option::is_none")]
365    pub offset_c: Option<Reported>,
366    /// The temperature the heater is driving towards.
367    #[serde(default, skip_serializing_if = "Option::is_none")]
368    pub target_c: Option<Reported>,
369}
370
371/// What a history read answers.
372#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
373pub struct HistoryAnswer {
374    /// The print's events, newest first.
375    pub events: Vec<EventRecord>,
376}
377
378/// What an image read answers.
379///
380/// The path is absolute on this server's own filesystem, and is the whole of
381/// the answer about the bytes: nothing here renders them, encodes them or
382/// serves them. It is absent when the record is intact and the file is not,
383/// which is a different answer from there being no such image.
384#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
385pub struct ImageAnswer {
386    /// Where its bytes are, absolute on this host.
387    #[serde(default, skip_serializing_if = "Option::is_none")]
388    pub path: Option<String>,
389    /// The record.
390    pub record: ImageRecord,
391}
392
393/// A lowercase hyphenated version 7 UUID identifying one image.
394pub type ImageId = String;
395
396/// One image, stored beside the event it arrived with.
397///
398/// `relative_path` is relative to the configured state directory, so that the
399/// store stays portable. Materializing an image resolves that to an absolute
400/// path; nothing in this system renders image bytes into JSON.
401#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
402pub struct ImageRecord {
403    /// How many bytes it is.
404    pub byte_len: i64,
405    /// The content type it was served as.
406    pub content_type: String,
407    /// The event it arrived with.
408    pub event_id: EventId,
409    /// When it was fetched.
410    pub fetched_at: Timestamp,
411    /// This image's identifier, minted by the store.
412    pub id: ImageId,
413    /// The print it belongs to.
414    pub print_id: PrintId,
415    /// Where it lives, relative to the configured state directory.
416    pub relative_path: String,
417    /// The SHA-256 of its bytes, lowercase hexadecimal.
418    pub sha256: String,
419    /// Where it was fetched from, when it was fetched from somewhere.
420    #[serde(default, skip_serializing_if = "Option::is_none")]
421    pub source_url: Option<String>,
422}
423
424/// The handle an image travels in context under.
425#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
426pub struct ImageRef {
427    /// The image's identifier.
428    pub id: ImageId,
429    /// The SHA-256 of its bytes, lowercase hexadecimal.
430    pub sha256: String,
431}
432
433/// One adjustment made for a bounded time.
434///
435/// `prior_value` is read from the printer snapshot taken before the change,
436/// and
437/// is absent when the printer reported none — in which case expiry restores
438/// nothing and the outcome says so rather than guessing a default.
439#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
440pub struct Intervention {
441    /// The action that asked for it.
442    pub action_id: ActionId,
443    /// What it changed.
444    pub adjustable: Adjustable,
445    /// When it was applied.
446    pub applied_at: Timestamp,
447    /// What it was changed to.
448    pub applied_value: f64,
449    /// When it stops standing.
450    pub expires_at: Timestamp,
451    /// This intervention's identifier, minted by the store.
452    pub id: InterventionId,
453    /// What became of it.
454    pub outcome: InterventionOutcome,
455    /// The print it was made against.
456    pub print_id: PrintId,
457    /// What the printer reported before the change, if it reported anything.
458    #[serde(default, skip_serializing_if = "Option::is_none")]
459    pub prior_value: Option<f64>,
460    /// When the prior value was put back, if it was.
461    #[serde(default, skip_serializing_if = "Option::is_none")]
462    pub restored_at: Option<Timestamp>,
463}
464
465/// A bounded intervention expired.
466#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
467pub struct InterventionExpiredPayload {
468    /// What it had changed.
469    pub adjustable: Adjustable,
470    /// The intervention's identifier.
471    pub intervention_id: InterventionId,
472    /// What became of it.
473    pub outcome: InterventionOutcome,
474}
475
476/// A lowercase hyphenated version 7 UUID identifying one bounded
477/// intervention.
478pub type InterventionId = String;
479
480/// What became of a bounded change.
481#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
482pub enum InterventionOutcome {
483    /// It is still in force.
484    #[serde(rename = "still_active")]
485    StillActive,
486    /// The prior value was put back.
487    #[serde(rename = "restored")]
488    Restored,
489    /// There was no prior value to put back.
490    #[serde(rename = "restore_unavailable")]
491    RestoreUnavailable,
492    /// Putting the prior value back failed.
493    #[serde(rename = "restore_failed")]
494    RestoreFailed {
495        /// Why it failed.
496        reason: String,
497    },
498    /// Another intervention replaced it before it expired.
499    #[serde(rename = "superseded")]
500    Superseded {
501        /// The intervention that replaced it.
502        by: InterventionId,
503    },
504}
505
506/// What a sliced job declares about itself and about what may be adjusted.
507///
508/// An adjustable the manifest does not name takes the envelope's own range; a
509/// manifest range wider than the envelope's is narrowed to the envelope's and
510/// the narrowing is recorded on the print. A manifest may only narrow.
511#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
512pub struct JobManifest {
513    /// The range each named adjustable may take, inclusive.
514    pub allowed: BTreeMap<String, Range>,
515    /// The file this manifest is about, as the slicer named it.
516    pub file_name: String,
517    /// The material the job is sliced for.
518    pub material: String,
519    /// Whatever else the slicer recorded.
520    pub metadata: BTreeMap<String, String>,
521    /// The nozzle the job is sliced for, in millimetres.
522    pub nozzle_diameter_mm: f64,
523    /// The slicer profile the job was sliced with.
524    pub slicer_profile: String,
525}
526
527/// The job a printer reports it is running.
528///
529/// Every field but `state` is optional: an absent one means the source did
530/// not
531/// report it.
532#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
533pub struct JobSnapshot {
534    /// How far through the print is, as a fraction from zero to one.
535    ///
536    /// Normalized to a fraction here regardless of how the source expresses
537    /// it.
538    #[serde(default, skip_serializing_if = "Option::is_none")]
539    pub completion: Option<Reported>,
540    /// The error the source reports, when it reports one.
541    #[serde(default, skip_serializing_if = "Option::is_none")]
542    pub error: Option<String>,
543    /// The whole print's estimated duration, in whole seconds.
544    #[serde(default, skip_serializing_if = "Option::is_none")]
545    pub estimated_print_time_s: Option<i64>,
546    /// The name of the file being printed, as the source reported it.
547    #[serde(default, skip_serializing_if = "Option::is_none")]
548    pub file_name: Option<String>,
549    /// Where the file lives, in the source's own vocabulary.
550    #[serde(default, skip_serializing_if = "Option::is_none")]
551    pub file_origin: Option<String>,
552    /// How long the print has left, in whole seconds.
553    #[serde(default, skip_serializing_if = "Option::is_none")]
554    pub print_time_left_s: Option<i64>,
555    /// How long the print has been running, in whole seconds.
556    #[serde(default, skip_serializing_if = "Option::is_none")]
557    pub print_time_s: Option<i64>,
558    /// The file's size in bytes.
559    #[serde(default, skip_serializing_if = "Option::is_none")]
560    pub size_bytes: Option<i64>,
561    /// The state the source reports the job to be in.
562    pub state: PrinterState,
563}
564
565/// An external body arrived that could not be read.
566///
567/// This kind always carries its `raw` bytes, and it exists so that an alert
568/// this system cannot read is written down rather than dropped.
569#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
570pub struct MalformedExternalEventPayload {
571    /// One line saying why the body could not be read.
572    pub detail: String,
573}
574
575/// What a manifest read or write answers.
576#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
577pub struct ManifestAnswer {
578    /// The manifest, when the print has one.
579    #[serde(default, skip_serializing_if = "Option::is_none")]
580    pub manifest: Option<JobManifest>,
581    /// Every range this manifest asked wider than the envelope allows,
582    /// narrowed
583    /// to the envelope's — recorded on the print, so nobody has to wonder
584    /// later
585    /// which bound applied.
586    pub narrowings: Vec<ManifestNarrowing>,
587}
588
589/// One adjustable whose manifest range was wider than the envelope's.
590#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
591pub struct ManifestNarrowing {
592    /// The adjustable that was narrowed.
593    pub adjustable: Adjustable,
594    /// The range that stands.
595    pub applied: Range,
596    /// The range the manifest asked for.
597    pub requested: Range,
598}
599
600/// Obico reported a print failure.
601///
602/// The two instants are optional because Obico's own field for each is a Unix
603/// timestamp number, an empty string, or absent, and the last two both mean
604/// the
605/// producer reported no instant. An absent field here is that, never an epoch
606/// date standing in for it.
607#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
608pub struct ObicoFailureAlertPayload {
609    /// When the print ended, when Obico reported an instant for it.
610    #[serde(default, skip_serializing_if = "Option::is_none")]
611    pub ended_at: Option<Timestamp>,
612    /// The file being printed, when Obico named one.
613    #[serde(default, skip_serializing_if = "Option::is_none")]
614    pub file_name: Option<String>,
615    /// Whether Obico called it a warning rather than a failure.
616    pub is_warning: bool,
617    /// Obico's own identifier for the print, when it named one.
618    #[serde(default, skip_serializing_if = "Option::is_none")]
619    pub obico_print_id: Option<i64>,
620    /// Whether Obico paused the print itself.
621    pub print_paused: bool,
622    /// When the print started, when Obico reported an instant for it.
623    #[serde(default, skip_serializing_if = "Option::is_none")]
624    pub started_at: Option<Timestamp>,
625}
626
627/// The kind of printer notification Obico sent, normalized.
628#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
629pub enum ObicoNotificationType {
630    /// A print started.
631    #[serde(rename = "started")]
632    Started,
633    /// A print finished.
634    #[serde(rename = "done")]
635    Done,
636    /// A print was cancelled.
637    #[serde(rename = "cancelled")]
638    Cancelled,
639    /// A print was paused.
640    #[serde(rename = "paused")]
641    Paused,
642    /// A print was resumed.
643    #[serde(rename = "resumed")]
644    Resumed,
645    /// The printer is waiting for a filament change.
646    #[serde(rename = "filament_change")]
647    FilamentChange,
648    /// A heater cooled down.
649    #[serde(rename = "heater_cooled")]
650    HeaterCooled,
651    /// A heater reached its target.
652    #[serde(rename = "heater_target")]
653    HeaterTarget,
654}
655
656/// Obico sent a printer notification.
657///
658/// The two instants are optional for the same reason
659/// `ObicoFailureAlertPayload`'s are, and are absent along with the rest of
660/// the print's fields when the notification is about no print at all.
661#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
662pub struct ObicoPrinterNotificationPayload {
663    /// When the print ended, when Obico reported an instant for it.
664    #[serde(default, skip_serializing_if = "Option::is_none")]
665    pub ended_at: Option<Timestamp>,
666    /// The file being printed, when the notification is about one.
667    #[serde(default, skip_serializing_if = "Option::is_none")]
668    pub file_name: Option<String>,
669    /// Which notification it is.
670    pub notification_type: ObicoNotificationType,
671    /// Obico's own identifier for the print, when the notification is about
672    /// one.
673    #[serde(default, skip_serializing_if = "Option::is_none")]
674    pub obico_print_id: Option<i64>,
675    /// When the print started, when Obico reported an instant for it.
676    #[serde(default, skip_serializing_if = "Option::is_none")]
677    pub started_at: Option<Timestamp>,
678}
679
680/// An operator acknowledged an event.
681#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
682pub struct OperatorAcknowledgementPayload {
683    /// The event being acknowledged.
684    pub acknowledged_event_id: EventId,
685    /// What the operator asked for next.
686    pub disposition: AcknowledgementDisposition,
687}
688
689/// The decision policy took on one request.
690#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
691pub enum PolicyDecision {
692    /// The request may proceed.
693    #[serde(rename = "accepted")]
694    Accepted,
695    /// The request may not, for this reason.
696    #[serde(rename = "rejected")]
697    Rejected(RejectionReason),
698}
699
700/// A port failed while one event was being handled.
701///
702/// The event is named rather than implied, so that a reader holding an
703/// event's
704/// identifier reaches every failure recorded while that event was being
705/// handled. A failure recorded here is one the handling survived: the event
706/// is
707/// already in the history by the time any of these sites is reached, and the
708/// loop goes on to handle the next event.
709#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
710pub struct PortFailurePayload {
711    /// What the port said about it, in the port's own words.
712    pub detail: String,
713    /// The event whose handling reached the failing call.
714    pub event_id: EventId,
715    /// Where it failed.
716    pub site: PortFailureSite,
717}
718
719/// Where a port failed while an event was being handled.
720///
721/// A closed set of exactly the sites at which a failure has nowhere else to
722/// be
723/// recorded. The printer's action methods record theirs on the
724/// `ActionRecord` the request minted, and a restoring
725/// call records its own on the `Intervention` it was
726/// expiring; those are not sites here, because a second record of them would
727/// be
728/// a second version of one fact.
729#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
730pub enum PortFailureSite {
731    /// Reading the printer's own state.
732    #[serde(rename = "printer_snapshot")]
733    PrinterSnapshot,
734    /// Reading the job the printer reports it is running.
735    #[serde(rename = "printer_job")]
736    PrinterJob,
737    /// Writing the image the event arrived with.
738    #[serde(rename = "image_write")]
739    ImageWrite,
740    /// Running the supervision turn the event prompted.
741    #[serde(rename = "supervision_turn")]
742    SupervisionTurn,
743}
744
745/// The whole vocabulary an actor may ask for, and there is no other.
746#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
747#[serde(tag = "action")]
748pub enum PrintAction {
749    /// Pause the print.
750    #[serde(rename = "pause")]
751    Pause {
752        /// Who is asking.
753        actor: Actor,
754        /// Why the actor is asking for this.
755        reason: String,
756    },
757    /// Resume the print.
758    #[serde(rename = "resume")]
759    Resume {
760        /// Who is asking.
761        actor: Actor,
762        /// Why the actor is asking for this.
763        reason: String,
764    },
765    /// Cancel the print.
766    #[serde(rename = "cancel")]
767    Cancel {
768        /// Who is asking.
769        actor: Actor,
770        /// Why the actor is asking for this.
771        reason: String,
772    },
773    /// Start a print of a named file, with a manifest.
774    #[serde(rename = "start_print")]
775    StartPrint {
776        /// Who is asking.
777        actor: Actor,
778        /// The file to print, validated as a name a file API can be asked
779        /// for.
780        file_name: FileName,
781        /// The manifest this print is bounded by.
782        manifest: JobManifest,
783        /// Why the actor is asking for this.
784        reason: String,
785    },
786    /// Set the feedrate factor, where one means one hundred percent.
787    #[serde(rename = "set_feedrate_factor")]
788    SetFeedrateFactor {
789        /// Who is asking.
790        actor: Actor,
791        /// How long the change stands for, in whole seconds.
792        #[serde(default, skip_serializing_if = "Option::is_none")]
793        duration_s: Option<i64>,
794        /// The multiplier asked for.
795        factor: f64,
796        /// Why the actor is asking for this.
797        reason: String,
798    },
799    /// Set the flowrate factor, where one means one hundred percent.
800    #[serde(rename = "set_flowrate_factor")]
801    SetFlowrateFactor {
802        /// Who is asking.
803        actor: Actor,
804        /// How long the change stands for, in whole seconds.
805        #[serde(default, skip_serializing_if = "Option::is_none")]
806        duration_s: Option<i64>,
807        /// The multiplier asked for.
808        factor: f64,
809        /// Why the actor is asking for this.
810        reason: String,
811    },
812    /// Set one tool's target temperature.
813    #[serde(rename = "set_tool_target_c")]
814    SetToolTargetC {
815        /// Who is asking.
816        actor: Actor,
817        /// How long the change stands for, in whole seconds.
818        #[serde(default, skip_serializing_if = "Option::is_none")]
819        duration_s: Option<i64>,
820        /// Why the actor is asking for this.
821        reason: String,
822        /// The target temperature asked for, in degrees Celsius.
823        target_c: f64,
824        /// The tool, in the printer's own numbering.
825        tool: i64,
826    },
827    /// Set the bed's target temperature.
828    #[serde(rename = "set_bed_target_c")]
829    SetBedTargetC {
830        /// Who is asking.
831        actor: Actor,
832        /// How long the change stands for, in whole seconds.
833        #[serde(default, skip_serializing_if = "Option::is_none")]
834        duration_s: Option<i64>,
835        /// Why the actor is asking for this.
836        reason: String,
837        /// The target temperature asked for, in degrees Celsius.
838        target_c: f64,
839    },
840    /// Set the part-cooling fan percentage.
841    #[serde(rename = "set_fan_percent")]
842    SetFanPercent {
843        /// Who is asking.
844        actor: Actor,
845        /// How long the change stands for, in whole seconds.
846        #[serde(default, skip_serializing_if = "Option::is_none")]
847        duration_s: Option<i64>,
848        /// The percentage asked for.
849        percent: f64,
850        /// Why the actor is asking for this.
851        reason: String,
852    },
853    /// Acknowledge a failure event, with a disposition.
854    #[serde(rename = "acknowledge_failure")]
855    AcknowledgeFailure {
856        /// Who is asking.
857        actor: Actor,
858        /// What to do next.
859        disposition: AcknowledgementDisposition,
860        /// The event being acknowledged.
861        event_id: EventId,
862        /// Why the actor is asking for this.
863        reason: String,
864    },
865}
866
867/// Everything a supervision turn is given about one print.
868#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
869pub struct PrintContext {
870    /// The limits in force, so that the agent can see them before it asks.
871    pub bounds: EffectiveBounds,
872    /// The interventions still active.
873    pub interventions: Vec<Intervention>,
874    /// The job, when a snapshot could be taken.
875    #[serde(default, skip_serializing_if = "Option::is_none")]
876    pub job: Option<JobSnapshot>,
877    /// The most recent image, when there is one.
878    #[serde(default, skip_serializing_if = "Option::is_none")]
879    pub latest_image: Option<ImageRef>,
880    /// The manifest, when the print has one.
881    #[serde(default, skip_serializing_if = "Option::is_none")]
882    pub manifest: Option<JobManifest>,
883    /// The print itself.
884    pub print: PrintRecord,
885    /// The printer, when a snapshot could be taken.
886    #[serde(default, skip_serializing_if = "Option::is_none")]
887    pub printer: Option<PrinterSnapshot>,
888    /// A bounded list of this print's events, newest first.
889    pub recent_events: Vec<EventRecord>,
890}
891
892/// A lowercase hyphenated version 7 UUID identifying one print.
893pub type PrintId = String;
894
895/// One print, and the record supervision keys from.
896///
897/// The provider's own print id is carried beside this record's identifier
898/// rather than as it, because a print may be observed before the provider
899/// that reports it has one.
900#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
901pub struct PrintRecord {
902    /// Why it ended, if it has.
903    #[serde(default, skip_serializing_if = "Option::is_none")]
904    pub end_reason: Option<String>,
905    /// When it ended, if it has.
906    #[serde(default, skip_serializing_if = "Option::is_none")]
907    pub ended_at: Option<Timestamp>,
908    /// The file being printed, as the source reported it.
909    #[serde(default, skip_serializing_if = "Option::is_none")]
910    pub file_name: Option<String>,
911    /// This print's identifier, minted by the store.
912    pub id: PrintId,
913    /// Every manifest range this print narrowed to the envelope's.
914    pub narrowings: Vec<ManifestNarrowing>,
915    /// When the print was opened.
916    pub opened_at: Timestamp,
917    /// The provider's own identifier for the print, whichever provider
918    /// reported it, when one has.
919    #[serde(default, skip_serializing_if = "Option::is_none")]
920    pub provider_print_id: Option<i64>,
921    /// The state the print is in.
922    pub state: PrinterState,
923}
924
925/// A printer, as a source reported it at one instant.
926#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
927pub struct PrinterSnapshot {
928    /// The bed heater, when the printer reports one.
929    #[serde(default, skip_serializing_if = "Option::is_none")]
930    pub bed: Option<HeaterSnapshot>,
931    /// The chamber heater, when the printer reports one.
932    #[serde(default, skip_serializing_if = "Option::is_none")]
933    pub chamber: Option<HeaterSnapshot>,
934    /// The state the printer is in.
935    pub connection: PrinterState,
936    /// The part-cooling fan, in percent.
937    #[serde(default, skip_serializing_if = "Option::is_none")]
938    pub fan_percent: Option<Reported>,
939    /// The feedrate multiplier, where one means one hundred percent.
940    #[serde(default, skip_serializing_if = "Option::is_none")]
941    pub feedrate_factor: Option<Reported>,
942    /// The flowrate multiplier, where one means one hundred percent.
943    #[serde(default, skip_serializing_if = "Option::is_none")]
944    pub flowrate_factor: Option<Reported>,
945    /// The instant this observation was taken.
946    pub observed_at: Timestamp,
947    /// The tool heaters, indexed by tool number.
948    pub tools: Vec<HeaterSnapshot>,
949}
950
951/// The state a source reports a printer or a print to be in.
952///
953/// The `unknown` arm exists so that a state nobody anticipated is recorded
954/// carrying the source's own word for it rather than lost.
955#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
956pub enum PrinterState {
957    /// Connected and idle.
958    #[serde(rename = "operational")]
959    Operational,
960    /// Printing, but paused.
961    #[serde(rename = "paused")]
962    Paused,
963    /// Printing.
964    #[serde(rename = "printing")]
965    Printing,
966    /// Cancelling a print.
967    #[serde(rename = "cancelling")]
968    Cancelling,
969    /// In an error state.
970    #[serde(rename = "error")]
971    Error,
972    /// Not reachable.
973    #[serde(rename = "offline")]
974    Offline,
975    /// A state this vocabulary does not name, in the source's own word for
976    /// it.
977    #[serde(rename = "unknown")]
978    Unknown(String),
979}
980
981/// What the prints read answers: every print, and the one the printer is
982/// running.
983///
984/// An open print's recorded `state` is the state it was opened in, which is
985/// `printing` whether or not the machine is paused now; what the machine is
986/// doing is the status read's answer.
987#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
988pub struct PrintsAnswer {
989    /// The print the printer's current job belongs to, present exactly when
990    /// the
991    /// printer reports a job it is printing or has paused. Absent when the
992    /// printer could not be read.
993    #[serde(default, skip_serializing_if = "Option::is_none")]
994    pub active: Option<PrintId>,
995    /// Every print this server holds, ended or not, most recently opened
996    /// first.
997    pub prints: Vec<PrintRecord>,
998}
999
1000/// An inclusive pair of 64-bit floats.
1001#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1002pub struct Range {
1003    /// The highest value the range admits, inclusive.
1004    pub max: f64,
1005    /// The lowest value the range admits, inclusive.
1006    pub min: f64,
1007}
1008
1009/// Bytes exactly as received, base64-encoded.
1010pub type RawBytes = String;
1011
1012/// Why a request was refused.
1013///
1014/// Each rejection is a distinct variant, so a consumer distinguishes them by
1015/// matching rather than by reading a message.
1016#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1017pub enum RejectionReason {
1018    /// The value asked for is outside the range allowed for that adjustable.
1019    #[serde(rename = "out_of_bounds")]
1020    OutOfBounds {
1021        /// The adjustable that was asked for.
1022        adjustable: Adjustable,
1023        /// The range that was allowed.
1024        allowed: Range,
1025        /// The value that was asked for.
1026        requested: f64,
1027    },
1028    /// This actor class may not request this action at all.
1029    #[serde(rename = "actor_may_not_request")]
1030    ActorMayNotRequest {
1031        /// The action they asked for.
1032        action: ActionKind,
1033        /// The class of the actor that asked.
1034        actor_class: ActorClass,
1035    },
1036    /// There is no active print to act on.
1037    #[serde(rename = "no_active_print")]
1038    NoActivePrint,
1039    /// The printer is not in a state this action is valid from.
1040    #[serde(rename = "invalid_from_state")]
1041    InvalidFromState {
1042        /// The state the printer is in.
1043        state: PrinterState,
1044    },
1045    /// The agent's minimum interval has not elapsed.
1046    #[serde(rename = "min_interval_not_elapsed")]
1047    MinIntervalNotElapsed {
1048        /// The minimum interval, in whole seconds.
1049        interval_s: i64,
1050        /// How long it has been since the last agent action, in whole
1051        /// seconds.
1052        since_last_s: i64,
1053    },
1054    /// The adjustable is not one this printer has.
1055    #[serde(rename = "unsupported_adjustable")]
1056    UnsupportedAdjustable {
1057        /// The adjustable this printer cannot express.
1058        adjustable: Adjustable,
1059    },
1060}
1061
1062/// A value as a source reported it, flagged when it is outside the
1063/// plausibility range this crate declares for its field.
1064#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1065pub struct Reported {
1066    /// One shape of the contracts, which say nothing more about it.
1067    pub out_of_range: bool,
1068    /// One shape of the contracts, which say nothing more about it.
1069    pub value: f64,
1070}
1071
1072/// What one restart put back the way it found it.
1073///
1074/// A supervisor that has been restarted adopts whatever the store holds
1075/// rather
1076/// than starting empty, and each of these is one of those adoptions. They are
1077/// recorded rather than merely done, because a print that carried on across a
1078/// restart and one that was started again look identical afterwards unless
1079/// the
1080/// history says which happened.
1081#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1082pub enum StartupOutcome {
1083    /// A print left open was adopted as the print this supervisor is
1084    /// watching.
1085    #[serde(rename = "print_adopted")]
1086    PrintAdopted,
1087    /// A session left open was resumed rather than replaced.
1088    #[serde(rename = "session_resumed")]
1089    SessionResumed {
1090        /// The session's own name in the harness.
1091        session_name: String,
1092    },
1093    /// An intervention already past its expiry was expired on start.
1094    #[serde(rename = "intervention_expired")]
1095    InterventionExpired {
1096        /// What it had changed.
1097        adjustable: Adjustable,
1098        /// The intervention that had outlived its bound.
1099        intervention_id: InterventionId,
1100        /// What became of putting the prior value back.
1101        outcome: InterventionOutcome,
1102    },
1103}
1104
1105/// A supervisor reconciled one thing the store held when it started.
1106#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1107pub struct StartupReconciliationPayload {
1108    /// What was reconciled.
1109    pub outcome: StartupOutcome,
1110    /// The print it is about.
1111    pub print_id: PrintId,
1112}
1113
1114/// What a status read answers.
1115#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1116pub struct StatusAnswer {
1117    /// The bounded interventions still in force.
1118    pub interventions: Vec<Intervention>,
1119    /// The job, when a snapshot could be taken.
1120    #[serde(default, skip_serializing_if = "Option::is_none")]
1121    pub job: Option<JobSnapshot>,
1122    /// The print.
1123    pub print: PrintRecord,
1124    /// The printer, when a snapshot could be taken.
1125    #[serde(default, skip_serializing_if = "Option::is_none")]
1126    pub printer: Option<PrinterSnapshot>,
1127    /// The supervision session watching it, when one is.
1128    #[serde(default, skip_serializing_if = "Option::is_none")]
1129    pub session: Option<SupervisionSession>,
1130}
1131
1132/// The supervision session keyed to one print.
1133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1134pub struct SupervisionSession {
1135    /// Why it was closed, if it was.
1136    #[serde(default, skip_serializing_if = "Option::is_none")]
1137    pub close_reason: Option<String>,
1138    /// When the session was closed, if it was.
1139    #[serde(default, skip_serializing_if = "Option::is_none")]
1140    pub closed_at: Option<Timestamp>,
1141    /// When the session was opened.
1142    pub created_at: Timestamp,
1143    /// The identity the harness ran the session under.
1144    pub harness_identity: String,
1145    /// When the last turn ran.
1146    pub last_turn_at: Timestamp,
1147    /// The print this session watches.
1148    pub print_id: PrintId,
1149    /// The session's own name in the harness.
1150    pub session_name: String,
1151}
1152
1153/// A supervision session was closed.
1154#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1155pub struct SupervisionSessionClosedPayload {
1156    /// Why it was closed.
1157    pub close_reason: String,
1158    /// The session's own name in the harness.
1159    pub session_name: String,
1160}
1161
1162/// A supervision session was opened.
1163#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1164pub struct SupervisionSessionOpenedPayload {
1165    /// The identity the harness ran it under.
1166    pub harness_identity: String,
1167    /// The session's own name in the harness.
1168    pub session_name: String,
1169}
1170
1171/// An instant in UTC, as an RFC 3339 string with a zero offset.
1172pub type Timestamp = String;
1173
1174/// One payload type declared under a kind name, by the domain that owns it.
1175///
1176/// The table from kind name to payload type, as the server declares it: every
1177/// kind below has exactly one implementation here, and a kind this client
1178/// does not know flows through `EventRecord` untouched.
1179pub trait EventPayloadKind: serde::de::DeserializeOwned {
1180    /// The name this payload's events are written down under.
1181    const KIND: &'static str;
1182}
1183
1184impl EventPayloadKind for ActionExecutedPayload {
1185    const KIND: &'static str = "action_executed";
1186}
1187
1188impl EventPayloadKind for ActionRejectedPayload {
1189    const KIND: &'static str = "action_rejected";
1190}
1191
1192impl EventPayloadKind for ActionRequestedPayload {
1193    const KIND: &'static str = "action_requested";
1194}
1195
1196impl EventPayloadKind for AgentAssessmentPayload {
1197    const KIND: &'static str = "agent_assessment";
1198}
1199
1200impl EventPayloadKind for InterventionExpiredPayload {
1201    const KIND: &'static str = "intervention_expired";
1202}
1203
1204impl EventPayloadKind for MalformedExternalEventPayload {
1205    const KIND: &'static str = "malformed_external_event";
1206}
1207
1208impl EventPayloadKind for ObicoFailureAlertPayload {
1209    const KIND: &'static str = "obico_failure_alert";
1210}
1211
1212impl EventPayloadKind for ObicoPrinterNotificationPayload {
1213    const KIND: &'static str = "obico_printer_notification";
1214}
1215
1216impl EventPayloadKind for OperatorAcknowledgementPayload {
1217    const KIND: &'static str = "operator_acknowledgement";
1218}
1219
1220impl EventPayloadKind for PortFailurePayload {
1221    const KIND: &'static str = "port_failure";
1222}
1223
1224impl EventPayloadKind for StartupReconciliationPayload {
1225    const KIND: &'static str = "startup_reconciliation";
1226}
1227
1228impl EventPayloadKind for SupervisionSessionClosedPayload {
1229    const KIND: &'static str = "supervision_session_closed";
1230}
1231
1232impl EventPayloadKind for SupervisionSessionOpenedPayload {
1233    const KIND: &'static str = "supervision_session_opened";
1234}
1235
1236/// Every kind the server declares a payload type for, in name order.
1237pub const EVENT_KINDS: [&str; 13] = [
1238    "action_executed",
1239    "action_rejected",
1240    "action_requested",
1241    "agent_assessment",
1242    "intervention_expired",
1243    "malformed_external_event",
1244    "obico_failure_alert",
1245    "obico_printer_notification",
1246    "operator_acknowledgement",
1247    "port_failure",
1248    "startup_reconciliation",
1249    "supervision_session_closed",
1250    "supervision_session_opened",
1251];
1252
1253impl EventRecord {
1254    /// The payload as `P`, when this event is under the kind `P` declares.
1255    ///
1256    /// Answers `None` for an event of any other kind — one this client knows
1257    /// or one it does not — and the parse failure for an event under the
1258    /// right kind whose payload is not of the type.
1259    #[must_use]
1260    pub fn payload_as<P: EventPayloadKind>(&self) -> Option<Result<P, serde_json::Error>> {
1261        (self.kind == P::KIND).then(|| serde_json::from_value(self.payload.clone()))
1262    }
1263}
1264
1265impl Client {
1266    /// Call `prints` on the configured supervisor.
1267    ///
1268    /// # Errors
1269    ///
1270    /// Returns `ClientError` when the supervisor could not be reached, when
1271    /// it answered something this client cannot read.
1272    // llmlint: ignore[names_match_behavior] See suppressions.toml.
1273    pub fn prints(&self) -> Result<PrintsAnswer, ClientError> {
1274        let target = String::from("/v1/prints");
1275        let asked: Vec<(String, String)> = Vec::new();
1276        let sending: Option<serde_json::Value> = None;
1277        self.call("GET", &target, &asked, sending.as_ref())
1278    }
1279
1280    /// Call `status` on the configured supervisor.
1281    ///
1282    /// # Errors
1283    ///
1284    /// Returns `ClientError` when the supervisor could not be reached, when
1285    /// it answered something this client cannot read.
1286    pub fn status(&self, print_id: &str) -> Result<StatusAnswer, ClientError> {
1287        let target = format!("/v1/prints/{print_id}/status");
1288        let asked: Vec<(String, String)> = Vec::new();
1289        let sending: Option<serde_json::Value> = None;
1290        self.call("GET", &target, &asked, sending.as_ref())
1291    }
1292
1293    /// Call `context` on the configured supervisor.
1294    ///
1295    /// # Errors
1296    ///
1297    /// Returns `ClientError` when the supervisor could not be reached, when
1298    /// it answered something this client cannot read.
1299    pub fn context(&self, print_id: &str) -> Result<ContextAnswer, ClientError> {
1300        let target = format!("/v1/prints/{print_id}/context");
1301        let asked: Vec<(String, String)> = Vec::new();
1302        let sending: Option<serde_json::Value> = None;
1303        self.call("GET", &target, &asked, sending.as_ref())
1304    }
1305
1306    /// Call `image` on the configured supervisor.
1307    ///
1308    /// # Errors
1309    ///
1310    /// Returns `ClientError` when the supervisor could not be reached, when
1311    /// it answered something this client cannot read.
1312    pub fn image(&self, image_id: &str) -> Result<ImageAnswer, ClientError> {
1313        let target = format!("/v1/images/{image_id}");
1314        let asked: Vec<(String, String)> = Vec::new();
1315        let sending: Option<serde_json::Value> = None;
1316        self.call("GET", &target, &asked, sending.as_ref())
1317    }
1318
1319    /// Call `history` on the configured supervisor.
1320    ///
1321    /// # Errors
1322    ///
1323    /// Returns `ClientError` when the supervisor could not be reached, when
1324    /// it answered something this client cannot read.
1325    pub fn history(
1326        &self,
1327        print_id: &str,
1328        limit: Option<i64>,
1329    ) -> Result<HistoryAnswer, ClientError> {
1330        let target = format!("/v1/prints/{print_id}/history");
1331        let mut asked: Vec<(String, String)> = Vec::new();
1332        if let Some(value) = limit {
1333            asked.push(("limit".to_owned(), value.to_string()));
1334        }
1335        let sending: Option<serde_json::Value> = None;
1336        self.call("GET", &target, &asked, sending.as_ref())
1337    }
1338
1339    /// Call `manifest_get` on the configured supervisor.
1340    ///
1341    /// # Errors
1342    ///
1343    /// Returns `ClientError` when the supervisor could not be reached, when
1344    /// it answered something this client cannot read.
1345    pub fn manifest_get(&self, print_id: &str) -> Result<ManifestAnswer, ClientError> {
1346        let target = format!("/v1/prints/{print_id}/manifest");
1347        let asked: Vec<(String, String)> = Vec::new();
1348        let sending: Option<serde_json::Value> = None;
1349        self.call("GET", &target, &asked, sending.as_ref())
1350    }
1351
1352    /// Call `manifest_set` on the configured supervisor.
1353    ///
1354    /// # Errors
1355    ///
1356    /// Returns `ClientError` when the supervisor could not be reached, when
1357    /// it answered something this client cannot read, when this client
1358    /// refuses the call before making it because the reason is empty, and
1359    /// when the policy refused the action — which arrives as
1360    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1361    /// the range allowed.
1362    pub fn manifest_set(
1363        &self,
1364        print_id: &str,
1365        reason: &str,
1366        manifest: &JobManifest,
1367    ) -> Result<ManifestAnswer, ClientError> {
1368        crate::reason_given(reason)?;
1369        let target = format!("/v1/prints/{print_id}/manifest");
1370        let asked: Vec<(String, String)> = Vec::new();
1371        let mut sending = serde_json::Map::new();
1372        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1373        sending.insert("manifest".to_owned(), crate::as_value(&manifest)?);
1374        let sending = Some(serde_json::Value::Object(sending));
1375        self.call("PUT", &target, &asked, sending.as_ref())
1376    }
1377
1378    /// Call `pause` on the configured supervisor.
1379    ///
1380    /// # Errors
1381    ///
1382    /// Returns `ClientError` when the supervisor could not be reached, when
1383    /// it answered something this client cannot read, when this client
1384    /// refuses the call before making it because the reason is empty, and
1385    /// when the policy refused the action — which arrives as
1386    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1387    /// the range allowed.
1388    pub fn pause(&self, print_id: &str, reason: &str) -> Result<ActionAnswer, ClientError> {
1389        crate::reason_given(reason)?;
1390        let target = format!("/v1/prints/{print_id}/actions/pause");
1391        let asked: Vec<(String, String)> = Vec::new();
1392        let mut sending = serde_json::Map::new();
1393        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1394        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1395        let sending = Some(serde_json::Value::Object(sending));
1396        self.call("POST", &target, &asked, sending.as_ref())
1397    }
1398
1399    /// Call `resume` on the configured supervisor.
1400    ///
1401    /// # Errors
1402    ///
1403    /// Returns `ClientError` when the supervisor could not be reached, when
1404    /// it answered something this client cannot read, when this client
1405    /// refuses the call before making it because the reason is empty, and
1406    /// when the policy refused the action — which arrives as
1407    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1408    /// the range allowed.
1409    pub fn resume(&self, print_id: &str, reason: &str) -> Result<ActionAnswer, ClientError> {
1410        crate::reason_given(reason)?;
1411        let target = format!("/v1/prints/{print_id}/actions/resume");
1412        let asked: Vec<(String, String)> = Vec::new();
1413        let mut sending = serde_json::Map::new();
1414        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1415        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1416        let sending = Some(serde_json::Value::Object(sending));
1417        self.call("POST", &target, &asked, sending.as_ref())
1418    }
1419
1420    /// Call `cancel` on the configured supervisor.
1421    ///
1422    /// # Errors
1423    ///
1424    /// Returns `ClientError` when the supervisor could not be reached, when
1425    /// it answered something this client cannot read, when this client
1426    /// refuses the call before making it because the reason is empty, and
1427    /// when the policy refused the action — which arrives as
1428    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1429    /// the range allowed.
1430    pub fn cancel(&self, print_id: &str, reason: &str) -> Result<ActionAnswer, ClientError> {
1431        crate::reason_given(reason)?;
1432        let target = format!("/v1/prints/{print_id}/actions/cancel");
1433        let asked: Vec<(String, String)> = Vec::new();
1434        let mut sending = serde_json::Map::new();
1435        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1436        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1437        let sending = Some(serde_json::Value::Object(sending));
1438        self.call("POST", &target, &asked, sending.as_ref())
1439    }
1440
1441    /// Call `start_print` on the configured supervisor.
1442    ///
1443    /// # Errors
1444    ///
1445    /// Returns `ClientError` when the supervisor could not be reached, when
1446    /// it answered something this client cannot read, when this client
1447    /// refuses the call before making it because the reason is empty, and
1448    /// when the policy refused the action — which arrives as
1449    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1450    /// the range allowed.
1451    pub fn start_print(
1452        &self,
1453        print_id: &str,
1454        file_name: &FileName,
1455        manifest: &JobManifest,
1456        reason: &str,
1457    ) -> Result<ActionAnswer, ClientError> {
1458        crate::reason_given(reason)?;
1459        let target = format!("/v1/prints/{print_id}/actions/start_print");
1460        let asked: Vec<(String, String)> = Vec::new();
1461        let mut sending = serde_json::Map::new();
1462        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1463        sending.insert("file_name".to_owned(), crate::as_value(&file_name)?);
1464        sending.insert("manifest".to_owned(), crate::as_value(&manifest)?);
1465        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1466        let sending = Some(serde_json::Value::Object(sending));
1467        self.call("POST", &target, &asked, sending.as_ref())
1468    }
1469
1470    /// Call `set_feedrate_factor` on the configured supervisor.
1471    ///
1472    /// # Errors
1473    ///
1474    /// Returns `ClientError` when the supervisor could not be reached, when
1475    /// it answered something this client cannot read, when this client
1476    /// refuses the call before making it because the reason is empty, and
1477    /// when the policy refused the action — which arrives as
1478    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1479    /// the range allowed.
1480    pub fn set_feedrate_factor(
1481        &self,
1482        print_id: &str,
1483        factor: f64,
1484        reason: &str,
1485        duration_s: Option<i64>,
1486    ) -> Result<ActionAnswer, ClientError> {
1487        crate::reason_given(reason)?;
1488        let target = format!("/v1/prints/{print_id}/actions/set_feedrate_factor");
1489        let asked: Vec<(String, String)> = Vec::new();
1490        let mut sending = serde_json::Map::new();
1491        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1492        if let Some(value) = duration_s {
1493            sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
1494        }
1495        sending.insert("factor".to_owned(), crate::as_value(&factor)?);
1496        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1497        let sending = Some(serde_json::Value::Object(sending));
1498        self.call("POST", &target, &asked, sending.as_ref())
1499    }
1500
1501    /// Call `set_flowrate_factor` on the configured supervisor.
1502    ///
1503    /// # Errors
1504    ///
1505    /// Returns `ClientError` when the supervisor could not be reached, when
1506    /// it answered something this client cannot read, when this client
1507    /// refuses the call before making it because the reason is empty, and
1508    /// when the policy refused the action — which arrives as
1509    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1510    /// the range allowed.
1511    pub fn set_flowrate_factor(
1512        &self,
1513        print_id: &str,
1514        factor: f64,
1515        reason: &str,
1516        duration_s: Option<i64>,
1517    ) -> Result<ActionAnswer, ClientError> {
1518        crate::reason_given(reason)?;
1519        let target = format!("/v1/prints/{print_id}/actions/set_flowrate_factor");
1520        let asked: Vec<(String, String)> = Vec::new();
1521        let mut sending = serde_json::Map::new();
1522        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1523        if let Some(value) = duration_s {
1524            sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
1525        }
1526        sending.insert("factor".to_owned(), crate::as_value(&factor)?);
1527        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1528        let sending = Some(serde_json::Value::Object(sending));
1529        self.call("POST", &target, &asked, sending.as_ref())
1530    }
1531
1532    /// Call `set_tool_target_c` on the configured supervisor.
1533    ///
1534    /// # Errors
1535    ///
1536    /// Returns `ClientError` when the supervisor could not be reached, when
1537    /// it answered something this client cannot read, when this client
1538    /// refuses the call before making it because the reason is empty, and
1539    /// when the policy refused the action — which arrives as
1540    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1541    /// the range allowed.
1542    pub fn set_tool_target_c(
1543        &self,
1544        print_id: &str,
1545        reason: &str,
1546        target_c: f64,
1547        tool: i64,
1548        duration_s: Option<i64>,
1549    ) -> Result<ActionAnswer, ClientError> {
1550        crate::reason_given(reason)?;
1551        let target = format!("/v1/prints/{print_id}/actions/set_tool_target_c");
1552        let asked: Vec<(String, String)> = Vec::new();
1553        let mut sending = serde_json::Map::new();
1554        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1555        if let Some(value) = duration_s {
1556            sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
1557        }
1558        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1559        sending.insert("target_c".to_owned(), crate::as_value(&target_c)?);
1560        sending.insert("tool".to_owned(), crate::as_value(&tool)?);
1561        let sending = Some(serde_json::Value::Object(sending));
1562        self.call("POST", &target, &asked, sending.as_ref())
1563    }
1564
1565    /// Call `set_bed_target_c` on the configured supervisor.
1566    ///
1567    /// # Errors
1568    ///
1569    /// Returns `ClientError` when the supervisor could not be reached, when
1570    /// it answered something this client cannot read, when this client
1571    /// refuses the call before making it because the reason is empty, and
1572    /// when the policy refused the action — which arrives as
1573    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1574    /// the range allowed.
1575    pub fn set_bed_target_c(
1576        &self,
1577        print_id: &str,
1578        reason: &str,
1579        target_c: f64,
1580        duration_s: Option<i64>,
1581    ) -> Result<ActionAnswer, ClientError> {
1582        crate::reason_given(reason)?;
1583        let target = format!("/v1/prints/{print_id}/actions/set_bed_target_c");
1584        let asked: Vec<(String, String)> = Vec::new();
1585        let mut sending = serde_json::Map::new();
1586        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1587        if let Some(value) = duration_s {
1588            sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
1589        }
1590        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1591        sending.insert("target_c".to_owned(), crate::as_value(&target_c)?);
1592        let sending = Some(serde_json::Value::Object(sending));
1593        self.call("POST", &target, &asked, sending.as_ref())
1594    }
1595
1596    /// Call `set_fan_percent` on the configured supervisor.
1597    ///
1598    /// # Errors
1599    ///
1600    /// Returns `ClientError` when the supervisor could not be reached, when
1601    /// it answered something this client cannot read, when this client
1602    /// refuses the call before making it because the reason is empty, and
1603    /// when the policy refused the action — which arrives as
1604    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1605    /// the range allowed.
1606    pub fn set_fan_percent(
1607        &self,
1608        print_id: &str,
1609        percent: f64,
1610        reason: &str,
1611        duration_s: Option<i64>,
1612    ) -> Result<ActionAnswer, ClientError> {
1613        crate::reason_given(reason)?;
1614        let target = format!("/v1/prints/{print_id}/actions/set_fan_percent");
1615        let asked: Vec<(String, String)> = Vec::new();
1616        let mut sending = serde_json::Map::new();
1617        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1618        if let Some(value) = duration_s {
1619            sending.insert("duration_s".to_owned(), crate::as_value(&value)?);
1620        }
1621        sending.insert("percent".to_owned(), crate::as_value(&percent)?);
1622        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1623        let sending = Some(serde_json::Value::Object(sending));
1624        self.call("POST", &target, &asked, sending.as_ref())
1625    }
1626
1627    /// Call `acknowledge_failure` on the configured supervisor.
1628    ///
1629    /// # Errors
1630    ///
1631    /// Returns `ClientError` when the supervisor could not be reached, when
1632    /// it answered something this client cannot read, when this client
1633    /// refuses the call before making it because the reason is empty, and
1634    /// when the policy refused the action — which arrives as
1635    /// `ClientError::Rejected`, carrying the reason, the value asked for and
1636    /// the range allowed.
1637    pub fn acknowledge_failure(
1638        &self,
1639        print_id: &str,
1640        disposition: &AcknowledgementDisposition,
1641        event_id: &EventId,
1642        reason: &str,
1643    ) -> Result<ActionAnswer, ClientError> {
1644        crate::reason_given(reason)?;
1645        let target = format!("/v1/prints/{print_id}/actions/acknowledge_failure");
1646        let asked: Vec<(String, String)> = Vec::new();
1647        let mut sending = serde_json::Map::new();
1648        sending.insert("actor".to_owned(), crate::as_value(&self.actor())?);
1649        sending.insert("disposition".to_owned(), crate::as_value(&disposition)?);
1650        sending.insert("event_id".to_owned(), crate::as_value(&event_id)?);
1651        sending.insert("reason".to_owned(), crate::as_value(&reason)?);
1652        let sending = Some(serde_json::Value::Object(sending));
1653        self.call("POST", &target, &asked, sending.as_ref())
1654    }
1655}