Skip to content

Commit ab398e4

Browse files
authored
Added sample protobuf services math_server and math_client (#94)
1 parent c422255 commit ab398e4

File tree

9 files changed

+330
-0
lines changed

9 files changed

+330
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ members = [
2222
"rustecal-samples/pubsub/person_receive",
2323
"rustecal-samples/pubsub/serde_send",
2424
"rustecal-samples/pubsub/serde_receive",
25+
"rustecal-samples/service/math_client",
26+
"rustecal-samples/service/math_server",
2527
"rustecal-samples/service/mirror_client",
2628
"rustecal-samples/service/mirror_client_instances",
2729
"rustecal-samples/service/mirror_server",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "math_client"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
rustecal = { path = "../../../rustecal", features = ["service"] }
8+
prost = "0.14"
9+
10+
11+
[build-dependencies]
12+
prost-build = "0.14"
13+
prost-reflect-build = "0.16.0"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let protos = ["proto/math.proto"];
3+
4+
let protos_inc = ["proto"];
5+
6+
prost_build::compile_protos(&protos, &protos_inc).unwrap();
7+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* ========================= eCAL LICENSE =================================
2+
*
3+
* Copyright (C) 2016 - 2019 Continental Corporation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* ========================= eCAL LICENSE =================================
18+
*/
19+
20+
syntax = "proto3";
21+
22+
option cc_generic_services = true;
23+
24+
///////////////////////////////////////////////////////
25+
// Math Service
26+
///////////////////////////////////////////////////////
27+
message SFloatTuple
28+
{
29+
double inp1 = 1;
30+
double inp2 = 2;
31+
}
32+
33+
message SFloat
34+
{
35+
double out = 1;
36+
}
37+
38+
service MathService
39+
{
40+
rpc Add (SFloatTuple) returns (SFloat);
41+
rpc Multiply (SFloatTuple) returns (SFloat);
42+
rpc Divide (SFloatTuple) returns (SFloat);
43+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use prost::Message;
2+
use rustecal::{CallState, ServiceClient, ServiceRequest};
3+
use rustecal::{Ecal, EcalComponents};
4+
use std::thread;
5+
use std::time::Duration;
6+
7+
// Add the protobuf compiled by prost
8+
mod math_pb {
9+
include!(concat!(env!("OUT_DIR"), "/_.rs"));
10+
}
11+
use math_pb::{SFloat, SFloatTuple};
12+
13+
fn main() -> Result<(), Box<dyn std::error::Error>> {
14+
// initialize eCAL
15+
Ecal::initialize(Some("math client rust"), EcalComponents::DEFAULT, None)
16+
.expect("eCAL initialization failed");
17+
18+
let client = ServiceClient::new("MathService")?;
19+
20+
// wait until connected
21+
while client.get_client_instances().is_empty() {
22+
println!("Waiting for a service ..");
23+
thread::sleep(Duration::from_secs(1));
24+
}
25+
26+
let methods = ["Add", "Multiply", "Divide"];
27+
let mut i = 0;
28+
29+
while Ecal::ok() {
30+
let method_name = methods[i % methods.len()];
31+
i += 1;
32+
33+
let payload_pb = SFloatTuple {
34+
inp1: i as f64,
35+
inp2: (i + 1) as f64,
36+
};
37+
38+
let request = ServiceRequest {
39+
payload: payload_pb.encode_to_vec(),
40+
};
41+
42+
for instance in client.get_client_instances() {
43+
let response = instance.call(method_name, request.clone(), Some(1000));
44+
45+
println!();
46+
println!(
47+
"Method '{}' called with message: {:?}",
48+
method_name, payload_pb
49+
);
50+
51+
match response {
52+
Some(res) => match CallState::from(res.success as i32) {
53+
CallState::Executed => {
54+
let response_data = SFloat::decode(&res.payload[..])?;
55+
println!(
56+
"Received response: {:?} from service id {:?}",
57+
response_data, res.server_id.service_id.entity_id
58+
);
59+
}
60+
CallState::Failed => {
61+
println!(
62+
"Received error: {} from service id {:?}",
63+
res.error_msg.unwrap_or_else(|| "Unknown".into()),
64+
res.server_id.service_id.entity_id
65+
);
66+
}
67+
_ => {}
68+
},
69+
None => {
70+
println!("Method blocking call failed ..");
71+
}
72+
}
73+
}
74+
75+
thread::sleep(Duration::from_secs(1));
76+
}
77+
78+
// clean up and finalize eCAL
79+
Ecal::finalize();
80+
Ok(())
81+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "math_server"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
rustecal = { path = "../../../rustecal", features = ["service"] }
8+
prost = "0.14"
9+
10+
11+
[build-dependencies]
12+
prost-build = "0.14"
13+
prost-reflect-build = "0.16.0"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let protos = ["proto/math.proto"];
3+
4+
let protos_inc = ["proto"];
5+
6+
prost_build::compile_protos(&protos, &protos_inc).unwrap();
7+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* ========================= eCAL LICENSE =================================
2+
*
3+
* Copyright (C) 2016 - 2019 Continental Corporation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
* ========================= eCAL LICENSE =================================
18+
*/
19+
20+
syntax = "proto3";
21+
22+
option cc_generic_services = true;
23+
24+
///////////////////////////////////////////////////////
25+
// Math Service
26+
///////////////////////////////////////////////////////
27+
message SFloatTuple
28+
{
29+
double inp1 = 1;
30+
double inp2 = 2;
31+
}
32+
33+
message SFloat
34+
{
35+
double out = 1;
36+
}
37+
38+
service MathService
39+
{
40+
rpc Add (SFloatTuple) returns (SFloat);
41+
rpc Multiply (SFloatTuple) returns (SFloat);
42+
rpc Divide (SFloatTuple) returns (SFloat);
43+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
use prost::Message;
2+
use rustecal::{Ecal, EcalComponents};
3+
use rustecal::{MethodInfo, ServiceServer};
4+
5+
// Add the protobuf compiled by prost
6+
mod math_pb {
7+
include!(concat!(env!("OUT_DIR"), "/_.rs"));
8+
}
9+
use math_pb::{SFloat, SFloatTuple};
10+
11+
fn main() -> Result<(), Box<dyn std::error::Error>> {
12+
// initialize eCAL
13+
Ecal::initialize(Some("math server rust"), EcalComponents::DEFAULT, None)
14+
.expect("eCAL initialization failed");
15+
16+
// create the service server named "MathService"
17+
let mut server = ServiceServer::new("MathService")?;
18+
19+
// register "Add" method from protobuf rpc
20+
server.add_method(
21+
"Add",
22+
Box::new(|info: MethodInfo, req: &[u8]| {
23+
// Decode serialized protobuf request
24+
let req_pb = SFloatTuple::decode(req);
25+
26+
match req_pb {
27+
Ok(pb) => {
28+
println!(
29+
"Received request for MathService in Rust: {}",
30+
info.method_name
31+
);
32+
println!("Input1 : {}", pb.inp1);
33+
println!("Input2 : {}", pb.inp2);
34+
println!();
35+
36+
let result = SFloat {
37+
out: pb.inp1 + pb.inp2,
38+
};
39+
// Serialize protobuf response
40+
result.encode_to_vec()
41+
}
42+
_ => {
43+
println!("Unable to decode protobuf");
44+
vec![]
45+
}
46+
}
47+
}),
48+
)?;
49+
50+
// register "Multiply" method from protobuf rpc
51+
server.add_method(
52+
"Multiply",
53+
Box::new(|info: MethodInfo, req: &[u8]| {
54+
// Decode serialized protobuf request
55+
let req_pb = SFloatTuple::decode(req);
56+
57+
match req_pb {
58+
Ok(pb) => {
59+
println!(
60+
"Received request for MathService in Rust: {}",
61+
info.method_name
62+
);
63+
println!("Input1 : {}", pb.inp1);
64+
println!("Input2 : {}", pb.inp2);
65+
println!();
66+
67+
let result = SFloat {
68+
out: pb.inp1 * pb.inp2,
69+
};
70+
// Serialize protobuf response
71+
result.encode_to_vec()
72+
}
73+
_ => {
74+
println!("Unable to decode protobuf");
75+
vec![]
76+
}
77+
}
78+
}),
79+
)?;
80+
81+
// register "Divide" method from protobuf rpc
82+
server.add_method(
83+
"Divide",
84+
Box::new(|info: MethodInfo, req: &[u8]| {
85+
// Decode serialized protobuf request
86+
let req_pb = SFloatTuple::decode(req);
87+
88+
match req_pb {
89+
Ok(pb) => {
90+
println!(
91+
"Received request for MathService in Rust: {}",
92+
info.method_name
93+
);
94+
println!("Input1 : {}", pb.inp1);
95+
println!("Input2 : {}", pb.inp2);
96+
println!();
97+
98+
let result = SFloat {
99+
out: pb.inp1 / pb.inp2,
100+
};
101+
// Serialize protobuf response
102+
result.encode_to_vec()
103+
}
104+
_ => {
105+
println!("Unable to decode protobuf");
106+
vec![]
107+
}
108+
}
109+
}),
110+
)?;
111+
112+
println!("Rust math service running. Press Ctrl+C to exit.");
113+
114+
while Ecal::ok() {
115+
std::thread::sleep(std::time::Duration::from_millis(100));
116+
}
117+
118+
// clean up and finalize eCAL
119+
Ecal::finalize();
120+
Ok(())
121+
}

0 commit comments

Comments
 (0)