use opcda_bridge_proto::bridge::bridge_server::{Bridge, BridgeServer};
use opcda_bridge_proto::bridge::{
BrowseRequest, BrowseResponse, ListServersRequest, ListServersResponse, ReadRequest,
ReadResponse, WriteRequest, WriteResponse,
};
use std::net::SocketAddr;
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;
use tonic::transport::Server;
use tonic::{Request, Response, Status};
#[derive(Default)]
pub(crate) struct MockBridgeService {
pub(crate) list_servers_response: ListServersResponse,
pub(crate) browse_responses: Vec<BrowseResponse>,
pub(crate) read_response: ReadResponse,
pub(crate) write_response: WriteResponse,
}
#[tonic::async_trait]
impl Bridge for MockBridgeService {
async fn list_servers(
&self,
_request: Request<ListServersRequest>,
) -> Result<Response<ListServersResponse>, Status> {
Ok(Response::new(self.list_servers_response.clone()))
}
type BrowseStream = ReceiverStream<Result<BrowseResponse, Status>>;
async fn browse(
&self,
_request: Request<BrowseRequest>,
) -> Result<Response<Self::BrowseStream>, Status> {
let (tx, rx) = mpsc::channel(4);
let items = self.browse_responses.clone();
tokio::spawn(async move {
for item in items {
if tx.send(Ok(item)).await.is_err() {
break;
}
}
});
Ok(Response::new(ReceiverStream::new(rx)))
}
async fn read(&self, _request: Request<ReadRequest>) -> Result<Response<ReadResponse>, Status> {
Ok(Response::new(self.read_response.clone()))
}
async fn write(
&self,
_request: Request<WriteRequest>,
) -> Result<Response<WriteResponse>, Status> {
Ok(Response::new(self.write_response.clone()))
}
}
pub(crate) async fn start_mock_server(service: MockBridgeService) -> String {
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
let port = listener.local_addr().unwrap().port();
tokio::spawn(async move {
Server::builder()
.add_service(BridgeServer::new(service))
.serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener))
.await
.unwrap();
});
format!("127.0.0.1:{port}")
}