Files
roto/examples/hello_world/src/bin/server.rs
T

221 lines
6.7 KiB
Rust
Raw Normal View History

2026-05-12 13:44:53 -07:00
use std::pin::Pin;
use std::future::Future;
use std::task::{Context, Poll};
use std::sync::{Arc, Mutex};
2026-05-12 13:44:53 -07:00
use tonic::{transport::Server, Request, Response, Status};
use roto_tonic::RotoCodec;
use hello::{HelloWorldService, OwnedHelloRequest, OwnedHelloResponse};
use tower::Service;
use bytes::{Bytes, BytesMut, Buf, BufMut};
2026-05-12 13:44:53 -07:00
use tonic::body::BoxBody;
use futures_util::StreamExt;
use roto_runtime::{RotoOwned, RotoMessage};
use http_body_util::BodyExt;
use http_body::Body;
pub mod hello {
2026-05-13 23:08:21 -07:00
include!(concat!(env!("OUT_DIR"), "/hello.rs"));
2026-05-12 13:44:53 -07:00
}
struct BufferPool {
pool: Mutex<Vec<BytesMut>>,
default_capacity: usize,
}
impl BufferPool {
fn new(default_capacity: usize) -> Self {
Self {
pool: Mutex::new(Vec::new()),
default_capacity,
}
}
fn get(&self) -> BytesMut {
self.pool.lock().unwrap().pop().unwrap_or_else(|| BytesMut::with_capacity(self.default_capacity))
}
fn put(&self, mut buf: BytesMut) {
buf.clear();
if buf.capacity() >= self.default_capacity {
self.pool.lock().unwrap().push(buf);
}
}
}
#[derive(Clone)]
pub struct MyHelloWorld {
pool: Arc<BufferPool>,
}
impl MyHelloWorld {
pub fn new(pool: Arc<BufferPool>) -> Self {
Self { pool }
}
}
2026-05-12 13:44:53 -07:00
#[tonic::async_trait]
impl HelloWorldService for MyHelloWorld {
async fn hello_world(
&self,
request: Request<OwnedHelloRequest>,
) -> Result<Response<OwnedHelloResponse>, Status> {
let req = request.into_inner();
let reader = req.reader();
let name = reader.name().unwrap_or("Unknown");
let mut buf = self.pool.get();
buf.resize(1024, 0);
let slice = hello::HelloResponseBuilder::builder(&mut buf[..])
2026-05-12 13:44:53 -07:00
.message(&format!("Hello {}!", name)).unwrap()
.finish().unwrap();
let res_len = slice.len();
let response_bytes = buf.split_to(res_len).freeze();
self.pool.put(buf);
2026-05-12 13:44:53 -07:00
let reply = OwnedHelloResponse {
data: response_bytes,
2026-05-12 13:44:53 -07:00
};
Ok(Response::new(reply))
}
}
// --- Tonic Glue ---
#[derive(Clone)]
pub struct HelloWorldServer {
inner: Arc<MyHelloWorld>,
pool: Arc<BufferPool>,
2026-05-12 13:44:53 -07:00
}
impl HelloWorldServer {
pub fn new(inner: MyHelloWorld, pool: Arc<BufferPool>) -> Self {
Self { inner: Arc::new(inner), pool }
2026-05-12 13:44:53 -07:00
}
}
impl tonic::server::NamedService for HelloWorldServer {
const NAME: &'static str = "hello.HelloWorldService";
}
struct StatusBody(Option<Bytes>);
impl Body for StatusBody {
type Data = Bytes;
type Error = Status;
fn poll_frame(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
if let Some(data) = self.0.take() {
Poll::Ready(Some(Ok(http_body::Frame::data(data))))
} else {
Poll::Ready(None)
}
}
}
impl Service<http::Request<BoxBody>> for HelloWorldServer {
type Response = http::Response<BoxBody>;
type Error = std::convert::Infallible;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<BoxBody>) -> Self::Future {
let inner = self.inner.clone();
let pool = self.pool.clone();
2026-05-12 13:44:53 -07:00
println!("Server received request: {} {}", req.method(), req.uri());
Box::pin(async move {
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.map_err(|e| {
println!("Body frame error: {}", e);
panic!("Body frame error: {}", e);
})?;
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);
2026-05-12 13:44:53 -07:00
println!("Collected body bytes: {} bytes", bytes_vec.len());
if bytes_vec.len() < 5 {
println!("Body too short: {} bytes", bytes_vec.len());
let res_body = BoxBody::new(StatusBody(Some(Bytes::from_static(&[0, 0, 0, 0, 0]))));
2026-05-12 13:44:53 -07:00
return Ok(http::Response::builder()
.status(200)
.body(res_body)
.unwrap());
}
println!("Decoding request from {} bytes", bytes_vec.len() - 5);
let request_msg = match OwnedHelloRequest::decode(bytes_vec.slice(5..)) {
2026-05-12 13:44:53 -07:00
Ok(msg) => msg,
Err(e) => {
println!("Decode error: {}", e);
let res_body = BoxBody::new(StatusBody(Some(Bytes::from_static(&[0, 0, 0, 0, 0]))));
2026-05-12 13:44:53 -07:00
return Ok(http::Response::builder().status(200).body(res_body).unwrap());
}
};
println!("Request decoded successfully");
let response = match inner.hello_world(Request::new(request_msg)).await {
Ok(res) => res,
Err(e) => {
println!("Service error: {}", e);
let res_body = BoxBody::new(StatusBody(Some(Bytes::from_static(&[0, 0, 0, 0, 0]))));
2026-05-12 13:44:53 -07:00
return Ok(http::Response::builder().status(200).body(res_body).unwrap());
}
};
let response_msg = response.into_inner();
let response_bytes = response_msg.bytes();
println!("Service responded with {} bytes", response_bytes.len());
let mut res_buf = pool.get();
res_buf.put_u8(0);
2026-05-12 13:44:53 -07:00
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);
2026-05-12 13:44:53 -07:00
let res_body = BoxBody::new(StatusBody(Some(frame)));
2026-05-12 13:44:53 -07:00
Ok(http::Response::builder()
.status(200)
.header("content-type", "application/grpc")
.body(res_body)
.unwrap())
})
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr: std::net::SocketAddr = "[::1]:50051".parse()?;
let pool = Arc::new(BufferPool::new(1024));
let hello = MyHelloWorld::new(pool.clone());
2026-05-12 13:44:53 -07:00
println!("Server listening on {}", addr);
Server::builder()
.add_service(HelloWorldServer::new(hello, pool))
2026-05-12 13:44:53 -07:00
.serve(addr)
.await?;
Ok(())
}