refactor(firmware): centralize configuration and diagnostics
This commit is contained in:
1 parent
7048ed89d0
commit
387fdaad23
140 files changed
+6891
-4541
No files matched your search
@@ -1,248 +0,0 @@
|
||||
//! Bounded CBOR snapshot transfer state.
|
||||
|
||||
use kaptan_config::{CommitError, ConfigManager, ConfigModel, ProfileStore};
|
||||
|
||||
use super::session::{ConfigProtocol, Session};
|
||||
use crate::{ConfigCommand, ConfigReply, Operation, ProtocolError, ResultKind};
|
||||
|
||||
/// Maximum complete CBOR snapshot accepted by the protocol.
|
||||
pub(super) const IMPORT_MAXIMUM_BYTES: usize = 4096;
|
||||
/// Payload bytes carried by each aligned import chunk.
|
||||
pub(super) const IMPORT_CHUNK_BYTES: usize = 192;
|
||||
pub(super) const IMPORT_CHUNK_COUNT: usize = IMPORT_MAXIMUM_BYTES.div_ceil(IMPORT_CHUNK_BYTES);
|
||||
|
||||
/// `KAPTAN_CONFIG_INFO.capability_flags`: bounded CBOR transaction import.
|
||||
pub const CAPABILITY_CBOR_IMPORT: u8 = 1;
|
||||
|
||||
/// Decodes a complete bounded CBOR snapshot into this service's candidate.
|
||||
///
|
||||
/// Vehicle-specific implementations live above this transport adapter so the
|
||||
/// generic MAVLink layer never owns a profile schema or board capabilities.
|
||||
pub trait SnapshotImporter<C> {
|
||||
/// Whether this concrete deployment exposes the bounded import path.
|
||||
const IMPORT_SUPPORTED: bool;
|
||||
/// Current format carried inside the deployment's raw CBOR profile blob.
|
||||
const PROFILE_FORMAT: u16;
|
||||
/// Converts one complete CBOR payload to a candidate. The service performs
|
||||
/// the subsequent complete-context validation before replacing the RAM
|
||||
/// transaction.
|
||||
fn decode(&self, bytes: &[u8]) -> Result<C, ProtocolError>;
|
||||
}
|
||||
|
||||
/// Default importer used when a deployment deliberately does not expose CBOR
|
||||
/// import yet. It keeps the service type usable for descriptor-only tests.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct NoSnapshotImporter;
|
||||
|
||||
impl<C> SnapshotImporter<C> for NoSnapshotImporter {
|
||||
const IMPORT_SUPPORTED: bool = false;
|
||||
const PROFILE_FORMAT: u16 = 0;
|
||||
|
||||
fn decode(&self, _: &[u8]) -> Result<C, ProtocolError> {
|
||||
Err(ProtocolError::CborMalformed)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) struct ImportBuffer {
|
||||
owner: u64,
|
||||
session_id: u32,
|
||||
transfer_id: u32,
|
||||
revision: u32,
|
||||
length: u16,
|
||||
crc32c: u32,
|
||||
received: [bool; IMPORT_CHUNK_COUNT],
|
||||
data: [u8; IMPORT_MAXIMUM_BYTES],
|
||||
}
|
||||
|
||||
impl<I> ConfigProtocol<I> {
|
||||
pub(super) fn begin_import<C>(
|
||||
&mut self,
|
||||
owner: u64,
|
||||
command: ConfigCommand,
|
||||
session: Session,
|
||||
) -> ConfigReply
|
||||
where
|
||||
C: ConfigModel,
|
||||
I: SnapshotImporter<C>,
|
||||
{
|
||||
let ConfigCommand::ImportBegin {
|
||||
request_id,
|
||||
length,
|
||||
schema_id,
|
||||
crc32c,
|
||||
..
|
||||
} = command
|
||||
else {
|
||||
return self.rejected(command, ProtocolError::Internal);
|
||||
};
|
||||
if !I::IMPORT_SUPPORTED {
|
||||
return self.rejected(command, ProtocolError::ImportUnavailable);
|
||||
}
|
||||
if schema_id != C::SCHEMA_ID {
|
||||
return self.rejected(command, ProtocolError::SchemaMismatch);
|
||||
}
|
||||
if length == 0 || usize::from(length) > IMPORT_MAXIMUM_BYTES {
|
||||
return self.rejected(command, ProtocolError::CborTooLarge);
|
||||
}
|
||||
let Some(transfer_id) = self.allocate_transfer_id() else {
|
||||
return self.rejected(command, ProtocolError::Internal);
|
||||
};
|
||||
self.import = Some(ImportBuffer {
|
||||
owner,
|
||||
session_id: session.id,
|
||||
transfer_id,
|
||||
revision: session.revision,
|
||||
length,
|
||||
crc32c,
|
||||
received: [false; IMPORT_CHUNK_COUNT],
|
||||
data: [0; IMPORT_MAXIMUM_BYTES],
|
||||
});
|
||||
let mut reply = self.reply(
|
||||
request_id,
|
||||
session.id,
|
||||
session.revision,
|
||||
Operation::Import,
|
||||
ResultKind::Accepted,
|
||||
None,
|
||||
);
|
||||
reply.transfer_id = transfer_id;
|
||||
reply
|
||||
}
|
||||
|
||||
pub(super) fn import_chunk(&mut self, command: ConfigCommand, session: Session) -> ConfigReply {
|
||||
let ConfigCommand::ImportChunk {
|
||||
request_id,
|
||||
transfer_id,
|
||||
offset,
|
||||
length,
|
||||
data,
|
||||
..
|
||||
} = command
|
||||
else {
|
||||
return self.rejected(command, ProtocolError::Internal);
|
||||
};
|
||||
let offset = usize::from(offset);
|
||||
let length = usize::from(length);
|
||||
let Some(import) = self.import.as_mut() else {
|
||||
return self.rejected(command, ProtocolError::BadState);
|
||||
};
|
||||
if import.owner != session.owner
|
||||
|| import.session_id != session.id
|
||||
|| import.transfer_id != transfer_id
|
||||
{
|
||||
return self.rejected(command, ProtocolError::InvalidSession);
|
||||
}
|
||||
if import.revision != session.revision {
|
||||
return self.rejected(command, ProtocolError::StaleRevision);
|
||||
}
|
||||
let total = usize::from(import.length);
|
||||
let Some(end) = offset.checked_add(length) else {
|
||||
return self.rejected(command, ProtocolError::CborMalformed);
|
||||
};
|
||||
if length == 0
|
||||
|| offset % IMPORT_CHUNK_BYTES != 0
|
||||
|| end > total
|
||||
|| (length != IMPORT_CHUNK_BYTES && end != total)
|
||||
{
|
||||
return self.rejected(command, ProtocolError::CborMalformed);
|
||||
}
|
||||
let chunk = offset / IMPORT_CHUNK_BYTES;
|
||||
if import.received[chunk] {
|
||||
if import.data[offset..end] != data[..length] {
|
||||
return self.rejected(command, ProtocolError::RequestConflict);
|
||||
}
|
||||
} else {
|
||||
import.data[offset..end].copy_from_slice(&data[..length]);
|
||||
import.received[chunk] = true;
|
||||
}
|
||||
self.reply(
|
||||
request_id,
|
||||
session.id,
|
||||
session.revision,
|
||||
Operation::Import,
|
||||
ResultKind::Accepted,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn finish_import<C, S>(
|
||||
&mut self,
|
||||
manager: &mut ConfigManager<C, S>,
|
||||
command: ConfigCommand,
|
||||
session: Session,
|
||||
request_id: u32,
|
||||
transfer_id: u32,
|
||||
) -> ConfigReply
|
||||
where
|
||||
C: ConfigModel,
|
||||
S: ProfileStore<C>,
|
||||
I: SnapshotImporter<C>,
|
||||
{
|
||||
let Some(import) = self.import else {
|
||||
return self.rejected(command, ProtocolError::BadState);
|
||||
};
|
||||
if import.owner != session.owner
|
||||
|| import.session_id != session.id
|
||||
|| import.transfer_id != transfer_id
|
||||
{
|
||||
return self.rejected(command, ProtocolError::InvalidSession);
|
||||
}
|
||||
if import.revision != session.revision {
|
||||
return self.rejected(command, ProtocolError::StaleRevision);
|
||||
}
|
||||
let total = usize::from(import.length);
|
||||
let chunks = total.div_ceil(IMPORT_CHUNK_BYTES);
|
||||
if import.received[..chunks].iter().any(|received| !received) {
|
||||
return self.rejected(command, ProtocolError::CborMalformed);
|
||||
}
|
||||
if crc32c(&import.data[..total]) != import.crc32c {
|
||||
return self.rejected(command, ProtocolError::BlobCrc);
|
||||
}
|
||||
let candidate = match self.importer.decode(&import.data[..total]) {
|
||||
Ok(candidate) => candidate,
|
||||
Err(error) => return self.rejected(command, error),
|
||||
};
|
||||
let Some(next_revision) = session.revision.checked_add(1) else {
|
||||
return self.rejected(command, ProtocolError::Internal);
|
||||
};
|
||||
match manager.replace_transaction(candidate) {
|
||||
Ok(()) => {
|
||||
let Some(session) = self.session.as_mut() else {
|
||||
return self.rejected(command, ProtocolError::Internal);
|
||||
};
|
||||
session.revision = next_revision;
|
||||
let (session_id, revision) = (session.id, session.revision);
|
||||
self.import = None;
|
||||
self.reply(
|
||||
request_id,
|
||||
session_id,
|
||||
revision,
|
||||
Operation::Import,
|
||||
ResultKind::Accepted,
|
||||
None,
|
||||
)
|
||||
}
|
||||
Err(CommitError::NoTransaction) => self.rejected(command, ProtocolError::BadState),
|
||||
Err(CommitError::InvalidCandidate(violation)) => {
|
||||
self.rejected(command, ProtocolError::Violation(violation))
|
||||
}
|
||||
Err(CommitError::Store(_)) => self.rejected(command, ProtocolError::Internal),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn crc32c(bytes: &[u8]) -> u32 {
|
||||
let mut crc = !0_u32;
|
||||
for byte in bytes {
|
||||
crc ^= u32::from(*byte);
|
||||
for _ in 0..8 {
|
||||
crc = if crc & 1 == 0 {
|
||||
crc >> 1
|
||||
} else {
|
||||
(crc >> 1) ^ 0x82f6_3b78
|
||||
};
|
||||
}
|
||||
}
|
||||
!crc
|
||||
}
|
||||
@@ -1,24 +1,39 @@
|
||||
//! Read-only protocol discovery and value-query responses.
|
||||
|
||||
use kaptan_config::{
|
||||
ConfigManager, ConfigModel, ConfigState, ConfigValue, FieldDescriptor, FieldId, Generation,
|
||||
ProfileStore,
|
||||
ConfigManager, ConfigModel, ConfigState, ConfigStore, ConfigValue, EnumOption, FieldDescriptor,
|
||||
FieldId,
|
||||
};
|
||||
|
||||
use super::{import::SnapshotImporter, session::ConfigProtocol};
|
||||
use crate::{ProtocolError, ValueSource};
|
||||
use super::session::ConfigProtocol;
|
||||
use crate::{Principal, ProtocolError, ValueSource};
|
||||
|
||||
/// Bounded descriptor page returned by a schema discovery request.
|
||||
/// One descriptor returned by a schema discovery request.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct DescriptorPage {
|
||||
pub struct DescriptorResponse {
|
||||
/// Request being answered.
|
||||
pub request_id: u32,
|
||||
/// First requested descriptor index.
|
||||
pub first: u16,
|
||||
/// Number of descriptors present in `descriptors`.
|
||||
pub len: u8,
|
||||
/// Fixed-capacity response page; `None` slots are unused.
|
||||
pub descriptors: [Option<&'static FieldDescriptor>; 4],
|
||||
/// Stable index of this descriptor in the advertised schema.
|
||||
pub index: u16,
|
||||
/// Self-describing field metadata.
|
||||
pub descriptor: FieldDescriptor,
|
||||
/// Factory value selected by the concrete board/image composition.
|
||||
pub default: ConfigValue,
|
||||
}
|
||||
|
||||
/// One named enum choice associated with a descriptor response.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct EnumOptionResponse {
|
||||
/// Request being answered.
|
||||
pub request_id: u32,
|
||||
/// Stable schema index of the owning descriptor.
|
||||
pub descriptor_index: u16,
|
||||
/// Stable field identity of the owning descriptor.
|
||||
pub field: FieldId,
|
||||
/// Stable zero-based order within the descriptor's choices.
|
||||
pub option_index: u8,
|
||||
/// Self-describing named choice.
|
||||
pub option: EnumOption,
|
||||
}
|
||||
|
||||
/// One typed value read from an explicitly selected configuration snapshot.
|
||||
@@ -41,20 +56,12 @@ pub struct ValueResponse {
|
||||
pub struct ConfigInfo {
|
||||
/// Request being answered.
|
||||
pub request_id: u32,
|
||||
/// Boot-active generation, or `None` for the factory profile.
|
||||
pub active_generation: Option<Generation>,
|
||||
/// Last committed generation, or `None` for the factory profile.
|
||||
pub committed_generation: Option<Generation>,
|
||||
/// Exact schema identifier expected by profile import.
|
||||
/// Stable schema identity for this target-described field registry.
|
||||
pub schema_id: [u8; 16],
|
||||
/// Version carried inside the one raw CBOR profile blob.
|
||||
pub profile_format: u16,
|
||||
/// Number of editable fields in the registry.
|
||||
pub field_count: u16,
|
||||
/// Current configuration lifecycle state.
|
||||
pub state: ConfigState,
|
||||
/// Deployment capabilities such as bounded CBOR import.
|
||||
pub capability_flags: u8,
|
||||
}
|
||||
|
||||
/// Exact response produced by the custom configuration service.
|
||||
@@ -64,13 +71,15 @@ pub enum ServiceResponse {
|
||||
Info(ConfigInfo),
|
||||
/// Completion for a mutating operation or rejected query.
|
||||
Result(crate::ConfigReply),
|
||||
/// Bounded self-describing schema page.
|
||||
Descriptors(DescriptorPage),
|
||||
/// One self-describing schema field.
|
||||
Descriptor(DescriptorResponse),
|
||||
/// One named choice for its explicitly identified enum descriptor.
|
||||
EnumOption(EnumOptionResponse),
|
||||
/// One typed scalar value.
|
||||
Value(ValueResponse),
|
||||
}
|
||||
|
||||
impl<I> ConfigProtocol<I> {
|
||||
impl ConfigProtocol {
|
||||
/// Returns static descriptor metadata by stable schema index.
|
||||
pub fn descriptor<C, S>(
|
||||
&self,
|
||||
@@ -79,7 +88,7 @@ impl<I> ConfigProtocol<I> {
|
||||
) -> Option<&'static FieldDescriptor>
|
||||
where
|
||||
C: ConfigModel,
|
||||
S: ProfileStore<C>,
|
||||
S: ConfigStore<C>,
|
||||
{
|
||||
manager.descriptor(index)
|
||||
}
|
||||
@@ -93,7 +102,7 @@ impl<I> ConfigProtocol<I> {
|
||||
) -> Option<ConfigValue>
|
||||
where
|
||||
C: ConfigModel,
|
||||
S: ProfileStore<C>,
|
||||
S: ConfigStore<C>,
|
||||
{
|
||||
match source {
|
||||
ValueSource::Active => manager.active_value(field),
|
||||
@@ -102,60 +111,65 @@ impl<I> ConfigProtocol<I> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn descriptors<C, S>(
|
||||
pub(super) fn descriptor_response<C, S>(
|
||||
&self,
|
||||
manager: &ConfigManager<C, S>,
|
||||
request_id: u32,
|
||||
first: u16,
|
||||
requested: u16,
|
||||
) -> DescriptorPage
|
||||
index: u16,
|
||||
) -> Option<DescriptorResponse>
|
||||
where
|
||||
C: ConfigModel,
|
||||
S: ProfileStore<C>,
|
||||
S: ConfigStore<C>,
|
||||
{
|
||||
let mut descriptors = [None; 4];
|
||||
let count = requested.min(descriptors.len() as u16);
|
||||
let mut len = 0;
|
||||
for offset in 0..count {
|
||||
let Some(index) = first.checked_add(offset) else {
|
||||
break;
|
||||
};
|
||||
let Some(descriptor) = manager.descriptor(index) else {
|
||||
break;
|
||||
};
|
||||
descriptors[usize::from(len)] = Some(descriptor);
|
||||
len += 1;
|
||||
}
|
||||
DescriptorPage {
|
||||
let descriptor = *manager.descriptor(index)?;
|
||||
let default = manager.factory_value(descriptor.id)?;
|
||||
Some(DescriptorResponse {
|
||||
request_id,
|
||||
first,
|
||||
len,
|
||||
descriptors,
|
||||
}
|
||||
index,
|
||||
descriptor,
|
||||
default,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn enum_option_response<C, S>(
|
||||
&self,
|
||||
manager: &ConfigManager<C, S>,
|
||||
request_id: u32,
|
||||
descriptor_index: u16,
|
||||
option_index: u8,
|
||||
) -> Option<EnumOptionResponse>
|
||||
where
|
||||
C: ConfigModel,
|
||||
S: ConfigStore<C>,
|
||||
{
|
||||
let descriptor = manager.descriptor(descriptor_index)?;
|
||||
let option = *descriptor.enum_options.get(usize::from(option_index))?;
|
||||
Some(EnumOptionResponse {
|
||||
request_id,
|
||||
descriptor_index,
|
||||
field: descriptor.id,
|
||||
option_index,
|
||||
option,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn info<C, S>(&self, manager: &ConfigManager<C, S>, request_id: u32) -> ConfigInfo
|
||||
where
|
||||
C: ConfigModel,
|
||||
S: ProfileStore<C>,
|
||||
I: SnapshotImporter<C>,
|
||||
S: ConfigStore<C>,
|
||||
{
|
||||
ConfigInfo {
|
||||
request_id,
|
||||
active_generation: manager.active_generation(),
|
||||
committed_generation: manager.committed_generation(),
|
||||
schema_id: C::SCHEMA_ID,
|
||||
profile_format: I::PROFILE_FORMAT,
|
||||
field_count: manager.field_count(),
|
||||
state: self.state,
|
||||
capability_flags: self.capability_flags_for::<C>(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn value_response<C, S>(
|
||||
&self,
|
||||
manager: &ConfigManager<C, S>,
|
||||
owner: u64,
|
||||
owner: Principal,
|
||||
request_id: u32,
|
||||
session_id: u32,
|
||||
field: FieldId,
|
||||
@@ -163,7 +177,7 @@ impl<I> ConfigProtocol<I> {
|
||||
) -> ServiceResponse
|
||||
where
|
||||
C: ConfigModel,
|
||||
S: ProfileStore<C>,
|
||||
S: ConfigStore<C>,
|
||||
{
|
||||
let (value, reply_session, revision) = match source {
|
||||
ValueSource::Active => (manager.active_value(field), 0, 0),
|
||||
@@ -176,7 +190,7 @@ impl<I> ConfigProtocol<I> {
|
||||
ProtocolError::InvalidSession,
|
||||
));
|
||||
};
|
||||
if session.id != session_id || session.owner != owner {
|
||||
if session.id != session_id || self.principal != Some(owner) {
|
||||
return ServiceResponse::Result(self.rejected_for(
|
||||
request_id,
|
||||
session_id,
|
||||
|
||||
@@ -3,34 +3,42 @@
|
||||
use kaptan_config::ConfigValue;
|
||||
|
||||
use super::session::ConfigProtocol;
|
||||
use crate::{ConfigCommand, ConfigReply, ProtocolError};
|
||||
|
||||
pub(super) const REQUEST_CACHE_CAPACITY: usize = 8;
|
||||
use crate::{ConfigCommand, ConfigReply, Operation, Principal, ProtocolError};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) struct RememberedResult {
|
||||
pub(super) owner: u64,
|
||||
pub(super) command: ConfigCommand,
|
||||
pub(super) reply: ConfigReply,
|
||||
pub(super) owner: Principal,
|
||||
}
|
||||
|
||||
impl<I> ConfigProtocol<I> {
|
||||
pub(super) fn cached(&self, owner: u64, command: ConfigCommand) -> Option<ConfigReply> {
|
||||
for cached in self.remembered.iter().flatten() {
|
||||
if cached.owner != owner || cached.command.request_id() != command.request_id() {
|
||||
continue;
|
||||
}
|
||||
if same_command(cached.command, command) {
|
||||
return Some(cached.reply);
|
||||
}
|
||||
return Some(self.rejected(command, ProtocolError::RequestConflict));
|
||||
impl ConfigProtocol {
|
||||
pub(super) fn cached(&self, owner: Principal, command: ConfigCommand) -> Option<ConfigReply> {
|
||||
let cached = self.remembered?;
|
||||
if cached.owner != owner || cached.command.request_id() != command.request_id() {
|
||||
return None;
|
||||
}
|
||||
if same_command(cached.command, command) {
|
||||
Some(cached.reply)
|
||||
} else {
|
||||
Some(self.rejected(command, ProtocolError::RequestConflict))
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(super) fn remember(&mut self, result: RememberedResult) {
|
||||
self.remembered[self.next_remembered] = Some(result);
|
||||
self.next_remembered = (self.next_remembered + 1) % REQUEST_CACHE_CAPACITY;
|
||||
pub(super) fn remember(
|
||||
&mut self,
|
||||
owner: Principal,
|
||||
command: ConfigCommand,
|
||||
reply: ConfigReply,
|
||||
) {
|
||||
if reply.operation == Operation::Query {
|
||||
return;
|
||||
}
|
||||
self.remembered = Some(RememberedResult {
|
||||
command,
|
||||
reply,
|
||||
owner,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,20 +57,36 @@ fn same_command(left: ConfigCommand, right: ConfigCommand) -> bool {
|
||||
(
|
||||
ConfigCommand::DescriptorRequest {
|
||||
request_id: left_request,
|
||||
first: left_first,
|
||||
count: left_count,
|
||||
index: left_index,
|
||||
target: left_target,
|
||||
},
|
||||
ConfigCommand::DescriptorRequest {
|
||||
request_id: right_request,
|
||||
first: right_first,
|
||||
count: right_count,
|
||||
index: right_index,
|
||||
target: right_target,
|
||||
},
|
||||
) => {
|
||||
left_request == right_request
|
||||
&& left_first == right_first
|
||||
&& left_count == right_count
|
||||
&& left_index == right_index
|
||||
&& left_target == right_target
|
||||
}
|
||||
(
|
||||
ConfigCommand::EnumOptionRequest {
|
||||
request_id: left_request,
|
||||
descriptor_index: left_descriptor,
|
||||
option_index: left_option,
|
||||
target: left_target,
|
||||
},
|
||||
ConfigCommand::EnumOptionRequest {
|
||||
request_id: right_request,
|
||||
descriptor_index: right_descriptor,
|
||||
option_index: right_option,
|
||||
target: right_target,
|
||||
},
|
||||
) => {
|
||||
left_request == right_request
|
||||
&& left_descriptor == right_descriptor
|
||||
&& left_option == right_option
|
||||
&& left_target == right_target
|
||||
}
|
||||
(
|
||||
@@ -90,19 +114,13 @@ fn same_command(left: ConfigCommand, right: ConfigCommand) -> bool {
|
||||
(
|
||||
ConfigCommand::Begin {
|
||||
request_id: left_request,
|
||||
expected_generation: left_generation,
|
||||
target: left_target,
|
||||
},
|
||||
ConfigCommand::Begin {
|
||||
request_id: right_request,
|
||||
expected_generation: right_generation,
|
||||
target: right_target,
|
||||
},
|
||||
) => {
|
||||
left_request == right_request
|
||||
&& left_generation == right_generation
|
||||
&& left_target == right_target
|
||||
}
|
||||
) => left_request == right_request && left_target == right_target,
|
||||
(
|
||||
ConfigCommand::Set {
|
||||
request_id: left_request,
|
||||
@@ -151,21 +169,18 @@ fn same_command(left: ConfigCommand, right: ConfigCommand) -> bool {
|
||||
ConfigCommand::Commit {
|
||||
request_id: left_request,
|
||||
session_id: left_session,
|
||||
expected_generation: left_generation,
|
||||
expected_revision: left_revision,
|
||||
target: left_target,
|
||||
},
|
||||
ConfigCommand::Commit {
|
||||
request_id: right_request,
|
||||
session_id: right_session,
|
||||
expected_generation: right_generation,
|
||||
expected_revision: right_revision,
|
||||
target: right_target,
|
||||
},
|
||||
) => {
|
||||
left_request == right_request
|
||||
&& left_session == right_session
|
||||
&& left_generation == right_generation
|
||||
&& left_revision == right_revision
|
||||
&& left_target == right_target
|
||||
}
|
||||
@@ -185,84 +200,6 @@ fn same_command(left: ConfigCommand, right: ConfigCommand) -> bool {
|
||||
&& left_session == right_session
|
||||
&& left_target == right_target
|
||||
}
|
||||
(
|
||||
ConfigCommand::ImportBegin {
|
||||
request_id: left_request,
|
||||
session_id: left_session,
|
||||
expected_revision: left_revision,
|
||||
length: left_length,
|
||||
schema_id: left_schema,
|
||||
crc32c: left_crc,
|
||||
target: left_target,
|
||||
},
|
||||
ConfigCommand::ImportBegin {
|
||||
request_id: right_request,
|
||||
session_id: right_session,
|
||||
expected_revision: right_revision,
|
||||
length: right_length,
|
||||
schema_id: right_schema,
|
||||
crc32c: right_crc,
|
||||
target: right_target,
|
||||
},
|
||||
) => {
|
||||
left_request == right_request
|
||||
&& left_session == right_session
|
||||
&& left_revision == right_revision
|
||||
&& left_length == right_length
|
||||
&& left_schema == right_schema
|
||||
&& left_crc == right_crc
|
||||
&& left_target == right_target
|
||||
}
|
||||
(
|
||||
ConfigCommand::ImportChunk {
|
||||
request_id: left_request,
|
||||
session_id: left_session,
|
||||
transfer_id: left_transfer,
|
||||
offset: left_offset,
|
||||
length: left_length,
|
||||
data: left_data,
|
||||
target: left_target,
|
||||
},
|
||||
ConfigCommand::ImportChunk {
|
||||
request_id: right_request,
|
||||
session_id: right_session,
|
||||
transfer_id: right_transfer,
|
||||
offset: right_offset,
|
||||
length: right_length,
|
||||
data: right_data,
|
||||
target: right_target,
|
||||
},
|
||||
) => {
|
||||
left_request == right_request
|
||||
&& left_session == right_session
|
||||
&& left_transfer == right_transfer
|
||||
&& left_offset == right_offset
|
||||
&& left_length == right_length
|
||||
&& left_data == right_data
|
||||
&& left_target == right_target
|
||||
}
|
||||
(
|
||||
ConfigCommand::ImportFinish {
|
||||
request_id: left_request,
|
||||
session_id: left_session,
|
||||
transfer_id: left_transfer,
|
||||
expected_revision: left_revision,
|
||||
target: left_target,
|
||||
},
|
||||
ConfigCommand::ImportFinish {
|
||||
request_id: right_request,
|
||||
session_id: right_session,
|
||||
transfer_id: right_transfer,
|
||||
expected_revision: right_revision,
|
||||
target: right_target,
|
||||
},
|
||||
) => {
|
||||
left_request == right_request
|
||||
&& left_session == right_session
|
||||
&& left_transfer == right_transfer
|
||||
&& left_revision == right_revision
|
||||
&& left_target == right_target
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user