use crate::{
AgentInfoSigned, DynPeerMetaStore, DynPeerStore, K2Error, builder, config,
};
use crate::{
BoxFut, DynFetch, K2Result, OpId, SpaceId, Url, transport::DynTransport,
};
use bytes::{Bytes, BytesMut};
use prost::Message;
use std::sync::Arc;
pub(crate) mod proto {
include!("../proto/gen/kitsune2.publish.rs");
}
pub use proto::{
K2PublishMessage, PublishAgent, PublishOpEntry, PublishOps,
k2_publish_message::*,
};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PublishOp {
pub op_id: OpId,
pub metadata: Option<Bytes>,
}
impl From<Vec<PublishOp>> for PublishOps {
fn from(value: Vec<PublishOp>) -> Self {
Self {
entries: value
.into_iter()
.map(|op| PublishOpEntry {
op_id: op.op_id.into(),
metadata: op.metadata,
})
.collect(),
}
}
}
impl From<PublishOps> for Vec<PublishOp> {
fn from(value: PublishOps) -> Self {
value
.entries
.into_iter()
.map(|entry| PublishOp {
op_id: OpId::from(entry.op_id),
metadata: entry.metadata,
})
.collect()
}
}
fn serialize_publish_ops(ops: Vec<PublishOp>) -> Bytes {
let mut out = BytesMut::new();
PublishOps::from(ops)
.encode(&mut out)
.expect("failed to encode publish ops request");
out.freeze()
}
pub fn serialize_publish_ops_message(ops: Vec<PublishOp>) -> Bytes {
let mut out = BytesMut::new();
let data = serialize_publish_ops(ops);
let publish_message = K2PublishMessage {
publish_message_type: PublishMessageType::Ops.into(),
data,
};
publish_message
.encode(&mut out)
.expect("failed to encode publish ops message");
out.freeze()
}
impl TryFrom<&Arc<AgentInfoSigned>> for PublishAgent {
type Error = K2Error;
fn try_from(value: &Arc<AgentInfoSigned>) -> K2Result<Self> {
let agent_info_encoded = value.encode()?;
Ok(Self {
agent_info: agent_info_encoded,
})
}
}
pub fn serialize_publish_agent(
value: &Arc<AgentInfoSigned>,
) -> K2Result<Bytes> {
let mut out = BytesMut::new();
PublishAgent::try_from(value)?
.encode(&mut out)
.expect("failed to encode publish agent request");
Ok(out.freeze())
}
pub fn serialize_publish_agent_message(
value: &Arc<AgentInfoSigned>,
) -> K2Result<Bytes> {
let mut out = BytesMut::new();
let data = serialize_publish_agent(value)?;
let publish_message = K2PublishMessage {
publish_message_type: PublishMessageType::Agent.into(),
data,
};
publish_message
.encode(&mut out)
.expect("failed to encode publish agent message");
Ok(out.freeze())
}
pub trait Publish: 'static + Send + Sync + std::fmt::Debug {
fn publish_ops(
&self,
ops: Vec<PublishOp>,
target: Url,
) -> BoxFut<'_, K2Result<()>>;
fn publish_agent(
&self,
agent_info: Arc<AgentInfoSigned>,
target: Url,
) -> BoxFut<'_, K2Result<()>>;
}
pub type DynPublish = Arc<dyn Publish>;
pub trait PublishFactory: 'static + Send + Sync + std::fmt::Debug {
fn default_config(&self, config: &mut config::Config) -> K2Result<()>;
fn validate_config(&self, config: &config::Config) -> K2Result<()>;
fn create(
&self,
builder: Arc<builder::Builder>,
space_id: SpaceId,
fetch: DynFetch,
peer_store: DynPeerStore,
peer_meta_store: DynPeerMetaStore,
transport: DynTransport,
) -> BoxFut<'static, K2Result<DynPublish>>;
}
pub type DynPublishFactory = Arc<dyn PublishFactory>;
#[cfg(test)]
mod test {
use super::*;
use prost::Message;
#[test]
fn happy_publish_ops_encode_decode() {
let op_1 = PublishOp {
op_id: OpId::from(Bytes::from_static(b"some_op_id")),
metadata: Some(Bytes::from_static(b"meta1")),
};
let op_2 = PublishOp {
op_id: OpId::from(Bytes::from_static(b"another_op_id")),
metadata: None,
};
let ops = vec![op_1, op_2];
let publish_ops = PublishOps::from(ops.clone());
let enc = publish_ops.encode_to_vec();
let dec = PublishOps::decode(enc.as_slice()).unwrap();
let dec_ops = Vec::<PublishOp>::from(dec);
assert_eq!(ops, dec_ops);
}
#[test]
fn happy_publish_ops_message_encode_decode() {
let op = PublishOp {
op_id: OpId::from(Bytes::from_static(b"id_1")),
metadata: Some(Bytes::from_static(b"host_meta")),
};
let ops = vec![op.clone()];
let message = serialize_publish_ops_message(ops);
let decoded = K2PublishMessage::decode(message).unwrap();
assert_eq!(
decoded.publish_message_type,
i32::from(PublishMessageType::Ops)
);
let pub_ops = PublishOps::decode(decoded.data).unwrap();
let decoded_ops = Vec::<PublishOp>::from(pub_ops);
assert_eq!(vec![op], decoded_ops);
}
}