use std::sync::Arc;
use std::time::Duration;
use foundation_core::synca::OnSignal;
use foundation_core::valtron::valtron;
use foundation_http::native::server::{HttpServer, ServerConfig};
use foundation_http::shared::app::HttpApp;
use foundation_netio::http::NativeHttpClient;
use foundation_connectrpc::shared::transport::Transport;
use foundation_connectrpc::{
service, ClientOptions, ConnectResult, ConnectRpcServe, Ctx, H1Transport, Request, Response,
Router,
};
#[derive(Clone, Default, Debug, serde::Serialize, serde::Deserialize)]
pub struct GreetRequest {
name: String,
}
#[derive(Clone, Default, Debug, serde::Serialize, serde::Deserialize)]
pub struct GreetResponse {
message: String,
}
#[service(package = "demo.greet.v1", codecs(json))]
pub trait GreetService {
async fn greet(
&self,
_ctx: Ctx,
_req: Request<GreetRequest>,
) -> ConnectResult<Response<GreetResponse>>;
}
struct Greeter;
impl GreetService for Greeter {
async fn greet(
&self,
_ctx: Ctx,
req: Request<GreetRequest>,
) -> ConnectResult<Response<GreetResponse>> {
Ok(Response::new(GreetResponse { message: format!("Hello, {}!", req.msg.name) }))
}
}
fn start_server() -> (std::net::SocketAddr, Arc<OnSignal>) {
let mut router = Router::new();
register_greet_service(&mut router, Arc::new(Greeter));
let serve: Arc<dyn foundation_http::shared::serve::Serve> =
Arc::new(ConnectRpcServe::new(router.into_handler()));
let mut app = HttpApp::new_serve();
app.router.add_route_any(procedure::GREET, &serve);
let listener = std::net::TcpListener::bind("127.0.0.1:0").expect("bind loopback");
let addr = listener.local_addr().expect("local addr");
let server =
HttpServer::with_config(app, &format!("127.0.0.1:{}", addr.port()), ServerConfig::defaults());
let shutdown = Arc::new(OnSignal::new());
let shutdown_thread = shutdown.clone();
std::thread::spawn(move || server.serve_with_listener(&listener, &shutdown_thread));
while std::net::TcpStream::connect_timeout(&addr, Duration::from_millis(200)).is_err() {}
(addr, shutdown)
}
#[valtron(seed = 1, threads = 4)]
async fn main() {
let (addr, shutdown) = start_server();
let transport: Arc<dyn Transport> = Arc::new(H1Transport::new(Arc::new(NativeHttpClient::from_system())));
let base_url = format!("http://127.0.0.1:{}", addr.port());
let client = GreetServiceClient::new(transport, &base_url, ClientOptions::new().with_codec("json"))
.expect("build client");
let ctx = Ctx::background().with_deadline(Duration::from_secs(10));
let resp = client
.greet(ctx, Request::new(GreetRequest { name: "code-first".into() }))
.await
.expect("greet call");
println!("greet response: {:?}", resp.msg.message);
assert_eq!(resp.msg.message, "Hello, code-first!");
println!("code-first #[service] round-trip verified ✓ (service = {GREETSERVICE_NAME})");
shutdown.turn_on();
}