1#![deny(missing_docs)]
2#![forbid(unsafe_code)]
3#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]
4mod bindings;
25pub mod constants;
26mod diff;
27mod error;
28#[cfg(feature = "network-client")]
29pub mod network_client;
30mod traits;
31
32#[cfg(any(
33 feature = "files",
34 feature = "listen",
35 feature = "network-client"
36))]
37pub mod transfer;
38
39#[cfg(feature = "hashcheck")]
40pub mod hashcheck;
41
42pub use bindings::*;
43pub use diff::*;
44pub use error::{AsConflict, ConflictError, Error, ErrorReply, NetworkError};
45pub use traits::*;
46
47use prost::{bytes::Buf, Message};
48
49#[cfg(feature = "network-client")]
50pub use reqwest;
51
52#[cfg(any(feature = "listen", feature = "pairing"))]
53pub use tokio_tungstenite;
54
55pub(crate) type Result<T> = std::result::Result<T, Error>;
57
58#[derive(Default, Debug)]
60pub enum HardConflictResolver {
61 #[default]
63 AutomaticFetch,
64}
65
66#[derive(Default, Debug)]
68pub struct SyncOptions {
69 pub origins: Vec<sos_core::Origin>,
71 pub hard_conflict_resolver: HardConflictResolver,
73}
74
75#[doc(hidden)]
80pub trait ProtoMessage {
81 #[allow(async_fn_in_trait)]
83 async fn encode_proto(self) -> Result<Vec<u8>>;
84
85 #[allow(async_fn_in_trait)]
87 async fn decode_proto<B>(buffer: B) -> Result<Self>
88 where
89 B: Buf + Send + 'static,
90 Self: Sized;
91}
92
93impl<T> ProtoMessage for T
94where
95 T: Message + Default + 'static,
96{
97 async fn encode_proto(self) -> Result<Vec<u8>> {
98 tokio::task::spawn_blocking(move || {
99 let mut buf = Vec::new();
100 buf.reserve(self.encoded_len());
101 self.encode(&mut buf)?;
102 Ok(buf)
103 })
104 .await?
105 }
106
107 async fn decode_proto<B>(buffer: B) -> Result<Self>
108 where
109 B: Buf + Send + 'static,
110 Self: Sized,
111 {
112 tokio::task::spawn_blocking(move || Ok(Self::decode(buffer)?)).await?
113 }
114}
115
116trait ProtoBinding {
119 type Inner: Message + Default;
120}
121
122#[doc(hidden)]
124pub trait WireEncodeDecode {
125 #[allow(async_fn_in_trait)]
127 async fn encode(self) -> Result<Vec<u8>>;
128
129 #[allow(async_fn_in_trait)]
131 async fn decode<B>(buffer: B) -> Result<Self>
132 where
133 B: Buf + Send + 'static,
134 Self: Sized;
135}
136
137impl<T> WireEncodeDecode for T
138where
139 T: ProtoBinding + Send + 'static,
140 <T as ProtoBinding>::Inner: From<T> + 'static,
141 T: TryFrom<<T as ProtoBinding>::Inner, Error = Error>,
142{
143 #[cfg(not(target_arch = "wasm32"))]
144 async fn encode(self) -> Result<Vec<u8>> {
145 tokio::task::spawn_blocking(move || {
146 let value: <Self as ProtoBinding>::Inner = self.into();
147 let mut buf = Vec::new();
148 buf.reserve(value.encoded_len());
149 value.encode(&mut buf)?;
150 Ok(buf)
151 })
152 .await?
153 }
154
155 #[cfg(not(target_arch = "wasm32"))]
156 async fn decode<B>(buffer: B) -> Result<Self>
157 where
158 B: Buf + Send + 'static,
159 Self: Sized,
160 {
161 tokio::task::spawn_blocking(move || {
162 let result = <<Self as ProtoBinding>::Inner>::decode(buffer)?;
163 Ok(result.try_into()?)
164 })
165 .await?
166 }
167
168 #[cfg(target_arch = "wasm32")]
169 async fn encode(self) -> Result<Vec<u8>> {
170 let value: <Self as ProtoBinding>::Inner = self.into();
171 let mut buf = Vec::new();
172 buf.reserve(value.encoded_len());
173 value.encode(&mut buf)?;
174 Ok(buf)
175 }
176
177 #[cfg(target_arch = "wasm32")]
178 async fn decode<B>(buffer: B) -> Result<Self>
179 where
180 B: Buf + Send + 'static,
181 Self: Sized,
182 {
183 let result = <<Self as ProtoBinding>::Inner>::decode(buffer)?;
184 Ok(result.try_into()?)
185 }
186}
187
188fn decode_uuid(id: &[u8]) -> Result<uuid::Uuid> {
189 let id: [u8; 16] = id.try_into()?;
190 Ok(uuid::Uuid::from_bytes(id))
191}
192
193fn encode_uuid(id: &uuid::Uuid) -> Vec<u8> {
194 id.as_bytes().to_vec()
195}
196
197pub fn is_offline() -> bool {
199 use sos_core::constants::SOS_OFFLINE;
200 std::env::var(SOS_OFFLINE).ok().is_some()
201}