first commit
This commit is contained in:
commit
7057a0584d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
1226
Cargo.lock
generated
Normal file
1226
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
Cargo.toml
Normal file
25
Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "rust_test_grpc"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "server"
|
||||||
|
path = "src/server.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "client"
|
||||||
|
path = "src/client.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
futures = "0.3"
|
||||||
|
prost = "0.13"
|
||||||
|
prost-types = "0.13"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
tokio = { version = "1.42", features = ["macros", "rt-multi-thread"] }
|
||||||
|
tokio-stream = "0.1"
|
||||||
|
tonic = "0.12"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tonic-build = "0.12"
|
6
build.rs
Normal file
6
build.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
fn main() {
|
||||||
|
tonic_build::configure()
|
||||||
|
.build_server(true)
|
||||||
|
.compile_protos(&["dummy.proto"], &["proto"])
|
||||||
|
.unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e));
|
||||||
|
}
|
27
dummy.proto
Normal file
27
dummy.proto
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package dummy;
|
||||||
|
|
||||||
|
message Empty {
|
||||||
|
}
|
||||||
|
|
||||||
|
message SomeRequest {
|
||||||
|
string what_client_sends = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SomeResponse {
|
||||||
|
string what_server_sends = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StreamRequest {
|
||||||
|
string what_client_sends = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StreamResponse {
|
||||||
|
string what_server_sends = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
service TestService {
|
||||||
|
rpc GetSomething (SomeRequest) returns (SomeResponse);
|
||||||
|
rpc ClientMessages (stream StreamRequest) returns (Empty);
|
||||||
|
rpc ServerMessages (Empty) returns (stream StreamResponse);
|
||||||
|
}
|
5
src/client.rs
Normal file
5
src/client.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
mod grpc;
|
||||||
|
|
||||||
|
fn main (){
|
||||||
|
println!("Hello! I am a client!");
|
||||||
|
}
|
3
src/grpc.rs
Normal file
3
src/grpc.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod dummy {
|
||||||
|
tonic::include_proto!("dummy");
|
||||||
|
}
|
110
src/server.rs
Normal file
110
src/server.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use futures::Stream;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio_stream::{wrappers::ReceiverStream, StreamExt};
|
||||||
|
use tonic::{transport::Server, Request, Response, Status};
|
||||||
|
mod grpc;
|
||||||
|
|
||||||
|
// Import the generated server trait and messages.
|
||||||
|
use grpc::dummy::brain_daemon_server::{BrainDaemon, BrainDaemonServer};
|
||||||
|
use grpc::dummy::{Empty, SomeRequest, SomeResponse, StreamRequest, StreamResponse};
|
||||||
|
|
||||||
|
/// Our service implementation
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct MyBrainDaemon;
|
||||||
|
|
||||||
|
#[tonic::async_trait]
|
||||||
|
impl BrainDaemon for MyBrainDaemon {
|
||||||
|
/// Unary RPC: (SomeRequest) -> SomeResponse
|
||||||
|
async fn get_something(
|
||||||
|
&self,
|
||||||
|
request: Request<SomeRequest>,
|
||||||
|
) -> Result<Response<SomeResponse>, Status> {
|
||||||
|
// Extract the request message
|
||||||
|
let req = request.into_inner();
|
||||||
|
println!("Got a request: {:?}", req.what_client_sends);
|
||||||
|
|
||||||
|
// Build the response
|
||||||
|
let reply = SomeResponse {
|
||||||
|
what_server_sends: format!("Server says: Hello, {}!", req.what_client_sends),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Response::new(reply))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn client_messages(
|
||||||
|
&self,
|
||||||
|
request: Request<tonic::Streaming<StreamRequest>>,
|
||||||
|
) -> Result<Response<Empty>, Status> {
|
||||||
|
let mut stream = request.into_inner();
|
||||||
|
|
||||||
|
// Process the incoming stream
|
||||||
|
while let Some(item) = stream.next().await {
|
||||||
|
let message = item?;
|
||||||
|
println!("Received stream message: {}", message.what_client_sends);
|
||||||
|
// Do something with the message ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an Empty to the client
|
||||||
|
Ok(Response::new(Empty {}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Server streaming RPC: (Empty) -> (stream StreamResponse)
|
||||||
|
type ServerMessagesStream =
|
||||||
|
Pin<Box<dyn Stream<Item = Result<StreamResponse, Status>> + Send + 'static>>;
|
||||||
|
|
||||||
|
async fn server_messages(
|
||||||
|
&self,
|
||||||
|
_request: Request<Empty>,
|
||||||
|
) -> Result<Response<Self::ServerMessagesStream>, Status> {
|
||||||
|
// Create a channel (or use any stream you like)
|
||||||
|
let (tx, rx) = tokio::sync::mpsc::channel(4);
|
||||||
|
|
||||||
|
// Spawn a task that sends data to the client
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let messages = vec![
|
||||||
|
"Hello from the server!",
|
||||||
|
"Here's another message!",
|
||||||
|
"And one more message!",
|
||||||
|
];
|
||||||
|
|
||||||
|
for msg in messages {
|
||||||
|
// Send a single response
|
||||||
|
let response = StreamResponse {
|
||||||
|
what_server_sends: msg.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = tx.send(Ok(response)).await {
|
||||||
|
eprintln!("Failed to send response via stream: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert MPSC receiver into a Tonic-friendly stream
|
||||||
|
let output_stream = ReceiverStream::new(rx);
|
||||||
|
|
||||||
|
// Box it up and return
|
||||||
|
Ok(Response::new(
|
||||||
|
Box::pin(output_stream) as Self::ServerMessagesStream
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// The address on which your server will listen
|
||||||
|
let addr = "[::1]:50051".parse()?;
|
||||||
|
|
||||||
|
// Create an instance of your service
|
||||||
|
let daemon = MyBrainDaemon::default();
|
||||||
|
|
||||||
|
println!("BrainDaemon server listening on {}", addr);
|
||||||
|
|
||||||
|
// Run the server
|
||||||
|
Server::builder()
|
||||||
|
.add_service(BrainDaemonServer::new(daemon))
|
||||||
|
.serve(addr)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user