mirror of
https://codeberg.org/JasterV/granc.git
synced 2026-04-26 18:40:05 +00:00
This PR implements a new subcommand `doc` that generates markdown documentation for a given gRPC service! **Description** For the most part, the inner logic of this subcommand is the same as the `describe`, the only thing that changes is the way that the found descriptor is transformed to a final output. In this case, a `Packages` type has been implemented to transform a `ServiceDescriptor` into a map of `Package`s. Each package groups all the file descriptors with the same package name (or namespace). A `Package` contains all the necessary information for a file of documentation to be generated (All its contained services, messages and enum descriptors and its name). The output of this command is a folder with all the generated documentation, which contains a file per protobuf package. **Introduced the `granc-test-support` crate** * Renamed the `echo_service` crate as `granc-test-support`, providing both the definition of a protobuf service for integration testing and a function to compile protobuffer at runtime into a file descriptor (Potentially this could be used to let users pass a folder to a proto project in addition to the server reflection and the local file descriptor options. For example, the `call` command could compile a file descriptor on the fly from a folder containing a protobuffer project before making the call to the gRPC server. **Descriptor API Enhancements:** * Added `name`, `full_name`, and `package_name` methods to the `Descriptor` enum to simplify access to descriptor metadata. (`granc-core/src/client/types.rs`) **Dependency Management Improvements:** * Added grouping for gRPC-related dependencies in `dependabot.yml` for improved automated dependency updates. (`.github/dependabot.yml`)
89 lines
2.8 KiB
Rust
89 lines
2.8 KiB
Rust
use futures_util::Stream;
|
|
use futures_util::StreamExt;
|
|
use granc_test_support::echo_service::EchoService;
|
|
use granc_test_support::echo_service::pb::{EchoRequest, EchoResponse};
|
|
use std::pin::Pin;
|
|
use tokio::sync::mpsc;
|
|
use tokio_stream::wrappers::ReceiverStream;
|
|
use tonic::{Request, Response, Status, Streaming};
|
|
|
|
#[derive(Debug)]
|
|
pub struct EchoServiceImpl;
|
|
|
|
#[tonic::async_trait]
|
|
impl EchoService for EchoServiceImpl {
|
|
type BidirectionalEchoStream = Pin<Box<dyn Stream<Item = Result<EchoResponse, Status>> + Send>>;
|
|
type ServerStreamingEchoStream = ReceiverStream<Result<EchoResponse, Status>>;
|
|
|
|
async fn unary_echo(
|
|
&self,
|
|
request: Request<EchoRequest>,
|
|
) -> Result<Response<EchoResponse>, Status> {
|
|
Ok(Response::new(EchoResponse {
|
|
message: request.into_inner().message,
|
|
}))
|
|
}
|
|
|
|
async fn server_streaming_echo(
|
|
&self,
|
|
request: Request<EchoRequest>,
|
|
) -> Result<Response<Self::ServerStreamingEchoStream>, Status> {
|
|
let msg = request.into_inner().message;
|
|
let (tx, rx) = mpsc::channel(4);
|
|
|
|
tokio::spawn(async move {
|
|
for i in 0..3 {
|
|
let response = EchoResponse {
|
|
message: format!("{} - seq {}", msg, i),
|
|
};
|
|
tx.send(Ok(response)).await.ok();
|
|
}
|
|
});
|
|
|
|
Ok(Response::new(ReceiverStream::new(rx)))
|
|
}
|
|
|
|
async fn client_streaming_echo(
|
|
&self,
|
|
request: Request<Streaming<EchoRequest>>,
|
|
) -> Result<Response<EchoResponse>, Status> {
|
|
let mut stream = request.into_inner();
|
|
let mut full_msg = String::new();
|
|
|
|
while let Some(req) = stream.next().await {
|
|
let req = req?;
|
|
full_msg.push_str(&req.message);
|
|
}
|
|
|
|
Ok(Response::new(EchoResponse { message: full_msg }))
|
|
}
|
|
|
|
async fn bidirectional_echo(
|
|
&self,
|
|
request: Request<Streaming<EchoRequest>>,
|
|
) -> Result<Response<Self::BidirectionalEchoStream>, Status> {
|
|
let mut in_stream = request.into_inner();
|
|
let (tx, rx) = mpsc::channel(128);
|
|
|
|
tokio::spawn(async move {
|
|
while let Some(result) = in_stream.next().await {
|
|
match result {
|
|
Ok(req) => {
|
|
let resp = EchoResponse {
|
|
message: format!("echo: {}", req.message),
|
|
};
|
|
if tx.send(Ok(resp)).await.is_err() {
|
|
break;
|
|
}
|
|
}
|
|
Err(e) => {
|
|
let _ = tx.send(Err(e)).await;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
Ok(Response::new(Box::pin(ReceiverStream::new(rx))))
|
|
}
|
|
}
|