include!(concat!(env!("OUT_DIR"), "/common.rs"));
use crate::{decode_uuid, encode_uuid, Error, ProtoBinding, Result};
use rs_merkle::{algorithms::Sha256, MerkleProof};
use sos_core::{
commit::{CommitHash, CommitProof, CommitState},
events::{patch::CheckedPatch, EventLogType, EventRecord},
SecretPath, UtcDateTime,
};
use time::{Duration, OffsetDateTime};
impl ProtoBinding for UtcDateTime {
type Inner = WireUtcDateTime;
}
impl TryFrom<WireUtcDateTime> for UtcDateTime {
type Error = Error;
fn try_from(value: WireUtcDateTime) -> Result<Self> {
let time = OffsetDateTime::from_unix_timestamp(value.seconds)?
+ Duration::nanoseconds(value.nanos as i64);
Ok(time.into())
}
}
impl From<UtcDateTime> for WireUtcDateTime {
fn from(value: UtcDateTime) -> Self {
let time: OffsetDateTime = value.into();
Self {
seconds: time.unix_timestamp(),
nanos: time.nanosecond(),
}
}
}
impl ProtoBinding for CommitHash {
type Inner = WireCommitHash;
}
impl TryFrom<WireCommitHash> for CommitHash {
type Error = Error;
fn try_from(value: WireCommitHash) -> Result<Self> {
let hash: [u8; 32] = value.hash.as_slice().try_into()?;
Ok(CommitHash(hash))
}
}
impl From<CommitHash> for WireCommitHash {
fn from(value: CommitHash) -> Self {
Self {
hash: value.as_ref().to_vec(),
}
}
}
impl ProtoBinding for CommitProof {
type Inner = WireCommitProof;
}
impl TryFrom<WireCommitProof> for CommitProof {
type Error = Error;
fn try_from(value: WireCommitProof) -> Result<Self> {
Ok(CommitProof {
root: value.root.unwrap().try_into()?,
length: value.length as usize,
proof: MerkleProof::<Sha256>::from_bytes(&value.proof)?,
indices: value.indices.into_iter().map(|i| i as usize).collect(),
})
}
}
impl From<CommitProof> for WireCommitProof {
fn from(value: CommitProof) -> Self {
Self {
root: Some(value.root.into()),
proof: value.proof.to_bytes(),
length: value.length as u64,
indices: value.indices.into_iter().map(|i| i as u64).collect(),
}
}
}
impl ProtoBinding for CommitState {
type Inner = WireCommitState;
}
impl TryFrom<WireCommitState> for CommitState {
type Error = Error;
fn try_from(value: WireCommitState) -> Result<Self> {
Ok(CommitState(
value.hash.unwrap().try_into()?,
value.proof.unwrap().try_into()?,
))
}
}
impl From<CommitState> for WireCommitState {
fn from(value: CommitState) -> Self {
Self {
hash: Some(value.0.into()),
proof: Some(value.1.into()),
}
}
}
impl ProtoBinding for EventRecord {
type Inner = WireEventRecord;
}
impl TryFrom<WireEventRecord> for EventRecord {
type Error = Error;
fn try_from(value: WireEventRecord) -> Result<Self> {
Ok(EventRecord::new(
value.time.unwrap().try_into()?,
value.last_commit.unwrap().try_into()?,
value.commit.unwrap().try_into()?,
value.event,
))
}
}
impl From<EventRecord> for WireEventRecord {
fn from(value: EventRecord) -> Self {
let (time, last_commit, commit, event): (
UtcDateTime,
CommitHash,
CommitHash,
Vec<u8>,
) = value.into();
Self {
time: Some(time.into()),
last_commit: Some(last_commit.into()),
commit: Some(commit.into()),
event,
}
}
}
impl ProtoBinding for CheckedPatch {
type Inner = WireCheckedPatch;
}
impl TryFrom<WireCheckedPatch> for CheckedPatch {
type Error = Error;
fn try_from(value: WireCheckedPatch) -> Result<Self> {
let inner = value.inner.unwrap();
Ok(match inner {
wire_checked_patch::Inner::Success(success) => {
Self::Success(success.proof.unwrap().try_into()?)
}
wire_checked_patch::Inner::Conflict(conflict) => {
let contains = if let Some(contains) = conflict.contains {
Some(contains.try_into()?)
} else {
None
};
Self::Conflict {
head: conflict.head.unwrap().try_into()?,
contains,
}
}
})
}
}
impl From<CheckedPatch> for WireCheckedPatch {
fn from(value: CheckedPatch) -> Self {
match value {
CheckedPatch::Success(proof) => WireCheckedPatch {
inner: Some(wire_checked_patch::Inner::Success(
WireCheckedPatchSuccess {
proof: Some(proof.into()),
},
)),
},
CheckedPatch::Conflict { head, contains } => WireCheckedPatch {
inner: Some(wire_checked_patch::Inner::Conflict(
WireCheckedPatchConflict {
head: Some(head.into()),
contains: contains.map(|c| c.into()),
},
)),
},
}
}
}
impl ProtoBinding for EventLogType {
type Inner = WireEventLogType;
}
impl TryFrom<WireEventLogType> for EventLogType {
type Error = Error;
fn try_from(value: WireEventLogType) -> Result<Self> {
let inner = value.inner.unwrap();
Ok(match inner {
wire_event_log_type::Inner::User(value) => {
EventLogType::Folder(decode_uuid(&value.folder_id)?)
}
wire_event_log_type::Inner::System(value) => {
let value: WireEventLogTypeSystem = value.try_into()?;
let name = value.as_str_name();
match name {
"Identity" => EventLogType::Identity,
"Account" => EventLogType::Account,
"Device" => EventLogType::Device,
#[cfg(feature = "files")]
"Files" => EventLogType::Files,
_ => unreachable!(),
}
}
})
}
}
impl From<EventLogType> for WireEventLogType {
fn from(value: EventLogType) -> Self {
if let EventLogType::Folder(id) = &value {
Self {
inner: Some(wire_event_log_type::Inner::User(
WireEventLogTypeUser {
folder_id: encode_uuid(id),
},
)),
}
} else {
let system: i32 = match value {
EventLogType::Identity => {
WireEventLogTypeSystem::from_str_name("Identity").unwrap()
as i32
}
EventLogType::Account => {
WireEventLogTypeSystem::from_str_name("Account").unwrap()
as i32
}
EventLogType::Device => {
WireEventLogTypeSystem::from_str_name("Device").unwrap()
as i32
}
#[cfg(feature = "files")]
EventLogType::Files => {
WireEventLogTypeSystem::from_str_name("Files").unwrap()
as i32
}
_ => unreachable!(),
};
Self {
inner: Some(wire_event_log_type::Inner::System(system)),
}
}
}
}
impl TryFrom<WireSecretPath> for SecretPath {
type Error = Error;
fn try_from(value: WireSecretPath) -> Result<Self> {
Ok(SecretPath(
decode_uuid(&value.folder_id)?,
decode_uuid(&value.secret_id)?,
))
}
}
impl From<SecretPath> for WireSecretPath {
fn from(value: SecretPath) -> Self {
WireSecretPath {
folder_id: encode_uuid(&value.0),
secret_id: encode_uuid(&value.1),
}
}
}