use std::sync::Arc; use service_rpc::base64; use service_rpc::{ serve, AccountRef, GameRequest, GameResponse, HomeRequestKind, RpcClient, RpcResult, RpcService, WireMessage, }; use tokio::net::TcpListener; struct EchoGame; #[async_trait::async_trait] impl RpcService for EchoGame { type Request = GameRequest; type Response = GameResponse; fn service_name(&self) -> &'static str { "echo-game" } async fn call(&self, request: GameRequest) -> RpcResult { match request { GameRequest::LoadHome { account, .. } => Ok(GameResponse::messages(vec![ WireMessage::new(24101, 0, vec![account.low as u8, 0xFF, 0x00, 0x7F]), ])), _ => Ok(GameResponse::Empty), } } } #[tokio::test] async fn requests_round_trip_over_the_length_prefixed_transport() { let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind"); let endpoint = listener.local_addr().expect("addr").to_string(); tokio::spawn(async move { let _ = serve(listener, Arc::new(EchoGame)).await; }); let client: RpcClient = RpcClient::new(endpoint); let response = client .call(&GameRequest::LoadHome { account: AccountRef::new(0, 9), kind: HomeRequestKind::Login, }) .await .expect("call"); let messages = response.into_messages(); assert_eq!(messages.len(), 1); assert_eq!(messages[0].message_type, 24101); assert_eq!(messages[0].payload, vec![9, 0xFF, 0x00, 0x7F]); let empty = client .call(&GameRequest::Disconnect { account: AccountRef::new(0, 9), }) .await .expect("call"); assert_eq!(empty, GameResponse::Empty); } #[tokio::test] async fn payloads_survive_base64_encoding() { for length in 0..64usize { let payload: Vec = (0..length).map(|index| (index * 7 % 251) as u8).collect(); let encoded = base64::encode(&payload); assert_eq!(base64::decode(&encoded).expect("decode"), payload); } assert_eq!(base64::encode(b"scroll"), "c2Nyb2xs"); assert_eq!(base64::decode("c2Nyb2xs").unwrap(), b"scroll"); }