/// Instruction for updating contacts. See each variant's steps. pubenum UpdateContactsInstruction { /// Run [`BeginTransactionInstruction`], wrapping any response into a /// [`UpdateContactsResponse::BeginTransactionResponse`].
BeginTransaction(BeginTransactionInstruction),
/// Run [`CommitTransactionInstruction`], wrapping any response into a /// [`UpdateContactsResponse::CommitTransactionResponse`].
ReflectAndCommitTransaction(CommitTransactionInstruction),
}
/// Possible response for an [`UpdateContactsInstruction`]. pubenum UpdateContactsResponse { /// Possible response for an inner [`BeginTransactionInstruction`].
BeginTransactionResponse(BeginTransactionResponse),
/// Possible response for an inner [`CommitTransactionInstruction`].
CommitTransactionResponse(CommitTransactionResponse),
}
/// Result of polling a [`UpdateContactsTask`]. pubtype UpdateContactsLoop = TaskLoop<UpdateContactsInstruction, ()>;
// Add tracing span // // TODO(LIB-16): This should be applied to the whole task somehow let _span = tracing::info_span! { "contacts", contacts = ?identities }.entered();
// Non-MD: Update contacts and done if context.d2x.is_none() { Self::update_contacts(&mut *context.contacts.borrow_mut(), state.contacts)?; return Ok((Self::Done, UpdateContactsLoop::Done(())));
}
// MD: We need to create a transaction.
// Precondition: All of the contacts must exist (hard error) let contact_provider = Rc::clone(&context.contacts); let precondition = Box::new(move || { let n_existing = contact_provider.borrow().has_many(&identities)?; if n_existing == identities.len() {
Ok(PreconditionVerdict::Continue)
} else { let message = "An existing contact disappeared";
error!(n_existing, n_expected = identities.len(), message);
Err(CspE2eProtocolError::DesyncError(message.to_owned()))
}
});
// Begin the transaction in the next state Self::poll_begin_transaction(
context,
BeginTransactionState {
contacts: state.contacts,
transaction_task: BeginTransactionSubtask::new(
precondition,
protobuf::d2d::transaction_scope::Scope::ContactSync,
None,
),
},
)
}
// Poll until the transaction is in progress match state.transaction_task.poll(d2x_context)? {
BeginTransactionLoop::Instruction(instruction) => { return Ok(( Self::BeginTransaction(state),
UpdateContactsLoop::Instruction(UpdateContactsInstruction::BeginTransaction(instruction)),
));
},
BeginTransactionLoop::Done(result) => match result {
BeginTransactionResult::TransactionInProgress => {},
BeginTransactionResult::TransactionAborted => { // The precondition should never abort, so this should never happen. let message = "Transaction aborted unexpectedly";
error!(message); return Err(CspE2eProtocolError::InternalError(message.into()));
},
},
}
// Encode and encrypt reflection messages containing the contacts to be updated let (reflect_messages, nonces) = state
.contacts
.iter_mut()
.map(|contact| {
ReflectPayload::encode_and_encrypt(
d2x_context,
ReflectFlags::default(),
protobuf::d2d::envelope::Content::ContactSync(protobuf::d2d::ContactSync {
action: Some(protobuf::d2d::contact_sync::Action::Update(
protobuf::d2d::contact_sync::Update {
contact: Some(protobuf::d2d_sync::Contact::from(&*contact)),
},
)),
}),
)
})
.collect::<Result<(Vec<ReflectPayload>, Vec<Nonce>), CspE2eProtocolError>>()?;
// Reflect and commit the transaction
d2x_context.nonce_storage.borrow_mut().add_many(nonces)?; let (transaction_state, commit_instruction) = CommitTransactionSubtask::new(reflect_messages);
Ok(( Self::ReflectAndCommitTransaction(ReflectAndCommitTransactionState {
contacts: state.contacts,
transaction_task: transaction_state,
}),
UpdateContactsLoop::Instruction(UpdateContactsInstruction::ReflectAndCommitTransaction(
commit_instruction,
)),
))
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.