1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. 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,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17 
18 #[macro_use]
19 extern crate clap;
20 extern crate kitchen_sink;
21 extern crate thrift;
22 
23 use thrift::protocol::{
24     TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, TCompactInputProtocolFactory,
25     TCompactOutputProtocolFactory, TInputProtocolFactory, TOutputProtocolFactory,
26 };
27 use thrift::server::TServer;
28 use thrift::transport::{
29     TFramedReadTransportFactory, TFramedWriteTransportFactory, TReadTransportFactory,
30     TWriteTransportFactory,
31 };
32 
33 use kitchen_sink::base_one::Noodle;
34 use kitchen_sink::base_two::{
35     BrothType, Napkin, NapkinServiceSyncHandler, Ramen, RamenServiceSyncHandler,
36 };
37 use kitchen_sink::midlayer::{
38     Dessert, Meal, MealServiceSyncHandler, MealServiceSyncProcessor, Pie,
39 };
40 use kitchen_sink::recursive;
41 use kitchen_sink::ultimate::FullMealAndDrinksServiceSyncHandler;
42 use kitchen_sink::ultimate::{
43     Drink, FullMeal, FullMealAndDrinks, FullMealAndDrinksServiceSyncProcessor,
44     FullMealServiceSyncHandler,
45 };
46 
main()47 fn main() {
48     match run() {
49         Ok(()) => println!("kitchen sink server completed successfully"),
50         Err(e) => {
51             println!("kitchen sink server failed with error {:?}", e);
52             std::process::exit(1);
53         }
54     }
55 }
56 
run() -> thrift::Result<()>57 fn run() -> thrift::Result<()> {
58     let matches = clap_app!(rust_kitchen_sink_server =>
59         (version: "0.1.0")
60         (author: "Apache Thrift Developers <dev@thrift.apache.org>")
61         (about: "Thrift Rust kitchen sink test server")
62         (@arg port: --port +takes_value "port on which the test server listens")
63         (@arg protocol: --protocol +takes_value "Thrift protocol implementation to use (\"binary\", \"compact\")")
64         (@arg service: --service +takes_value "Service type to contact (\"part\", \"full\", \"recursive\")")
65     )
66             .get_matches();
67 
68     let port = value_t!(matches, "port", u16).unwrap_or(9090);
69     let protocol = matches.value_of("protocol").unwrap_or("compact");
70     let service = matches.value_of("service").unwrap_or("part");
71     let listen_address = format!("127.0.0.1:{}", port);
72 
73     println!("binding to {}", listen_address);
74 
75     let r_transport_factory = TFramedReadTransportFactory::new();
76     let w_transport_factory = TFramedWriteTransportFactory::new();
77 
78     let (i_protocol_factory, o_protocol_factory): (
79         Box<TInputProtocolFactory>,
80         Box<TOutputProtocolFactory>,
81     ) = match &*protocol {
82         "binary" => (
83             Box::new(TBinaryInputProtocolFactory::new()),
84             Box::new(TBinaryOutputProtocolFactory::new()),
85         ),
86         "compact" => (
87             Box::new(TCompactInputProtocolFactory::new()),
88             Box::new(TCompactOutputProtocolFactory::new()),
89         ),
90         unknown => {
91             return Err(format!("unsupported transport type {}", unknown).into());
92         }
93     };
94 
95     // FIXME: should processor be boxed as well?
96     //
97     // [sigh] I hate Rust generics implementation
98     //
99     // I would have preferred to build a server here, return it, and then do
100     // the common listen-and-handle stuff, but since the server doesn't have a
101     // common type (because each match arm instantiates a server with a
102     // different processor) this isn't possible.
103     //
104     // Since what I'm doing is uncommon I'm just going to duplicate the code
105     match &*service {
106         "part" => run_meal_server(
107             &listen_address,
108             r_transport_factory,
109             i_protocol_factory,
110             w_transport_factory,
111             o_protocol_factory,
112         ),
113         "full" => run_full_meal_server(
114             &listen_address,
115             r_transport_factory,
116             i_protocol_factory,
117             w_transport_factory,
118             o_protocol_factory,
119         ),
120         "recursive" => run_recursive_server(
121             &listen_address,
122             r_transport_factory,
123             i_protocol_factory,
124             w_transport_factory,
125             o_protocol_factory,
126         ),
127         unknown => Err(format!("unsupported service type {}", unknown).into()),
128     }
129 }
130 
run_meal_server<RTF, IPF, WTF, OPF>( listen_address: &str, r_transport_factory: RTF, i_protocol_factory: IPF, w_transport_factory: WTF, o_protocol_factory: OPF, ) -> thrift::Result<()> where RTF: TReadTransportFactory + 'static, IPF: TInputProtocolFactory + 'static, WTF: TWriteTransportFactory + 'static, OPF: TOutputProtocolFactory + 'static,131 fn run_meal_server<RTF, IPF, WTF, OPF>(
132     listen_address: &str,
133     r_transport_factory: RTF,
134     i_protocol_factory: IPF,
135     w_transport_factory: WTF,
136     o_protocol_factory: OPF,
137 ) -> thrift::Result<()>
138 where
139     RTF: TReadTransportFactory + 'static,
140     IPF: TInputProtocolFactory + 'static,
141     WTF: TWriteTransportFactory + 'static,
142     OPF: TOutputProtocolFactory + 'static,
143 {
144     let processor = MealServiceSyncProcessor::new(PartHandler {});
145     let mut server = TServer::new(
146         r_transport_factory,
147         i_protocol_factory,
148         w_transport_factory,
149         o_protocol_factory,
150         processor,
151         1,
152     );
153 
154     server.listen(listen_address)
155 }
156 
run_full_meal_server<RTF, IPF, WTF, OPF>( listen_address: &str, r_transport_factory: RTF, i_protocol_factory: IPF, w_transport_factory: WTF, o_protocol_factory: OPF, ) -> thrift::Result<()> where RTF: TReadTransportFactory + 'static, IPF: TInputProtocolFactory + 'static, WTF: TWriteTransportFactory + 'static, OPF: TOutputProtocolFactory + 'static,157 fn run_full_meal_server<RTF, IPF, WTF, OPF>(
158     listen_address: &str,
159     r_transport_factory: RTF,
160     i_protocol_factory: IPF,
161     w_transport_factory: WTF,
162     o_protocol_factory: OPF,
163 ) -> thrift::Result<()>
164 where
165     RTF: TReadTransportFactory + 'static,
166     IPF: TInputProtocolFactory + 'static,
167     WTF: TWriteTransportFactory + 'static,
168     OPF: TOutputProtocolFactory + 'static,
169 {
170     let processor = FullMealAndDrinksServiceSyncProcessor::new(FullHandler {});
171     let mut server = TServer::new(
172         r_transport_factory,
173         i_protocol_factory,
174         w_transport_factory,
175         o_protocol_factory,
176         processor,
177         1,
178     );
179 
180     server.listen(listen_address)
181 }
182 
183 struct PartHandler;
184 
185 impl MealServiceSyncHandler for PartHandler {
handle_meal(&self) -> thrift::Result<Meal>186     fn handle_meal(&self) -> thrift::Result<Meal> {
187         println!("part: handling meal call");
188         Ok(meal())
189     }
190 }
191 
192 impl RamenServiceSyncHandler for PartHandler {
handle_ramen(&self, _: i32) -> thrift::Result<Ramen>193     fn handle_ramen(&self, _: i32) -> thrift::Result<Ramen> {
194         println!("part: handling ramen call");
195         Ok(ramen())
196     }
197 }
198 
199 impl NapkinServiceSyncHandler for PartHandler {
handle_napkin(&self) -> thrift::Result<Napkin>200     fn handle_napkin(&self) -> thrift::Result<Napkin> {
201         println!("part: handling napkin call");
202         Ok(napkin())
203     }
204 }
205 
206 // full service
207 //
208 
209 struct FullHandler;
210 
211 impl FullMealAndDrinksServiceSyncHandler for FullHandler {
handle_full_meal_and_drinks(&self) -> thrift::Result<FullMealAndDrinks>212     fn handle_full_meal_and_drinks(&self) -> thrift::Result<FullMealAndDrinks> {
213         println!("full_meal_and_drinks: handling full meal and drinks call");
214         Ok(FullMealAndDrinks::new(full_meal(), Drink::CanadianWhisky))
215     }
216 
handle_best_pie(&self) -> thrift::Result<Pie>217     fn handle_best_pie(&self) -> thrift::Result<Pie> {
218         println!("full_meal_and_drinks: handling pie call");
219         Ok(Pie::MississippiMud) // I prefer Pie::Pumpkin, but I have to check that casing works
220     }
221 }
222 
223 impl FullMealServiceSyncHandler for FullHandler {
handle_full_meal(&self) -> thrift::Result<FullMeal>224     fn handle_full_meal(&self) -> thrift::Result<FullMeal> {
225         println!("full: handling full meal call");
226         Ok(full_meal())
227     }
228 }
229 
230 impl MealServiceSyncHandler for FullHandler {
handle_meal(&self) -> thrift::Result<Meal>231     fn handle_meal(&self) -> thrift::Result<Meal> {
232         println!("full: handling meal call");
233         Ok(meal())
234     }
235 }
236 
237 impl RamenServiceSyncHandler for FullHandler {
handle_ramen(&self, _: i32) -> thrift::Result<Ramen>238     fn handle_ramen(&self, _: i32) -> thrift::Result<Ramen> {
239         println!("full: handling ramen call");
240         Ok(ramen())
241     }
242 }
243 
244 impl NapkinServiceSyncHandler for FullHandler {
handle_napkin(&self) -> thrift::Result<Napkin>245     fn handle_napkin(&self) -> thrift::Result<Napkin> {
246         println!("full: handling napkin call");
247         Ok(napkin())
248     }
249 }
250 
full_meal() -> FullMeal251 fn full_meal() -> FullMeal {
252     FullMeal::new(meal(), Dessert::Port("Graham's Tawny".to_owned()))
253 }
254 
meal() -> Meal255 fn meal() -> Meal {
256     Meal::new(noodle(), ramen())
257 }
258 
noodle() -> Noodle259 fn noodle() -> Noodle {
260     Noodle::new("spelt".to_owned(), 100)
261 }
262 
ramen() -> Ramen263 fn ramen() -> Ramen {
264     Ramen::new("Mr Ramen".to_owned(), 72, BrothType::Miso)
265 }
266 
napkin() -> Napkin267 fn napkin() -> Napkin {
268     Napkin {}
269 }
270 
run_recursive_server<RTF, IPF, WTF, OPF>( listen_address: &str, r_transport_factory: RTF, i_protocol_factory: IPF, w_transport_factory: WTF, o_protocol_factory: OPF, ) -> thrift::Result<()> where RTF: TReadTransportFactory + 'static, IPF: TInputProtocolFactory + 'static, WTF: TWriteTransportFactory + 'static, OPF: TOutputProtocolFactory + 'static,271 fn run_recursive_server<RTF, IPF, WTF, OPF>(
272     listen_address: &str,
273     r_transport_factory: RTF,
274     i_protocol_factory: IPF,
275     w_transport_factory: WTF,
276     o_protocol_factory: OPF,
277 ) -> thrift::Result<()>
278 where
279     RTF: TReadTransportFactory + 'static,
280     IPF: TInputProtocolFactory + 'static,
281     WTF: TWriteTransportFactory + 'static,
282     OPF: TOutputProtocolFactory + 'static,
283 {
284     let processor = recursive::TestServiceSyncProcessor::new(RecursiveTestServerHandler {});
285     let mut server = TServer::new(
286         r_transport_factory,
287         i_protocol_factory,
288         w_transport_factory,
289         o_protocol_factory,
290         processor,
291         1,
292     );
293 
294     server.listen(listen_address)
295 }
296 
297 struct RecursiveTestServerHandler;
298 impl recursive::TestServiceSyncHandler for RecursiveTestServerHandler {
handle_echo_tree(&self, tree: recursive::RecTree) -> thrift::Result<recursive::RecTree>299     fn handle_echo_tree(&self, tree: recursive::RecTree) -> thrift::Result<recursive::RecTree> {
300         println!("{:?}", tree);
301         Ok(tree)
302     }
303 
handle_echo_list(&self, lst: recursive::RecList) -> thrift::Result<recursive::RecList>304     fn handle_echo_list(&self, lst: recursive::RecList) -> thrift::Result<recursive::RecList> {
305         println!("{:?}", lst);
306         Ok(lst)
307     }
308 
handle_echo_co_rec(&self, item: recursive::CoRec) -> thrift::Result<recursive::CoRec>309     fn handle_echo_co_rec(&self, item: recursive::CoRec) -> thrift::Result<recursive::CoRec> {
310         println!("{:?}", item);
311         Ok(item)
312     }
313 }
314