1+ use tonic:: { Request , Response , Status } ;
2+ use tonic:: transport:: Server ;
3+ use tokio_stream:: wrappers:: ReceiverStream ;
4+ use futures_util:: StreamExt ;
5+
6+ pub mod droidgrpc {
7+ tonic:: include_proto!( "droidgrpc" ) ;
8+ }
9+
10+ use droidgrpc:: arm_service_server:: { ArmService , ArmServiceServer } ;
11+ use droidgrpc:: leg_service_server:: { LegService , LegServiceServer } ;
12+ use droidgrpc:: { DroidConfigs , DroidStateResponse , DroidArmResponse , DroidCommandRequest , Empty } ;
13+
14+ #[ derive( Debug , Default ) ]
15+ pub struct DummyArmService { }
16+
17+ #[ tonic:: async_trait]
18+ impl ArmService for DummyArmService {
19+ // --- 1. Define the missing associated types ---
20+ type GetArmStateStreamStream = ReceiverStream < Result < DroidArmResponse , Status > > ;
21+ type ExchangeArmControlStreamStream = ReceiverStream < Result < DroidArmResponse , Status > > ;
22+
23+ // --- 2. Implement the methods ---
24+
25+ async fn get_arm_config ( & self , _: Request < Empty > ) -> Result < Response < DroidConfigs > , Status > {
26+ Ok ( Response :: new ( DroidConfigs :: default ( ) ) )
27+ }
28+
29+ async fn get_arm_state ( & self , _: Request < Empty > ) -> Result < Response < DroidArmResponse > , Status > {
30+ Ok ( Response :: new ( DroidArmResponse :: default ( ) ) )
31+ }
32+
33+ async fn get_arm_state_stream ( & self , _: Request < Empty > ) -> Result < Response < Self :: GetArmStateStreamStream > , Status > {
34+ let ( tx, rx) = tokio:: sync:: mpsc:: channel ( 4 ) ;
35+ // Minimal result: just one empty response
36+ let _ = tx. try_send ( Ok ( DroidArmResponse :: default ( ) ) ) ;
37+ Ok ( Response :: new ( ReceiverStream :: new ( rx) ) )
38+ }
39+
40+ async fn set_arm_command ( & self , _: Request < DroidCommandRequest > ) -> Result < Response < Empty > , Status > {
41+ Ok ( Response :: new ( Empty :: default ( ) ) )
42+ }
43+
44+ async fn set_arm_command_stream ( & self , mut request : Request < tonic:: Streaming < DroidCommandRequest > > ) -> Result < Response < Empty > , Status > {
45+ let mut stream = request. into_inner ( ) ;
46+ while let Some ( _cmd) = stream. next ( ) . await {
47+ // Echo/Process logic here
48+ }
49+ Ok ( Response :: new ( Empty :: default ( ) ) )
50+ }
51+
52+ async fn exchange_arm_control_stream (
53+ & self ,
54+ request : Request < tonic:: Streaming < DroidCommandRequest > > ,
55+ ) -> Result < Response < Self :: ExchangeArmControlStreamStream > , Status > {
56+ let mut in_stream = request. into_inner ( ) ;
57+ let ( tx, rx) = tokio:: sync:: mpsc:: channel ( 128 ) ;
58+
59+ tokio:: spawn ( async move {
60+ while let Some ( Ok ( cmd) ) = in_stream. next ( ) . await {
61+ // Echoing the command fields back into a response
62+ let echo = DroidArmResponse {
63+ position : cmd. position ,
64+ velocity : cmd. velocity ,
65+ torque : cmd. torque ,
66+ ..Default :: default ( )
67+ } ;
68+ if tx. send ( Ok ( echo) ) . await . is_err ( ) { break ; }
69+ }
70+ } ) ;
71+
72+ Ok ( Response :: new ( ReceiverStream :: new ( rx) ) )
73+ }
74+ }
75+
76+ #[ derive( Debug , Default ) ]
77+ pub struct DummyLegService { }
78+
79+ #[ tonic:: async_trait]
80+ impl LegService for DummyLegService {
81+ // Associated types required by the generated trait for streaming RPCs
82+ type GetLegStateStreamStream = ReceiverStream < Result < DroidStateResponse , Status > > ;
83+ type ExchangeLegControlStreamStream = ReceiverStream < Result < DroidStateResponse , Status > > ;
84+
85+ async fn get_leg_config ( & self , _: Request < Empty > ) -> Result < Response < DroidConfigs > , Status > {
86+ Ok ( Response :: new ( DroidConfigs :: default ( ) ) )
87+ }
88+
89+ async fn get_leg_state ( & self , _: Request < Empty > ) -> Result < Response < DroidStateResponse > , Status > {
90+ Ok ( Response :: new ( DroidStateResponse :: default ( ) ) )
91+ }
92+
93+ async fn get_leg_state_stream ( & self , _: Request < Empty > ) -> Result < Response < Self :: GetLegStateStreamStream > , Status > {
94+ let ( tx, rx) = tokio:: sync:: mpsc:: channel ( 4 ) ;
95+ // Minimal pulse: send one default state
96+ let _ = tx. try_send ( Ok ( DroidStateResponse :: default ( ) ) ) ;
97+ Ok ( Response :: new ( ReceiverStream :: new ( rx) ) )
98+ }
99+
100+ async fn set_leg_command ( & self , _: Request < DroidCommandRequest > ) -> Result < Response < Empty > , Status > {
101+ Ok ( Response :: new ( Empty :: default ( ) ) )
102+ }
103+
104+ async fn set_leg_command_stream ( & self , mut request : Request < tonic:: Streaming < DroidCommandRequest > > ) -> Result < Response < Empty > , Status > {
105+ let mut stream = request. into_inner ( ) ;
106+ while let Some ( Ok ( _cmd) ) = stream. next ( ) . await {
107+ // Echo logic could be added here for processing
108+ }
109+ Ok ( Response :: new ( Empty :: default ( ) ) )
110+ }
111+
112+ async fn exchange_leg_control_stream (
113+ & self ,
114+ request : Request < tonic:: Streaming < DroidCommandRequest > > ,
115+ ) -> Result < Response < Self :: ExchangeLegControlStreamStream > , Status > {
116+ let mut in_stream = request. into_inner ( ) ;
117+ let ( tx, rx) = tokio:: sync:: mpsc:: channel ( 128 ) ;
118+
119+ tokio:: spawn ( async move {
120+ while let Some ( Ok ( cmd) ) = in_stream. next ( ) . await {
121+ // Echo common fields from DroidCommandRequest to DroidStateResponse
122+ let echo = DroidStateResponse {
123+ position : cmd. position ,
124+ velocity : cmd. velocity ,
125+ torque : cmd. torque ,
126+ ..Default :: default ( )
127+ } ;
128+ if tx. send ( Ok ( echo) ) . await . is_err ( ) {
129+ break ;
130+ }
131+ }
132+ } ) ;
133+
134+ Ok ( Response :: new ( ReceiverStream :: new ( rx) ) )
135+ }
136+ }
137+
138+ #[ tokio:: main]
139+ async fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
140+ // 1. Define the addresses
141+ let leg_addr = "[::1]:50051" . parse ( ) ?;
142+ let arm_addr = "[::1]:50052" . parse ( ) ?;
143+
144+ println ! ( "LegService starting on {}" , leg_addr) ;
145+ println ! ( "ArmService starting on {}" , arm_addr) ;
146+
147+ // 2. Spawn the LegService on port 50051
148+ let leg_handle = tokio:: spawn ( async move {
149+ let service = DummyLegService :: default ( ) ;
150+ Server :: builder ( )
151+ . add_service ( LegServiceServer :: new ( service) )
152+ . serve ( leg_addr)
153+ . await
154+ . expect ( "LegService server failed" ) ;
155+ } ) ;
156+
157+ // 3. Spawn the ArmService on port 50052
158+ let arm_handle = tokio:: spawn ( async move {
159+ let service = DummyArmService :: default ( ) ;
160+ Server :: builder ( )
161+ . add_service ( ArmServiceServer :: new ( service) )
162+ . serve ( arm_addr)
163+ . await
164+ . expect ( "ArmService server failed" ) ;
165+ } ) ;
166+
167+ // 4. Wait for both servers (they will run indefinitely)
168+ let _ = tokio:: try_join!( leg_handle, arm_handle) ?;
169+
170+ Ok ( ( ) )
171+ }
0 commit comments