pub use grpc::Code;
pub use grpc::Status;
use mesh::local_node::Port;
use mesh::payload::encoding::MessageEncoding;
use mesh::payload::protobuf::FieldSizer;
use mesh::payload::protobuf::FieldWriter;
use mesh::payload::protobuf::MessageReader;
use mesh::payload::protobuf::MessageSizer;
use mesh::payload::protobuf::MessageWriter;
use mesh::payload::DefaultEncoding;
use mesh::payload::MessageDecode;
use mesh::payload::MessageEncode;
use mesh::payload::Result;
use mesh::resource::Resource;
mod grpc {
use prost as _;
use prost_types as _;
include!(concat!(env!("OUT_DIR"), "/google.rpc.rs"));
impl std::fmt::Display for Code {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for Code {}
}
#[derive(mesh::MeshPayload)]
pub(crate) struct GenericRpc {
#[mesh(1)]
pub method: String,
#[mesh(2)]
pub data: Vec<u8>,
#[mesh(3)]
pub port: Port, }
impl GenericRpc {
pub(crate) fn respond_status(self, status: Status) {
let sender =
mesh::OneshotSender::<std::result::Result<std::convert::Infallible, Status>>::from(
self.port,
);
sender.send(Err(status));
}
}
#[derive(mesh::MeshPayload)]
struct GenericRpcView<'a> {
#[mesh(1)]
method: &'a str,
#[mesh(2)]
data: &'a [u8],
#[mesh(3)]
port: Port,
}
pub trait ServiceRpc: 'static + Send + Sized {
const NAME: &'static str;
fn method(&self) -> &'static str;
fn encode(self, writer: FieldWriter<'_, '_, Resource>) -> Port;
fn compute_size(&mut self, sizer: FieldSizer<'_>);
fn decode(
method: &str,
port: Port,
data: &[u8],
) -> std::result::Result<Self, (ServiceRpcError, Port)>;
}
pub enum ServiceRpcError {
UnknownMethod,
InvalidInput(mesh::payload::Error),
}
#[doc(hidden)]
pub(crate) enum DecodedRpc<T> {
Rpc(T),
Err {
rpc: GenericRpc,
err: ServiceRpcError,
},
}
pub(crate) struct DecodedRpcEncoder;
impl<T: ServiceRpc> DefaultEncoding for DecodedRpc<T> {
type Encoding = MessageEncoding<DecodedRpcEncoder>;
}
impl<T: ServiceRpc> MessageEncode<DecodedRpc<T>, Resource> for DecodedRpcEncoder {
fn write_message(item: DecodedRpc<T>, mut writer: MessageWriter<'_, '_, Resource>) {
match item {
DecodedRpc::Rpc(rpc) => {
writer.field(1).bytes(rpc.method().as_bytes());
let port = rpc.encode(writer.field(2));
writer.field(3).resource(Resource::Port(port));
}
DecodedRpc::Err { rpc, err: _ } => {
<GenericRpc as DefaultEncoding>::Encoding::write_message(rpc, writer)
}
}
}
fn compute_message_size(item: &mut DecodedRpc<T>, mut sizer: MessageSizer<'_>) {
match item {
DecodedRpc::Rpc(rpc) => {
sizer.field(1).bytes(rpc.method().len());
rpc.compute_size(sizer.field(2));
sizer.field(3).resource();
}
DecodedRpc::Err { rpc, err: _ } => {
<GenericRpc as DefaultEncoding>::Encoding::compute_message_size(rpc, sizer)
}
}
}
}
impl<'a, T: ServiceRpc> MessageDecode<'a, DecodedRpc<T>, Resource> for DecodedRpcEncoder {
fn read_message(
item: &mut mesh::payload::inplace::InplaceOption<'_, DecodedRpc<T>>,
reader: MessageReader<'a, '_, Resource>,
) -> Result<()> {
mesh::payload::inplace_none!(v: GenericRpcView<'_>);
<GenericRpcView<'_> as DefaultEncoding>::Encoding::read_message(&mut v, reader)?;
let v = v.take().expect("should be constructed");
let rpc = match T::decode(v.method, v.port, v.data) {
Ok(rpc) => DecodedRpc::Rpc(rpc),
Err((err, port)) => {
let rpc = GenericRpc {
method: v.method.to_string(),
data: v.data.to_vec(),
port,
};
DecodedRpc::Err { rpc, err }
}
};
item.set(rpc);
Ok(())
}
}