diff --git a/helloworld.rs b/helloworld.rs new file mode 100644 index 0000000..957a965 --- /dev/null +++ b/helloworld.rs @@ -0,0 +1,773 @@ +// @generated by protoc-gen-roto — do not edit +#[allow(unused_imports)] + +use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage}; +use std::str; +use bytes::{Bytes, BytesMut, Buf, BufMut}; +use tonic::{Request, Response, Status}; +use tokio_stream::Stream; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; +use std::future::Future; +use tonic::body::BoxBody; +use tower::Service; +use futures_util::StreamExt; +use http_body_util::BodyExt; +use http_body::Body; +use roto_tonic::{BufferPool, StatusBody}; + + +pub struct Hello<'a> { + accessor: roto_runtime::ProtoAccessor<'a>, + name_offset: Option, + d_offset: Option, + f_offset: Option, + b_offset: Option, + n_offset: Option, + l_offset: Option, + c1_offset: Option, + c2_offset: Option, + pets_start: Option, + pets_end: Option, +} + +impl<'a> Hello<'a> { + pub fn new(data: &'a [u8]) -> roto_runtime::Result { + let accessor = roto_runtime::ProtoAccessor::new(data)?; + let mut name_offset = None; + let mut d_offset = None; + let mut f_offset = None; + let mut b_offset = None; + let mut n_offset = None; + let mut l_offset = None; + let mut c1_offset = None; + let mut c2_offset = None; + let mut pets_start = None; + let mut pets_end = None; + for item in accessor.fields() { + let (offset, tag, _) = item?; + if tag.field_number == 1 { name_offset = Some(offset); } + if tag.field_number == 2 { d_offset = Some(offset); } + if tag.field_number == 3 { f_offset = Some(offset); } + if tag.field_number == 4 { b_offset = Some(offset); } + if tag.field_number == 5 { n_offset = Some(offset); } + if tag.field_number == 6 { l_offset = Some(offset); } + if tag.field_number == 7 { c1_offset = Some(offset); } + if tag.field_number == 8 { c2_offset = Some(offset); } + if tag.field_number == 9 { + if pets_start.is_none() { pets_start = Some(offset); } + pets_end = Some(offset); + } + } + + Ok(Self { + accessor, +name_offset, +d_offset, +f_offset, +b_offset, +n_offset, +l_offset, +c1_offset, +c2_offset, +pets_start, pets_end, + }) + } + + pub fn name(&self) -> roto_runtime::Result<&'a str> { + let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> { + self.name().or(Ok("")) + } + + pub fn has_name(&self) -> bool { self.name_offset.is_some() } + + pub fn d(&self) -> roto_runtime::Result { + let offset = self.d_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + Ok(f64::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?)) + } + + pub fn d_or_default(&self) -> roto_runtime::Result { + self.d().or(Ok(0.0)) + } + + pub fn has_d(&self) -> bool { self.d_offset.is_some() } + + pub fn f(&self) -> roto_runtime::Result { + let offset = self.f_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + Ok(f32::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?)) + } + + pub fn f_or_default(&self) -> roto_runtime::Result { + self.f().or(Ok(0.0)) + } + + pub fn has_f(&self) -> bool { self.f_offset.is_some() } + + pub fn b(&self) -> roto_runtime::Result { + let offset = self.b_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn b_or_default(&self) -> roto_runtime::Result { + self.b().or(Ok(false)) + } + + pub fn has_b(&self) -> bool { self.b_offset.is_some() } + + pub fn n(&self) -> roto_runtime::Result { + let offset = self.n_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn n_or_default(&self) -> roto_runtime::Result { + self.n().or(Ok(0)) + } + + pub fn has_n(&self) -> bool { self.n_offset.is_some() } + + pub fn l(&self) -> roto_runtime::Result { + let offset = self.l_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn l_or_default(&self) -> roto_runtime::Result { + self.l().or(Ok(0)) + } + + pub fn has_l(&self) -> bool { self.l_offset.is_some() } + + pub fn c1(&self) -> roto_runtime::Result<&'a str> { + let offset = self.c1_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn c1_or_default(&self) -> roto_runtime::Result<&'a str> { + self.c1().or(Ok("")) + } + + pub fn has_c1(&self) -> bool { self.c1_offset.is_some() } + + pub fn c2(&self) -> roto_runtime::Result { + let offset = self.c2_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn c2_or_default(&self) -> roto_runtime::Result { + self.c2().or(Ok(false)) + } + + pub fn has_c2(&self) -> bool { self.c2_offset.is_some() } + + pub fn pets(&self) -> roto_runtime::RepeatedFieldIterator<'a> { + match (self.pets_start, self.pets_end) { + (Some(start), Some(end)) => self.accessor.iter_repeated_range(9, start, end), + _ => self.accessor.iter_repeated(9), + } + } + + pub fn which_choice(&self) -> roto_runtime::Result> > { + if self.c1_offset.is_some() { + return Ok(Some(hello::Choice::c1 (self.c1()?))); + } + if self.c2_offset.is_some() { + return Ok(Some(hello::Choice::c2 (self.c2()?))); + } + Ok(None) + } + + pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { + self.accessor.raw_fields() + } + +} + +pub struct HelloBuilder<'b> { + builder: roto_runtime::ProtoBuilder<'b>, + name_written: bool, + d_written: bool, + f_written: bool, + b_written: bool, + n_written: bool, + l_written: bool, + c1_written: bool, + c2_written: bool, + pets_written: bool, +} + +impl<'b> HelloBuilder<'b> { + pub fn builder(buf: &mut [u8]) -> HelloBuilder<'_> { + HelloBuilder { + builder: roto_runtime::ProtoBuilder::new(buf), + name_written: false, + d_written: false, + f_written: false, + b_written: false, + n_written: false, + l_written: false, + c1_written: false, + c2_written: false, + pets_written: false, + } + } + + pub fn name(mut self, value: &str) -> roto_runtime::Result { + self.builder.write_string(1, value)?; + self.name_written = true; + Ok(self) + } + + pub fn d(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(2, value)?; + self.d_written = true; + Ok(self) + } + + pub fn f(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(3, value)?; + self.f_written = true; + Ok(self) + } + + pub fn b(mut self, value: u64) -> roto_runtime::Result { + self.builder.write_varint(4, value)?; + self.b_written = true; + Ok(self) + } + + pub fn n(mut self, value: i32) -> roto_runtime::Result { + self.builder.write_int32(5, value)?; + self.n_written = true; + Ok(self) + } + + pub fn l(mut self, value: u64) -> roto_runtime::Result { + self.builder.write_varint(6, value)?; + self.l_written = true; + Ok(self) + } + + pub fn c1(mut self, value: &str) -> roto_runtime::Result { + self.builder.write_string(7, value)?; + self.c1_written = true; + Ok(self) + } + + pub fn c2(mut self, value: u64) -> roto_runtime::Result { + self.builder.write_varint(8, value)?; + self.c2_written = true; + Ok(self) + } + + pub fn pets(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(9, value)?; + self.pets_written = true; + Ok(self) + } + + pub fn with(mut self, msg: &Hello<'_>) -> roto_runtime::Result { + for item in msg.accessor.raw_fields() { + let (field_number, raw_bytes) = item?; + let is_written = match field_number { + 1 => self.name_written, + 2 => self.d_written, + 3 => self.f_written, + 4 => self.b_written, + 5 => self.n_written, + 6 => self.l_written, + 7 => self.c1_written, + 8 => self.c2_written, + 9 => self.pets_written, + _ => false, + }; + if !is_written { + self.builder.write_raw(raw_bytes)?; + } + } + Ok(self) + } + + pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { + self.builder.finish() + } +} + +pub struct OwnedHello { + pub data: bytes::Bytes, +} + +impl roto_runtime::RotoOwned for OwnedHello { + type Reader<'a> = Hello<'a>; + fn reader(&self) -> Hello<'_> { + Hello::new(&self.data).expect("failed to create reader") + } +} + +impl roto_runtime::RotoMessage for OwnedHello { + fn decode(buf: bytes::Bytes) -> roto_runtime::Result { + Ok(OwnedHello { data: buf }) + } + + fn bytes(&self) -> bytes::Bytes { + self.data.clone() + } +} + +pub mod hello { +pub struct Pet<'a> { + accessor: roto_runtime::ProtoAccessor<'a>, + name_offset: Option, + color_offset: Option, +} + +impl<'a> Pet<'a> { + pub fn new(data: &'a [u8]) -> roto_runtime::Result { + let accessor = roto_runtime::ProtoAccessor::new(data)?; + let mut name_offset = None; + let mut color_offset = None; + for item in accessor.fields() { + let (offset, tag, _) = item?; + if tag.field_number == 1 { name_offset = Some(offset); } + if tag.field_number == 2 { color_offset = Some(offset); } + } + + Ok(Self { + accessor, +name_offset, +color_offset, + }) + } + + pub fn name(&self) -> roto_runtime::Result<&'a str> { + let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> { + self.name().or(Ok("")) + } + + pub fn has_name(&self) -> bool { self.name_offset.is_some() } + + pub fn color(&self) -> roto_runtime::Result { + let offset = self.color_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v as u64).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn color_or_default(&self) -> roto_runtime::Result { + self.color().or(Ok(0)) + } + + pub fn has_color(&self) -> bool { self.color_offset.is_some() } + + pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { + self.accessor.raw_fields() + } + +} + +pub struct PetBuilder<'b> { + builder: roto_runtime::ProtoBuilder<'b>, + name_written: bool, + color_written: bool, +} + +impl<'b> PetBuilder<'b> { + pub fn builder(buf: &mut [u8]) -> PetBuilder<'_> { + PetBuilder { + builder: roto_runtime::ProtoBuilder::new(buf), + name_written: false, + color_written: false, + } + } + + pub fn name(mut self, value: &str) -> roto_runtime::Result { + self.builder.write_string(1, value)?; + self.name_written = true; + Ok(self) + } + + pub fn color(mut self, value: u64) -> roto_runtime::Result { + self.builder.write_varint(2, value)?; + self.color_written = true; + Ok(self) + } + + pub fn with(mut self, msg: &Pet<'_>) -> roto_runtime::Result { + for item in msg.accessor.raw_fields() { + let (field_number, raw_bytes) = item?; + let is_written = match field_number { + 1 => self.name_written, + 2 => self.color_written, + _ => false, + }; + if !is_written { + self.builder.write_raw(raw_bytes)?; + } + } + Ok(self) + } + + pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { + self.builder.finish() + } +} + +pub struct OwnedPet { + pub data: bytes::Bytes, +} + +impl roto_runtime::RotoOwned for OwnedPet { + type Reader<'a> = Pet<'a>; + fn reader(&self) -> Pet<'_> { + Pet::new(&self.data).expect("failed to create reader") + } +} + +impl roto_runtime::RotoMessage for OwnedPet { + fn decode(buf: bytes::Bytes) -> roto_runtime::Result { + Ok(OwnedPet { data: buf }) + } + + fn bytes(&self) -> bytes::Bytes { + self.data.clone() + } +} + +pub mod pet { +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(i32)] +pub enum Color { + BLACK = 0, + WHITE = 1, + BLUE = 2, + RED = 3, + YELLOW = 4, + GREEN = 5, +} + +impl Color { + pub fn from_i32(value: i32) -> Self { + match value { + 0 => Color::BLACK, + 1 => Color::WHITE, + 2 => Color::BLUE, + 3 => Color::RED, + 4 => Color::YELLOW, + 5 => Color::GREEN, + _ => Color::BLACK, + } + } +} + +} + +pub enum Choice<'a> { + c1(&'a str), + c2(bool), +} + +} + +pub struct HelloRequest<'a> { + accessor: roto_runtime::ProtoAccessor<'a>, + request_offset: Option, +} + +impl<'a> HelloRequest<'a> { + pub fn new(data: &'a [u8]) -> roto_runtime::Result { + let accessor = roto_runtime::ProtoAccessor::new(data)?; + let mut request_offset = None; + for item in accessor.fields() { + let (offset, tag, _) = item?; + if tag.field_number == 1 { request_offset = Some(offset); } + } + + Ok(Self { + accessor, +request_offset, + }) + } + + pub fn request(&self) -> roto_runtime::Result<&'a [u8]> { + let offset = self.request_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + Ok(bytes) + } + + pub fn request_or_default(&self) -> roto_runtime::Result<&'a [u8]> { + self.request().or(Ok(&[])) + } + + pub fn has_request(&self) -> bool { self.request_offset.is_some() } + + pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { + self.accessor.raw_fields() + } + +} + +pub struct HelloRequestBuilder<'b> { + builder: roto_runtime::ProtoBuilder<'b>, + request_written: bool, +} + +impl<'b> HelloRequestBuilder<'b> { + pub fn builder(buf: &mut [u8]) -> HelloRequestBuilder<'_> { + HelloRequestBuilder { + builder: roto_runtime::ProtoBuilder::new(buf), + request_written: false, + } + } + + pub fn request(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(1, value)?; + self.request_written = true; + Ok(self) + } + + pub fn with(mut self, msg: &HelloRequest<'_>) -> roto_runtime::Result { + for item in msg.accessor.raw_fields() { + let (field_number, raw_bytes) = item?; + let is_written = match field_number { + 1 => self.request_written, + _ => false, + }; + if !is_written { + self.builder.write_raw(raw_bytes)?; + } + } + Ok(self) + } + + pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { + self.builder.finish() + } +} + +pub struct OwnedHelloRequest { + pub data: bytes::Bytes, +} + +impl roto_runtime::RotoOwned for OwnedHelloRequest { + type Reader<'a> = HelloRequest<'a>; + fn reader(&self) -> HelloRequest<'_> { + HelloRequest::new(&self.data).expect("failed to create reader") + } +} + +impl roto_runtime::RotoMessage for OwnedHelloRequest { + fn decode(buf: bytes::Bytes) -> roto_runtime::Result { + Ok(OwnedHelloRequest { data: buf }) + } + + fn bytes(&self) -> bytes::Bytes { + self.data.clone() + } +} + +pub struct HelloReply<'a> { + accessor: roto_runtime::ProtoAccessor<'a>, + response_offset: Option, +} + +impl<'a> HelloReply<'a> { + pub fn new(data: &'a [u8]) -> roto_runtime::Result { + let accessor = roto_runtime::ProtoAccessor::new(data)?; + let mut response_offset = None; + for item in accessor.fields() { + let (offset, tag, _) = item?; + if tag.field_number == 1 { response_offset = Some(offset); } + } + + Ok(Self { + accessor, +response_offset, + }) + } + + pub fn response(&self) -> roto_runtime::Result<&'a [u8]> { + let offset = self.response_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + Ok(bytes) + } + + pub fn response_or_default(&self) -> roto_runtime::Result<&'a [u8]> { + self.response().or(Ok(&[])) + } + + pub fn has_response(&self) -> bool { self.response_offset.is_some() } + + pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { + self.accessor.raw_fields() + } + +} + +pub struct HelloReplyBuilder<'b> { + builder: roto_runtime::ProtoBuilder<'b>, + response_written: bool, +} + +impl<'b> HelloReplyBuilder<'b> { + pub fn builder(buf: &mut [u8]) -> HelloReplyBuilder<'_> { + HelloReplyBuilder { + builder: roto_runtime::ProtoBuilder::new(buf), + response_written: false, + } + } + + pub fn response(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(1, value)?; + self.response_written = true; + Ok(self) + } + + pub fn with(mut self, msg: &HelloReply<'_>) -> roto_runtime::Result { + for item in msg.accessor.raw_fields() { + let (field_number, raw_bytes) = item?; + let is_written = match field_number { + 1 => self.response_written, + _ => false, + }; + if !is_written { + self.builder.write_raw(raw_bytes)?; + } + } + Ok(self) + } + + pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { + self.builder.finish() + } +} + +pub struct OwnedHelloReply { + pub data: bytes::Bytes, +} + +impl roto_runtime::RotoOwned for OwnedHelloReply { + type Reader<'a> = HelloReply<'a>; + fn reader(&self) -> HelloReply<'_> { + HelloReply::new(&self.data).expect("failed to create reader") + } +} + +impl roto_runtime::RotoMessage for OwnedHelloReply { + fn decode(buf: bytes::Bytes) -> roto_runtime::Result { + Ok(OwnedHelloReply { data: buf }) + } + + fn bytes(&self) -> bytes::Bytes { + self.data.clone() + } +} + +#[tonic::async_trait] +pub trait Greeter: Send + Sync + 'static { + async fn say_hello(&self, request: Request) -> std::result::Result, Status>; +} + +pub struct GreeterServer { + inner: Arc, + pool: Arc, +} + +impl GreeterServer { + pub fn new(inner: Arc, pool: Arc) -> Self { + Self { inner, pool } + } +} + +impl tonic::server::NamedService for GreeterServer { + const NAME: &'static str = "Greeter"; +} + +impl Service> for GreeterServer { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + let pool = self.pool.clone(); + Box::pin(async move { + let path = req.uri().path().to_string(); + let body = req.into_body(); + let mut buf = pool.get(); + let mut stream = body; + while let Some(frame_result) = stream.frame().await { + let frame = frame_result.expect("Body frame error"); + if let Some(data) = frame.data_ref() { + buf.put(data.clone()); + } + } + + let total_len = buf.len(); + let bytes_vec = buf.split_to(total_len).freeze(); + pool.put(buf); + if bytes_vec.len() < 5 { + let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); + return Ok(http::Response::builder().status(200).body(res_body).unwrap()); + } + + let payload = bytes_vec.slice(5..); + let mut routed = false; + + if path == "/Greeter/say_hello" { + let request_msg = match OwnedHelloRequest::decode(payload) { + Ok(msg) => msg, + Err(e) => { + let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); + return Ok(http::Response::builder().status(200).body(res_body).unwrap()); + } + }; + + let response = match inner.say_hello(Request::new(request_msg)).await { + Ok(res) => res, + Err(e) => { + let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); + return Ok(http::Response::builder().status(200).body(res_body).unwrap()); + } + }; + + let response_msg = response.into_inner(); + let response_bytes = response_msg.bytes(); + let mut res_buf = pool.get(); + res_buf.put_u8(0); + let len = response_bytes.len() as u32; + res_buf.put_slice(&len.to_be_bytes()); + res_buf.put_slice(&response_bytes); + let frame_len = res_buf.len(); + let frame = res_buf.split_to(frame_len).freeze(); + pool.put(res_buf); + let res_body = BoxBody::new(StatusBody::new(Some(frame), 0)); + routed = true; + return Ok(http::Response::builder().status(200).header("content-type", "application/grpc").body(res_body).unwrap()); + } + if !routed { + let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); + return Ok(http::Response::builder().status(200).body(res_body).unwrap()); + } + Ok(http::Response::builder().status(200).body(BoxBody::new(StatusBody::new(None, 0))).unwrap()) + }) + } +} diff --git a/proto/helloworld.proto b/proto/helloworld.proto new file mode 100644 index 0000000..8f38954 --- /dev/null +++ b/proto/helloworld.proto @@ -0,0 +1,67 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option go_package = "proto/helloworld"; +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "HLW"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The actual message exchanged by the client and the server. +// NOTE: When creating a custom scenario plese edit only this message. +message Hello { + string name = 1; + double d = 2; + float f = 3; + bool b = 4; + int32 n = 5; + int64 l = 6; + oneof choice { + string c1 = 7; + bool c2 = 8; + } + message Pet { + enum Color { + BLACK = 0; + WHITE = 1; + BLUE = 2; + RED = 3; + YELLOW = 4; + GREEN = 5; + } + string name = 1; + Color color = 2; + } + repeated Pet pets = 9; +} + +// The request message from the client. +message HelloRequest { + Hello request = 1; +} + +// The response message from the server. +message HelloReply { + Hello response = 1; +} diff --git a/roto-tonic/src/generated/helloworld.rs b/roto-tonic/src/generated/helloworld.rs new file mode 100644 index 0000000..71a5031 --- /dev/null +++ b/roto-tonic/src/generated/helloworld.rs @@ -0,0 +1,774 @@ +// @generated by protoc-gen-roto — do not edit +#[allow(unused_imports)] + +use roto_runtime::{ProtoAccessor, ProtoBuilder, Result, RotoError, read_varint, RepeatedFieldIterator, RotoMessage}; +use std::str; +use bytes::{Bytes, BytesMut, Buf, BufMut}; +use tonic::{Request, Response, Status}; +use tokio_stream::Stream; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; +use std::future::Future; +use tonic::body::BoxBody; +use tower::Service; +use futures_util::StreamExt; +use http_body_util::BodyExt; +use http_body::Body; +use crate::{BufferPool, StatusBody}; + + +pub struct Hello<'a> { + accessor: roto_runtime::ProtoAccessor<'a>, + name_offset: Option, + d_offset: Option, + f_offset: Option, + b_offset: Option, + n_offset: Option, + l_offset: Option, + c1_offset: Option, + c2_offset: Option, + pets_start: Option, + pets_end: Option, +} + +impl<'a> Hello<'a> { + pub fn new(data: &'a [u8]) -> roto_runtime::Result { + let accessor = roto_runtime::ProtoAccessor::new(data)?; + let mut name_offset = None; + let mut d_offset = None; + let mut f_offset = None; + let mut b_offset = None; + let mut n_offset = None; + let mut l_offset = None; + let mut c1_offset = None; + let mut c2_offset = None; + let mut pets_start = None; + let mut pets_end = None; + for item in accessor.fields() { + let (offset, tag, _) = item?; + if tag.field_number == 1 { name_offset = Some(offset); } + if tag.field_number == 2 { d_offset = Some(offset); } + if tag.field_number == 3 { f_offset = Some(offset); } + if tag.field_number == 4 { b_offset = Some(offset); } + if tag.field_number == 5 { n_offset = Some(offset); } + if tag.field_number == 6 { l_offset = Some(offset); } + if tag.field_number == 7 { c1_offset = Some(offset); } + if tag.field_number == 8 { c2_offset = Some(offset); } + if tag.field_number == 9 { + if pets_start.is_none() { pets_start = Some(offset); } + pets_end = Some(offset); + } + } + + Ok(Self { + accessor, +name_offset, +d_offset, +f_offset, +b_offset, +n_offset, +l_offset, +c1_offset, +c2_offset, +pets_start, pets_end, + }) + } + + pub fn name(&self) -> roto_runtime::Result<&'a str> { + let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> { + self.name().or(Ok("")) + } + + pub fn has_name(&self) -> bool { self.name_offset.is_some() } + + pub fn d(&self) -> roto_runtime::Result { + let offset = self.d_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + Ok(f64::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?)) + } + + pub fn d_or_default(&self) -> roto_runtime::Result { + self.d().or(Ok(0.0)) + } + + pub fn has_d(&self) -> bool { self.d_offset.is_some() } + + pub fn f(&self) -> roto_runtime::Result { + let offset = self.f_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + Ok(f32::from_le_bytes(bytes.try_into().map_err(|_| roto_runtime::RotoError::WireFormatViolation)?)) + } + + pub fn f_or_default(&self) -> roto_runtime::Result { + self.f().or(Ok(0.0)) + } + + pub fn has_f(&self) -> bool { self.f_offset.is_some() } + + pub fn b(&self) -> roto_runtime::Result { + let offset = self.b_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn b_or_default(&self) -> roto_runtime::Result { + self.b().or(Ok(false)) + } + + pub fn has_b(&self) -> bool { self.b_offset.is_some() } + + pub fn n(&self) -> roto_runtime::Result { + let offset = self.n_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn n_or_default(&self) -> roto_runtime::Result { + self.n().or(Ok(0)) + } + + pub fn has_n(&self) -> bool { self.n_offset.is_some() } + + pub fn l(&self) -> roto_runtime::Result { + let offset = self.l_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v as i32).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn l_or_default(&self) -> roto_runtime::Result { + self.l().or(Ok(0)) + } + + pub fn has_l(&self) -> bool { self.l_offset.is_some() } + + pub fn c1(&self) -> roto_runtime::Result<&'a str> { + let offset = self.c1_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn c1_or_default(&self) -> roto_runtime::Result<&'a str> { + self.c1().or(Ok("")) + } + + pub fn has_c1(&self) -> bool { self.c1_offset.is_some() } + + pub fn c2(&self) -> roto_runtime::Result { + let offset = self.c2_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v != 0).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn c2_or_default(&self) -> roto_runtime::Result { + self.c2().or(Ok(false)) + } + + pub fn has_c2(&self) -> bool { self.c2_offset.is_some() } + + pub fn pets(&self) -> roto_runtime::RepeatedFieldIterator<'a> { + match (self.pets_start, self.pets_end) { + (Some(start), Some(end)) => self.accessor.iter_repeated_range(9, start, end), + _ => self.accessor.iter_repeated(9), + } + } + + pub fn which_choice(&self) -> roto_runtime::Result> > { + if self.c1_offset.is_some() { + return Ok(Some(hello::Choice::c1 (self.c1()?))); + } + if self.c2_offset.is_some() { + return Ok(Some(hello::Choice::c2 (self.c2()?))); + } + Ok(None) + } + + pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { + self.accessor.raw_fields() + } + +} + +pub struct HelloBuilder<'b> { + builder: roto_runtime::ProtoBuilder<'b>, + name_written: bool, + d_written: bool, + f_written: bool, + b_written: bool, + n_written: bool, + l_written: bool, + c1_written: bool, + c2_written: bool, + pets_written: bool, +} + +impl<'b> HelloBuilder<'b> { + pub fn builder(buf: &mut [u8]) -> HelloBuilder<'_> { + HelloBuilder { + builder: roto_runtime::ProtoBuilder::new(buf), + name_written: false, + d_written: false, + f_written: false, + b_written: false, + n_written: false, + l_written: false, + c1_written: false, + c2_written: false, + pets_written: false, + } + } + + pub fn name(mut self, value: &str) -> roto_runtime::Result { + self.builder.write_string(1, value)?; + self.name_written = true; + Ok(self) + } + + pub fn d(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(2, value)?; + self.d_written = true; + Ok(self) + } + + pub fn f(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(3, value)?; + self.f_written = true; + Ok(self) + } + + pub fn b(mut self, value: u64) -> roto_runtime::Result { + self.builder.write_varint(4, value)?; + self.b_written = true; + Ok(self) + } + + pub fn n(mut self, value: i32) -> roto_runtime::Result { + self.builder.write_int32(5, value)?; + self.n_written = true; + Ok(self) + } + + pub fn l(mut self, value: u64) -> roto_runtime::Result { + self.builder.write_varint(6, value)?; + self.l_written = true; + Ok(self) + } + + pub fn c1(mut self, value: &str) -> roto_runtime::Result { + self.builder.write_string(7, value)?; + self.c1_written = true; + Ok(self) + } + + pub fn c2(mut self, value: u64) -> roto_runtime::Result { + self.builder.write_varint(8, value)?; + self.c2_written = true; + Ok(self) + } + + pub fn pets(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(9, value)?; + self.pets_written = true; + Ok(self) + } + + pub fn with(mut self, msg: &Hello<'_>) -> roto_runtime::Result { + for item in msg.accessor.raw_fields() { + let (field_number, raw_bytes) = item?; + let is_written = match field_number { + 1 => self.name_written, + 2 => self.d_written, + 3 => self.f_written, + 4 => self.b_written, + 5 => self.n_written, + 6 => self.l_written, + 7 => self.c1_written, + 8 => self.c2_written, + 9 => self.pets_written, + _ => false, + }; + if !is_written { + self.builder.write_raw(raw_bytes)?; + } + } + Ok(self) + } + + pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { + self.builder.finish() + } +} + +pub struct OwnedHello { + pub data: bytes::Bytes, +} + +impl roto_runtime::RotoOwned for OwnedHello { + type Reader<'a> = Hello<'a>; + fn reader(&self) -> Hello<'_> { + Hello::new(&self.data).expect("failed to create reader") + } +} + +impl roto_runtime::RotoMessage for OwnedHello { + fn decode(buf: bytes::Bytes) -> roto_runtime::Result { + Ok(OwnedHello { data: buf }) + } + + fn bytes(&self) -> bytes::Bytes { + self.data.clone() + } +} + +pub mod hello { +pub struct Pet<'a> { + accessor: roto_runtime::ProtoAccessor<'a>, + name_offset: Option, + color_offset: Option, +} + +impl<'a> Pet<'a> { + pub fn new(data: &'a [u8]) -> roto_runtime::Result { + let accessor = roto_runtime::ProtoAccessor::new(data)?; + let mut name_offset = None; + let mut color_offset = None; + for item in accessor.fields() { + let (offset, tag, _) = item?; + if tag.field_number == 1 { name_offset = Some(offset); } + if tag.field_number == 2 { color_offset = Some(offset); } + } + + Ok(Self { + accessor, +name_offset, +color_offset, + }) + } + + pub fn name(&self) -> roto_runtime::Result<&'a str> { + let offset = self.name_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + std::str::from_utf8(bytes).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn name_or_default(&self) -> roto_runtime::Result<&'a str> { + self.name().or(Ok("")) + } + + pub fn has_name(&self) -> bool { self.name_offset.is_some() } + + pub fn color(&self) -> roto_runtime::Result { + let offset = self.color_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + roto_runtime::read_varint(bytes).map(|(v, _)| v as u64).map_err(|_| roto_runtime::RotoError::WireFormatViolation) + } + + pub fn color_or_default(&self) -> roto_runtime::Result { + self.color().or(Ok(0)) + } + + pub fn has_color(&self) -> bool { self.color_offset.is_some() } + + pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { + self.accessor.raw_fields() + } + +} + +pub struct PetBuilder<'b> { + builder: roto_runtime::ProtoBuilder<'b>, + name_written: bool, + color_written: bool, +} + +impl<'b> PetBuilder<'b> { + pub fn builder(buf: &mut [u8]) -> PetBuilder<'_> { + PetBuilder { + builder: roto_runtime::ProtoBuilder::new(buf), + name_written: false, + color_written: false, + } + } + + pub fn name(mut self, value: &str) -> roto_runtime::Result { + self.builder.write_string(1, value)?; + self.name_written = true; + Ok(self) + } + + pub fn color(mut self, value: u64) -> roto_runtime::Result { + self.builder.write_varint(2, value)?; + self.color_written = true; + Ok(self) + } + + pub fn with(mut self, msg: &Pet<'_>) -> roto_runtime::Result { + for item in msg.accessor.raw_fields() { + let (field_number, raw_bytes) = item?; + let is_written = match field_number { + 1 => self.name_written, + 2 => self.color_written, + _ => false, + }; + if !is_written { + self.builder.write_raw(raw_bytes)?; + } + } + Ok(self) + } + + pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { + self.builder.finish() + } +} + +pub struct OwnedPet { + pub data: bytes::Bytes, +} + +impl roto_runtime::RotoOwned for OwnedPet { + type Reader<'a> = Pet<'a>; + fn reader(&self) -> Pet<'_> { + Pet::new(&self.data).expect("failed to create reader") + } +} + +impl roto_runtime::RotoMessage for OwnedPet { + fn decode(buf: bytes::Bytes) -> roto_runtime::Result { + Ok(OwnedPet { data: buf }) + } + + fn bytes(&self) -> bytes::Bytes { + self.data.clone() + } +} + +pub mod pet { +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(i32)] +pub enum Color { + BLACK = 0, + WHITE = 1, + BLUE = 2, + RED = 3, + YELLOW = 4, + GREEN = 5, +} + +impl Color { + pub fn from_i32(value: i32) -> Self { + match value { + 0 => Color::BLACK, + 1 => Color::WHITE, + 2 => Color::BLUE, + 3 => Color::RED, + 4 => Color::YELLOW, + 5 => Color::GREEN, + _ => Color::BLACK, + } + } +} + +} + +pub enum Choice<'a> { + c1(&'a str), + c2(bool), +} + +} + +pub struct HelloRequest<'a> { + accessor: roto_runtime::ProtoAccessor<'a>, + request_offset: Option, +} + +impl<'a> HelloRequest<'a> { + pub fn new(data: &'a [u8]) -> roto_runtime::Result { + let accessor = roto_runtime::ProtoAccessor::new(data)?; + let mut request_offset = None; + for item in accessor.fields() { + let (offset, tag, _) = item?; + if tag.field_number == 1 { request_offset = Some(offset); } + } + + Ok(Self { + accessor, +request_offset, + }) + } + + pub fn request(&self) -> roto_runtime::Result<&'a [u8]> { + let offset = self.request_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + Ok(bytes) + } + + pub fn request_or_default(&self) -> roto_runtime::Result<&'a [u8]> { + self.request().or(Ok(&[])) + } + + pub fn has_request(&self) -> bool { self.request_offset.is_some() } + + pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { + self.accessor.raw_fields() + } + +} + +pub struct HelloRequestBuilder<'b> { + builder: roto_runtime::ProtoBuilder<'b>, + request_written: bool, +} + +impl<'b> HelloRequestBuilder<'b> { + pub fn builder(buf: &mut [u8]) -> HelloRequestBuilder<'_> { + HelloRequestBuilder { + builder: roto_runtime::ProtoBuilder::new(buf), + request_written: false, + } + } + + pub fn request(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(1, value)?; + self.request_written = true; + Ok(self) + } + + pub fn with(mut self, msg: &HelloRequest<'_>) -> roto_runtime::Result { + for item in msg.accessor.raw_fields() { + let (field_number, raw_bytes) = item?; + let is_written = match field_number { + 1 => self.request_written, + _ => false, + }; + if !is_written { + self.builder.write_raw(raw_bytes)?; + } + } + Ok(self) + } + + pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { + self.builder.finish() + } +} + +pub struct OwnedHelloRequest { + pub data: bytes::Bytes, +} + +impl roto_runtime::RotoOwned for OwnedHelloRequest { + type Reader<'a> = HelloRequest<'a>; + fn reader(&self) -> HelloRequest<'_> { + HelloRequest::new(&self.data).expect("failed to create reader") + } +} + +impl roto_runtime::RotoMessage for OwnedHelloRequest { + fn decode(buf: bytes::Bytes) -> roto_runtime::Result { + Ok(OwnedHelloRequest { data: buf }) + } + + fn bytes(&self) -> bytes::Bytes { + self.data.clone() + } +} + +pub struct HelloReply<'a> { + accessor: roto_runtime::ProtoAccessor<'a>, + response_offset: Option, +} + +impl<'a> HelloReply<'a> { + pub fn new(data: &'a [u8]) -> roto_runtime::Result { + let accessor = roto_runtime::ProtoAccessor::new(data)?; + let mut response_offset = None; + for item in accessor.fields() { + let (offset, tag, _) = item?; + if tag.field_number == 1 { response_offset = Some(offset); } + } + + Ok(Self { + accessor, +response_offset, + }) + } + + pub fn response(&self) -> roto_runtime::Result<&'a [u8]> { + let offset = self.response_offset.ok_or(roto_runtime::RotoError::FieldNotFound)?; + let (bytes, _) = self.accessor.get_value_at(offset)?; + Ok(bytes) + } + + pub fn response_or_default(&self) -> roto_runtime::Result<&'a [u8]> { + self.response().or(Ok(&[])) + } + + pub fn has_response(&self) -> bool { self.response_offset.is_some() } + + pub fn raw_fields(&self) -> roto_runtime::RawFieldIterator<'a> { + self.accessor.raw_fields() + } + +} + +pub struct HelloReplyBuilder<'b> { + builder: roto_runtime::ProtoBuilder<'b>, + response_written: bool, +} + +impl<'b> HelloReplyBuilder<'b> { + pub fn builder(buf: &mut [u8]) -> HelloReplyBuilder<'_> { + HelloReplyBuilder { + builder: roto_runtime::ProtoBuilder::new(buf), + response_written: false, + } + } + + pub fn response(mut self, value: &[u8]) -> roto_runtime::Result { + self.builder.write_bytes(1, value)?; + self.response_written = true; + Ok(self) + } + + pub fn with(mut self, msg: &HelloReply<'_>) -> roto_runtime::Result { + for item in msg.accessor.raw_fields() { + let (field_number, raw_bytes) = item?; + let is_written = match field_number { + 1 => self.response_written, + _ => false, + }; + if !is_written { + self.builder.write_raw(raw_bytes)?; + } + } + Ok(self) + } + + pub fn finish(self) -> roto_runtime::Result<&'b mut [u8]> { + self.builder.finish() + } +} + +pub struct OwnedHelloReply { + pub data: bytes::Bytes, +} + +impl roto_runtime::RotoOwned for OwnedHelloReply { + type Reader<'a> = HelloReply<'a>; + fn reader(&self) -> HelloReply<'_> { + HelloReply::new(&self.data).expect("failed to create reader") + } +} + +impl roto_runtime::RotoMessage for OwnedHelloReply { + fn decode(buf: bytes::Bytes) -> roto_runtime::Result { + Ok(OwnedHelloReply { data: buf }) + } + + fn bytes(&self) -> bytes::Bytes { + self.data.clone() + } +} + +#[tonic::async_trait] +pub trait Greeter: Send + Sync + 'static { + async fn say_hello(&self, request: Request) -> std::result::Result, Status>; +} + +#[derive(Clone)] +pub struct GreeterServer { + inner: Arc, + pool: Arc, +} + +impl GreeterServer { + pub fn new(inner: Arc, pool: Arc) -> Self { + Self { inner, pool } + } +} + +impl tonic::server::NamedService for GreeterServer { + const NAME: &'static str = "helloworld.Greeter"; +} + +impl Service> for GreeterServer { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + let pool = self.pool.clone(); + Box::pin(async move { + let path = req.uri().path().to_string(); + let body = req.into_body(); + let mut buf = pool.get(); + let mut stream = body; + while let Some(frame_result) = stream.frame().await { + let frame = frame_result.expect("Body frame error"); + if let Some(data) = frame.data_ref() { + buf.put(data.clone()); + } + } + + let total_len = buf.len(); + let bytes_vec = buf.split_to(total_len).freeze(); + pool.put(buf); + if bytes_vec.len() < 5 { + let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); + return Ok(http::Response::builder().status(200).body(res_body).unwrap()); + } + + let payload = bytes_vec.slice(5..); + let mut routed = false; + + if path == "/helloworld.Greeter/say_hello" { + let request_msg = match OwnedHelloRequest::decode(payload) { + Ok(msg) => msg, + Err(e) => { + let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); + return Ok(http::Response::builder().status(200).body(res_body).unwrap()); + } + }; + + let response = match inner.say_hello(Request::new(request_msg)).await { + Ok(res) => res, + Err(e) => { + let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); + return Ok(http::Response::builder().status(200).body(res_body).unwrap()); + } + }; + + let response_msg = response.into_inner(); + let response_bytes = response_msg.bytes(); + let mut res_buf = pool.get(); + res_buf.put_u8(0); + let len = response_bytes.len() as u32; + res_buf.put_slice(&len.to_be_bytes()); + res_buf.put_slice(&response_bytes); + let frame_len = res_buf.len(); + let frame = res_buf.split_to(frame_len).freeze(); + pool.put(res_buf); + let res_body = BoxBody::new(StatusBody::new(Some(frame), 0)); + routed = true; + return Ok(http::Response::builder().status(200).header("content-type", "application/grpc").body(res_body).unwrap()); + } + if !routed { + let res_body = BoxBody::new(StatusBody::new(Some(Bytes::from_static(&[0, 0, 0, 0, 0])), 0)); + return Ok(http::Response::builder().status(200).body(res_body).unwrap()); + } + Ok(http::Response::builder().status(200).body(BoxBody::new(StatusBody::new(None, 0))).unwrap()) + }) + } +} diff --git a/roto-tonic/tests/helloworld_test.rs b/roto-tonic/tests/helloworld_test.rs new file mode 100644 index 0000000..c7ac745 --- /dev/null +++ b/roto-tonic/tests/helloworld_test.rs @@ -0,0 +1,100 @@ +use std::sync::Arc; +use tonic::{Request, Response, Status}; +use roto_runtime::RotoOwned; +use roto_tonic::{BufferPool, generated::helloworld::{Greeter, GreeterServer, OwnedHelloRequest, OwnedHelloReply, HelloReplyBuilder, HelloBuilder}}; +use std::net::SocketAddr; +use tokio::net::TcpListener; + +struct MyGreeter; + +#[tonic::async_trait] +impl Greeter for MyGreeter { + async fn say_hello(&self, request: Request) -> std::result::Result, Status> { + let req = request.into_inner(); + let hello_req = req.reader(); + + // Extract name from the nested Hello message in HelloRequest + let name = match hello_req.request() { + Ok(req_bytes) => { + let hello = roto_tonic::generated::helloworld::Hello::new(req_bytes).unwrap(); + hello.name_or_default().unwrap().to_string() + }, + Err(_) => "Unknown".to_string(), + }; + + // Build the Hello response message + let mut hello_buf = [0u8; 1024]; + let mut hello_builder = HelloBuilder::builder(&mut hello_buf); + hello_builder = hello_builder.name(&format!("Hello, {}!", name)) + .map_err(|e| Status::internal(format!("Build error: {:?}", e)))?; + + let hello_bytes = hello_builder.finish() + .map_err(|e| Status::internal(format!("Finish error: {:?}", e)))?; + + // Build the HelloReply message containing the Hello bytes + let mut reply_buf = [0u8; 1024]; + let mut reply_builder = HelloReplyBuilder::builder(&mut reply_buf); + reply_builder = reply_builder.response(hello_bytes) + .map_err(|e| Status::internal(format!("Build error: {:?}", e)))?; + + let reply_bytes = reply_builder.finish() + .map_err(|e| Status::internal(format!("Finish error: {:?}", e)))?; + + Ok(Response::new(OwnedHelloReply { + data: reply_bytes.to_vec().into(), + })) + } +} + +#[tokio::test] +async fn test_say_hello_handler() { + let greeter = MyGreeter; + + // Manually construct a valid proto buffer for HelloRequest + // HelloRequest { request: Hello { name: "World" } } + let mut hello_buf = [0u8; 1024]; + let mut hb = HelloBuilder::builder(&mut hello_buf); + hb = hb.name("World").unwrap(); + let hello_bytes = hb.finish().unwrap(); + + let mut req_buf = [0u8; 1024]; + let mut rb = roto_tonic::generated::helloworld::HelloRequestBuilder::builder(&mut req_buf); + rb = rb.request(hello_bytes).unwrap(); + let req_bytes = rb.finish().unwrap(); + + let request = Request::new(OwnedHelloRequest { + data: req_bytes.to_vec().into(), + }); + + let response = greeter.say_hello(request).await.unwrap(); + let reply = response.into_inner(); + let reply_reader = reply.reader(); + + let response_msg_bytes = reply_reader.response().expect("Response field missing"); + let response_msg = roto_tonic::generated::helloworld::Hello::new(response_msg_bytes).expect("Invalid Hello message"); + + assert_eq!(response_msg.name_or_default().unwrap(), "Hello, World!"); +} + +#[tokio::test] +async fn test_server_start() { + let pool = Arc::new(BufferPool::new(1024)); + let greeter = Arc::new(MyGreeter); + let server = GreeterServer::new(greeter, pool); + + let addr = SocketAddr::from(([127, 0, 0, 1], 0)); + let listener = TcpListener::bind(addr).await.unwrap(); + let _local_addr = listener.local_addr().unwrap(); + + let server_handle = tokio::spawn(async move { + tonic::transport::Server::builder() + .add_service(server) + .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener)) + .await + .unwrap(); + }); + + // Just verify it can start without crashing + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + server_handle.abort(); +}