Files
kaptan/firmware/libs/kaptan-config-mavlink/src/protocol.rs
T

129 lines
4.2 KiB
Rust

//! Stable typed outcomes for the Kaptan configuration microservice.
use kaptan_config::{ConfigState, ConfigViolation, FieldId};
use kaptan_err_reportable::KaptanError;
/// Operation reported in an authoritative result record.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Operation {
/// Query/read operation.
Query,
/// Begin transaction.
Begin,
/// Scalar write.
Set,
/// Whole-candidate validation.
Validate,
/// Durable commit.
Commit,
/// Transaction abort.
Abort,
}
/// Stable result classification.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ResultKind {
/// The operation was accepted.
Accepted,
/// A full snapshot committed but requires restart before activation.
CommittedRestartRequired,
/// The operation was rejected without an active-state transition.
Rejected,
}
/// Compact protocol error code. Detail belongs in [`ConfigViolation`] when a
/// configuration invariant was responsible.
#[derive(Clone, Copy, Debug, Eq, PartialEq, KaptanError)]
pub enum ProtocolError {
/// The request target did not match this component.
#[kaptan_error(id = 2001)]
BadTarget,
/// The configuration lease or single transaction slot is occupied.
#[kaptan_error(id = 2002)]
SessionBusy,
/// The session is unknown, expired, or belongs to a different principal.
#[kaptan_error(id = 2003)]
InvalidSession,
/// Reusing one request ID with different content is forbidden.
#[kaptan_error(id = 2004)]
RequestConflict,
/// The request was not based on the current transaction revision.
#[kaptan_error(id = 2005)]
StaleRevision,
/// A command is invalid in the current lifecycle state.
#[kaptan_error(id = 2006)]
BadState,
/// The field is not present in this schema.
#[kaptan_error(id = 2007)]
UnknownField(FieldId),
/// A query requested an empty or out-of-range descriptor span.
#[kaptan_error(id = 2008)]
InvalidQuery,
/// The typed setter does not match the field descriptor.
#[kaptan_error(id = 2009)]
TypeMismatch(FieldId),
/// A local or complete validation issue.
#[kaptan_error(id = 2010)]
Violation(ConfigViolation),
/// Persistence failed after a complete validation pass.
#[kaptan_error(id = 2011)]
StorageFailure,
/// The adapter reached an impossible internal state.
#[kaptan_error(id = 2012)]
Internal,
}
/// Authoritative completion for one request.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ConfigReply {
/// Client request identity.
pub request_id: u32,
/// The current session, or zero when none exists.
pub session_id: u32,
/// The transaction revision, or zero when no transaction exists.
pub revision: u32,
/// Completed operation.
pub operation: Operation,
/// High-level result.
pub result: ResultKind,
/// Exact typed failure, if rejected.
pub error: Option<ProtocolError>,
/// Current lifecycle state after handling the request.
pub state: ConfigState,
}
impl ConfigReply {
/// Stable primary field for the wire response, or the reserved sentinel.
pub const fn primary_field(self) -> u16 {
match self.error {
Some(ProtocolError::Violation(violation)) => match violation.primary() {
Some(field) => field.get(),
None => u16::MAX,
},
Some(ProtocolError::UnknownField(field)) | Some(ProtocolError::TypeMismatch(field)) => {
field.get()
}
_ => u16::MAX,
}
}
/// Stable related field for the wire response, or the reserved sentinel.
pub const fn related_field(self) -> u16 {
match self.error {
Some(ProtocolError::Violation(violation)) => match violation.related_field() {
Some(field) => field.get(),
None => u16::MAX,
},
_ => u16::MAX,
}
}
/// Stable validation-rule code, or zero when no validation rule applies.
pub const fn validation_rule(self) -> u16 {
match self.error {
Some(ProtocolError::Violation(violation)) => violation.rule().code(),
_ => 0,
}
}
}