use std::{collections::HashMap, fmt, net::SocketAddr, path::PathBuf, str::FromStr};
use bytes::Bytes;
use derive_more::{From, TryInto};
use iroh_bytes::util::{BlobFormat, SetTagOption, Tag};
pub use iroh_bytes::{protocol::RequestToken, provider::GetProgress, Hash};
use iroh_gossip::proto::util::base32;
use iroh_net::{
key::PublicKey,
magic_endpoint::{ConnectionInfo, PeerAddr},
};
use iroh_sync::{
store::GetFilter,
sync::{NamespaceId, SignedEntry},
AuthorId,
};
use quic_rpc::{
message::{Msg, RpcMsg, ServerStreaming, ServerStreamingMsg},
Service,
};
use serde::{Deserialize, Serialize};
pub use iroh_bytes::{baomap::ValidateProgress, provider::AddProgress, util::RpcResult};
use crate::sync_engine::{LiveEvent, LiveStatus};
pub type KeyBytes = [u8; 32];
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobAddPathRequest {
pub path: PathBuf,
pub in_place: bool,
pub tag: SetTagOption,
}
impl Msg<ProviderService> for BlobAddPathRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for BlobAddPathRequest {
type Response = AddProgress;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlobDownloadRequest {
pub hash: Hash,
pub recursive: bool,
pub peer: PeerAddr,
pub token: Option<RequestToken>,
pub tag: SetTagOption,
pub out: DownloadLocation,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DownloadLocation {
Internal,
External {
path: String,
in_place: bool,
},
}
impl Msg<ProviderService> for BlobDownloadRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for BlobDownloadRequest {
type Response = GetProgress;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobValidateRequest {
pub repair: bool,
}
impl Msg<ProviderService> for BlobValidateRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for BlobValidateRequest {
type Response = ValidateProgress;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobListRequest;
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobListResponse {
pub path: String,
pub hash: Hash,
pub size: u64,
}
impl Msg<ProviderService> for BlobListRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for BlobListRequest {
type Response = BlobListResponse;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobListIncompleteRequest;
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobListIncompleteResponse {
pub size: u64,
pub expected_size: u64,
pub hash: Hash,
}
impl Msg<ProviderService> for BlobListIncompleteRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for BlobListIncompleteRequest {
type Response = BlobListIncompleteResponse;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobListCollectionsRequest;
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobListCollectionsResponse {
pub tag: Tag,
pub hash: Hash,
pub total_blobs_count: Option<u64>,
pub total_blobs_size: Option<u64>,
}
impl Msg<ProviderService> for BlobListCollectionsRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for BlobListCollectionsRequest {
type Response = BlobListCollectionsResponse;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ListTagsRequest;
#[derive(Debug, Serialize, Deserialize)]
pub struct ListTagsResponse {
pub name: Tag,
pub format: BlobFormat,
pub hash: Hash,
}
impl Msg<ProviderService> for ListTagsRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for ListTagsRequest {
type Response = ListTagsResponse;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct BlobDeleteBlobRequest {
pub hash: Hash,
}
impl RpcMsg<ProviderService> for BlobDeleteBlobRequest {
type Response = RpcResult<()>;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DeleteTagRequest {
pub name: Tag,
}
impl RpcMsg<ProviderService> for DeleteTagRequest {
type Response = RpcResult<()>;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct NodeConnectionsRequest;
#[derive(Debug, Serialize, Deserialize)]
pub struct NodeConnectionsResponse {
pub conn_info: ConnectionInfo,
}
impl Msg<ProviderService> for NodeConnectionsRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for NodeConnectionsRequest {
type Response = RpcResult<NodeConnectionsResponse>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeConnectionInfoRequest {
pub node_id: PublicKey,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct NodeConnectionInfoResponse {
pub conn_info: Option<ConnectionInfo>,
}
impl RpcMsg<ProviderService> for NodeConnectionInfoRequest {
type Response = RpcResult<NodeConnectionInfoResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NodeShutdownRequest {
pub force: bool,
}
impl RpcMsg<ProviderService> for NodeShutdownRequest {
type Response = ();
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NodeStatusRequest;
impl RpcMsg<ProviderService> for NodeStatusRequest {
type Response = NodeStatusResponse;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NodeStatusResponse {
pub node_id: Box<PublicKey>,
pub listen_addrs: Vec<SocketAddr>,
pub version: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NodeWatchRequest;
impl Msg<ProviderService> for NodeWatchRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for NodeWatchRequest {
type Response = NodeWatchResponse;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NodeWatchResponse {
pub version: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct VersionResponse {
pub version: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct AuthorListRequest {}
impl Msg<ProviderService> for AuthorListRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for AuthorListRequest {
type Response = RpcResult<AuthorListResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct AuthorListResponse {
pub author_id: AuthorId,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct AuthorCreateRequest;
impl RpcMsg<ProviderService> for AuthorCreateRequest {
type Response = RpcResult<AuthorCreateResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct AuthorCreateResponse {
pub author_id: AuthorId,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct AuthorImportRequest {
pub key: KeyBytes,
}
impl RpcMsg<ProviderService> for AuthorImportRequest {
type Response = RpcResult<AuthorImportResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct AuthorImportResponse {
pub author_id: AuthorId,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
pub enum ShareMode {
Read,
Write,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocSubscribeRequest {
pub doc_id: NamespaceId,
}
impl Msg<ProviderService> for DocSubscribeRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for DocSubscribeRequest {
type Response = RpcResult<DocSubscribeResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocSubscribeResponse {
pub event: LiveEvent,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocListRequest {}
impl Msg<ProviderService> for DocListRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for DocListRequest {
type Response = RpcResult<DocListResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocListResponse {
pub id: NamespaceId,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocCreateRequest {}
impl RpcMsg<ProviderService> for DocCreateRequest {
type Response = RpcResult<DocCreateResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocCreateResponse {
pub id: NamespaceId,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct DocTicket {
pub key: KeyBytes,
pub peers: Vec<PeerAddr>,
}
impl DocTicket {
pub fn new(key: KeyBytes, peers: Vec<PeerAddr>) -> Self {
Self { key, peers }
}
pub fn to_bytes(&self) -> anyhow::Result<Vec<u8>> {
let bytes = postcard::to_stdvec(&self)?;
Ok(bytes)
}
pub fn from_bytes(bytes: &[u8]) -> anyhow::Result<Self> {
let slf = postcard::from_bytes(bytes)?;
Ok(slf)
}
}
impl FromStr for DocTicket {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_bytes(&base32::parse_vec(s)?)
}
}
impl fmt::Display for DocTicket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
base32::fmt(self.to_bytes().expect("failed to serialize"))
)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocImportRequest(pub DocTicket);
impl RpcMsg<ProviderService> for DocImportRequest {
type Response = RpcResult<DocImportResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocImportResponse {
pub doc_id: NamespaceId,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocShareRequest {
pub doc_id: NamespaceId,
pub mode: ShareMode,
}
impl RpcMsg<ProviderService> for DocShareRequest {
type Response = RpcResult<DocShareResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocShareResponse(pub DocTicket);
#[derive(Serialize, Deserialize, Debug)]
pub struct DocInfoRequest {
pub doc_id: NamespaceId,
}
impl RpcMsg<ProviderService> for DocInfoRequest {
type Response = RpcResult<DocInfoResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocInfoResponse {
pub status: LiveStatus,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocStartSyncRequest {
pub doc_id: NamespaceId,
pub peers: Vec<PeerAddr>,
}
impl RpcMsg<ProviderService> for DocStartSyncRequest {
type Response = RpcResult<DocStartSyncResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocStartSyncResponse {}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocStopSyncRequest {
pub doc_id: NamespaceId,
}
impl RpcMsg<ProviderService> for DocStopSyncRequest {
type Response = RpcResult<DocStopSyncResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocStopSyncResponse {}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocSetRequest {
pub doc_id: NamespaceId,
pub author_id: AuthorId,
pub key: Vec<u8>,
pub value: Vec<u8>,
}
impl RpcMsg<ProviderService> for DocSetRequest {
type Response = RpcResult<DocSetResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocSetResponse {
pub entry: SignedEntry,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocGetManyRequest {
pub doc_id: NamespaceId,
pub filter: GetFilter,
}
impl Msg<ProviderService> for DocGetManyRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for DocGetManyRequest {
type Response = RpcResult<DocGetManyResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocGetManyResponse {
pub entry: SignedEntry,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocGetOneRequest {
pub doc_id: NamespaceId,
pub key: Vec<u8>,
pub author: AuthorId,
}
impl RpcMsg<ProviderService> for DocGetOneRequest {
type Response = RpcResult<DocGetOneResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DocGetOneResponse {
pub entry: Option<SignedEntry>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct BytesGetRequest {
pub hash: Hash,
}
impl Msg<ProviderService> for BytesGetRequest {
type Pattern = ServerStreaming;
}
impl ServerStreamingMsg<ProviderService> for BytesGetRequest {
type Response = RpcResult<BlobReadResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub enum BlobReadResponse {
Entry {
size: u64,
is_complete: bool,
},
Data {
chunk: Bytes,
},
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NodeStatsRequest {}
impl RpcMsg<ProviderService> for NodeStatsRequest {
type Response = RpcResult<NodeStatsResponse>;
}
#[derive(Serialize, Deserialize, Debug)]
pub struct CounterStats {
pub value: u64,
pub description: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NodeStatsResponse {
pub stats: HashMap<String, CounterStats>,
}
#[derive(Debug, Clone)]
pub struct ProviderService;
#[allow(missing_docs)]
#[derive(strum::Display, Debug, Serialize, Deserialize, From, TryInto)]
pub enum ProviderRequest {
NodeStatus(NodeStatusRequest),
NodeStats(NodeStatsRequest),
NodeShutdown(NodeShutdownRequest),
NodeConnections(NodeConnectionsRequest),
NodeConnectionInfo(NodeConnectionInfoRequest),
NodeWatch(NodeWatchRequest),
BlobRead(BytesGetRequest),
BlobAddPath(BlobAddPathRequest),
BlobDownload(BlobDownloadRequest),
BlobList(BlobListRequest),
BlobListIncomplete(BlobListIncompleteRequest),
BlobListCollections(BlobListCollectionsRequest),
BlobDeleteBlob(BlobDeleteBlobRequest),
BlobValidate(BlobValidateRequest),
DeleteTag(DeleteTagRequest),
ListTags(ListTagsRequest),
DocInfo(DocInfoRequest),
DocList(DocListRequest),
DocCreate(DocCreateRequest),
DocImport(DocImportRequest),
DocSet(DocSetRequest),
DocGet(DocGetManyRequest),
DocGetOne(DocGetOneRequest),
DocStartSync(DocStartSyncRequest),
DocStopSync(DocStopSyncRequest),
DocShare(DocShareRequest),
DocSubscribe(DocSubscribeRequest),
AuthorList(AuthorListRequest),
AuthorCreate(AuthorCreateRequest),
AuthorImport(AuthorImportRequest),
}
#[allow(missing_docs, clippy::large_enum_variant)]
#[derive(Debug, Serialize, Deserialize, From, TryInto)]
pub enum ProviderResponse {
NodeStatus(NodeStatusResponse),
NodeStats(RpcResult<NodeStatsResponse>),
NodeConnections(RpcResult<NodeConnectionsResponse>),
NodeConnectionInfo(RpcResult<NodeConnectionInfoResponse>),
NodeShutdown(()),
NodeWatch(NodeWatchResponse),
BlobRead(RpcResult<BlobReadResponse>),
BlobAddPath(AddProgress),
BlobDownload(GetProgress),
BlobList(BlobListResponse),
BlobListIncomplete(BlobListIncompleteResponse),
BlobListCollections(BlobListCollectionsResponse),
BlobValidate(ValidateProgress),
ListTags(ListTagsResponse),
DeleteTag(RpcResult<()>),
DocInfo(RpcResult<DocInfoResponse>),
DocList(RpcResult<DocListResponse>),
DocCreate(RpcResult<DocCreateResponse>),
DocImport(RpcResult<DocImportResponse>),
DocSet(RpcResult<DocSetResponse>),
DocGet(RpcResult<DocGetManyResponse>),
DocGetOne(RpcResult<DocGetOneResponse>),
DocShare(RpcResult<DocShareResponse>),
DocStartSync(RpcResult<DocStartSyncResponse>),
DocStopSync(RpcResult<DocStopSyncResponse>),
DocSubscribe(RpcResult<DocSubscribeResponse>),
AuthorList(RpcResult<AuthorListResponse>),
AuthorCreate(RpcResult<AuthorCreateResponse>),
AuthorImport(RpcResult<AuthorImportResponse>),
}
impl Service for ProviderService {
type Req = ProviderRequest;
type Res = ProviderResponse;
}