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 log;
20 extern crate env_logger;
21 
22 #[macro_use]
23 extern crate clap;
24 extern crate ordered_float;
25 extern crate thrift;
26 extern crate thrift_test;
27 
28 use ordered_float::OrderedFloat;
29 use std::collections::{BTreeMap, BTreeSet};
30 use std::thread;
31 use std::time::Duration;
32 
33 use thrift::protocol::{TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory,
34                        TCompactInputProtocolFactory, TCompactOutputProtocolFactory,
35                        TInputProtocolFactory, TOutputProtocolFactory};
36 use thrift::server::{TMultiplexedProcessor, TServer};
37 use thrift::transport::{TBufferedReadTransportFactory, TBufferedWriteTransportFactory,
38                         TFramedReadTransportFactory, TFramedWriteTransportFactory,
39                         TReadTransportFactory, TWriteTransportFactory};
40 use thrift_test::*;
41 
main()42 fn main() {
43     env_logger::init().expect("logger setup failed");
44 
45     debug!("initialized logger - running cross-test server");
46 
47     match run() {
48         Ok(()) => info!("cross-test server succeeded"),
49         Err(e) => {
50             info!("cross-test server failed with error {:?}", e);
51             std::process::exit(1);
52         }
53     }
54 }
55 
run() -> thrift::Result<()>56 fn run() -> thrift::Result<()> {
57 
58     // unsupported options:
59     // --domain-socket
60     // --named-pipe
61     // --ssl
62     let matches = clap_app!(rust_test_client =>
63         (version: "1.0")
64         (author: "Apache Thrift Developers <dev@thrift.apache.org>")
65         (about: "Rust Thrift test server")
66         (@arg port: --port +takes_value "port on which the test server listens")
67         (@arg transport: --transport +takes_value "transport implementation to use (\"buffered\", \"framed\")")
68         (@arg protocol: --protocol +takes_value "protocol implementation to use (\"binary\", \"compact\")")
69         (@arg server_type: --server_type +takes_value "type of server instantiated (\"simple\", \"thread-pool\")")
70         (@arg workers: -n --workers +takes_value "number of thread-pool workers (\"4\")")
71     )
72             .get_matches();
73 
74     let port = value_t!(matches, "port", u16).unwrap_or(9090);
75     let transport = matches.value_of("transport").unwrap_or("buffered");
76     let protocol = matches.value_of("protocol").unwrap_or("binary");
77     let server_type = matches.value_of("server_type").unwrap_or("thread-pool");
78     let workers = value_t!(matches, "workers", usize).unwrap_or(4);
79     let listen_address = format!("127.0.0.1:{}", port);
80 
81     info!("binding to {}", listen_address);
82 
83     let (i_transport_factory, o_transport_factory): (Box<TReadTransportFactory>,
84                                                      Box<TWriteTransportFactory>) =
85         match &*transport {
86             "buffered" => {
87                 (Box::new(TBufferedReadTransportFactory::new()),
88                  Box::new(TBufferedWriteTransportFactory::new()))
89             }
90             "framed" => {
91                 (Box::new(TFramedReadTransportFactory::new()),
92                  Box::new(TFramedWriteTransportFactory::new()))
93             }
94             unknown => {
95                 return Err(format!("unsupported transport type {}", unknown).into());
96             }
97         };
98 
99     let (i_protocol_factory, o_protocol_factory): (Box<TInputProtocolFactory>,
100                                                    Box<TOutputProtocolFactory>) =
101         match &*protocol {
102             "binary" | "multi" | "multi:binary" => {
103                 (Box::new(TBinaryInputProtocolFactory::new()),
104                  Box::new(TBinaryOutputProtocolFactory::new()))
105             }
106             "compact" | "multic" | "multi:compact" => {
107                 (Box::new(TCompactInputProtocolFactory::new()),
108                  Box::new(TCompactOutputProtocolFactory::new()))
109             }
110             unknown => {
111                 return Err(format!("unsupported transport type {}", unknown).into());
112             }
113         };
114 
115     let test_processor = ThriftTestSyncProcessor::new(ThriftTestSyncHandlerImpl {});
116 
117     match &*server_type {
118         "simple" | "thread-pool" => {
119             if protocol == "multi" || protocol == "multic" {
120                 let second_service_processor = SecondServiceSyncProcessor::new(SecondServiceSyncHandlerImpl {},);
121 
122                 let mut multiplexed_processor = TMultiplexedProcessor::new();
123                 multiplexed_processor
124                     .register("ThriftTest", Box::new(test_processor), true)?;
125                 multiplexed_processor
126                     .register("SecondService", Box::new(second_service_processor), false)?;
127 
128                 let mut server = TServer::new(
129                     i_transport_factory,
130                     i_protocol_factory,
131                     o_transport_factory,
132                     o_protocol_factory,
133                     multiplexed_processor,
134                     workers,
135                 );
136 
137                 server.listen(&listen_address)
138             } else {
139                 let mut server = TServer::new(
140                     i_transport_factory,
141                     i_protocol_factory,
142                     o_transport_factory,
143                     o_protocol_factory,
144                     test_processor,
145                     workers,
146                 );
147 
148                 server.listen(&listen_address)
149             }
150         }
151         unknown => Err(format!("unsupported server type {}", unknown).into()),
152     }
153 }
154 
155 struct ThriftTestSyncHandlerImpl;
156 impl ThriftTestSyncHandler for ThriftTestSyncHandlerImpl {
handle_test_void(&self) -> thrift::Result<()>157     fn handle_test_void(&self) -> thrift::Result<()> {
158         info!("testVoid()");
159         Ok(())
160     }
161 
handle_test_string(&self, thing: String) -> thrift::Result<String>162     fn handle_test_string(&self, thing: String) -> thrift::Result<String> {
163         info!("testString({})", &thing);
164         Ok(thing)
165     }
166 
handle_test_bool(&self, thing: bool) -> thrift::Result<bool>167     fn handle_test_bool(&self, thing: bool) -> thrift::Result<bool> {
168         info!("testBool({})", thing);
169         Ok(thing)
170     }
171 
handle_test_byte(&self, thing: i8) -> thrift::Result<i8>172     fn handle_test_byte(&self, thing: i8) -> thrift::Result<i8> {
173         info!("testByte({})", thing);
174         Ok(thing)
175     }
176 
handle_test_i32(&self, thing: i32) -> thrift::Result<i32>177     fn handle_test_i32(&self, thing: i32) -> thrift::Result<i32> {
178         info!("testi32({})", thing);
179         Ok(thing)
180     }
181 
handle_test_i64(&self, thing: i64) -> thrift::Result<i64>182     fn handle_test_i64(&self, thing: i64) -> thrift::Result<i64> {
183         info!("testi64({})", thing);
184         Ok(thing)
185     }
186 
handle_test_double(&self, thing: OrderedFloat<f64>) -> thrift::Result<OrderedFloat<f64>>187     fn handle_test_double(&self, thing: OrderedFloat<f64>) -> thrift::Result<OrderedFloat<f64>> {
188         info!("testDouble({})", thing);
189         Ok(thing)
190     }
191 
handle_test_binary(&self, thing: Vec<u8>) -> thrift::Result<Vec<u8>>192     fn handle_test_binary(&self, thing: Vec<u8>) -> thrift::Result<Vec<u8>> {
193         info!("testBinary({:?})", thing);
194         Ok(thing)
195     }
196 
handle_test_struct(&self, thing: Xtruct) -> thrift::Result<Xtruct>197     fn handle_test_struct(&self, thing: Xtruct) -> thrift::Result<Xtruct> {
198         info!("testStruct({:?})", thing);
199         Ok(thing)
200     }
201 
handle_test_nest(&self, thing: Xtruct2) -> thrift::Result<Xtruct2>202     fn handle_test_nest(&self, thing: Xtruct2) -> thrift::Result<Xtruct2> {
203         info!("testNest({:?})", thing);
204         Ok(thing)
205     }
206 
handle_test_map(&self, thing: BTreeMap<i32, i32>) -> thrift::Result<BTreeMap<i32, i32>>207     fn handle_test_map(&self, thing: BTreeMap<i32, i32>) -> thrift::Result<BTreeMap<i32, i32>> {
208         info!("testMap({:?})", thing);
209         Ok(thing)
210     }
211 
handle_test_string_map( &self, thing: BTreeMap<String, String>, ) -> thrift::Result<BTreeMap<String, String>>212     fn handle_test_string_map(
213         &self,
214         thing: BTreeMap<String, String>,
215     ) -> thrift::Result<BTreeMap<String, String>> {
216         info!("testStringMap({:?})", thing);
217         Ok(thing)
218     }
219 
handle_test_set(&self, thing: BTreeSet<i32>) -> thrift::Result<BTreeSet<i32>>220     fn handle_test_set(&self, thing: BTreeSet<i32>) -> thrift::Result<BTreeSet<i32>> {
221         info!("testSet({:?})", thing);
222         Ok(thing)
223     }
224 
handle_test_list(&self, thing: Vec<i32>) -> thrift::Result<Vec<i32>>225     fn handle_test_list(&self, thing: Vec<i32>) -> thrift::Result<Vec<i32>> {
226         info!("testList({:?})", thing);
227         Ok(thing)
228     }
229 
handle_test_enum(&self, thing: Numberz) -> thrift::Result<Numberz>230     fn handle_test_enum(&self, thing: Numberz) -> thrift::Result<Numberz> {
231         info!("testEnum({:?})", thing);
232         Ok(thing)
233     }
234 
handle_test_typedef(&self, thing: UserId) -> thrift::Result<UserId>235     fn handle_test_typedef(&self, thing: UserId) -> thrift::Result<UserId> {
236         info!("testTypedef({})", thing);
237         Ok(thing)
238     }
239 
240     /// @return map<i32,map<i32,i32>> - returns a dictionary with these values:
241     /// {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 =>
242     /// 2, 3 => 3, 4 => 4, }, }
handle_test_map_map(&self, hello: i32) -> thrift::Result<BTreeMap<i32, BTreeMap<i32, i32>>>243     fn handle_test_map_map(&self, hello: i32) -> thrift::Result<BTreeMap<i32, BTreeMap<i32, i32>>> {
244         info!("testMapMap({})", hello);
245 
246         let mut inner_map_0: BTreeMap<i32, i32> = BTreeMap::new();
247         for i in -4..(0 as i32) {
248             inner_map_0.insert(i, i);
249         }
250 
251         let mut inner_map_1: BTreeMap<i32, i32> = BTreeMap::new();
252         for i in 1..5 {
253             inner_map_1.insert(i, i);
254         }
255 
256         let mut ret_map: BTreeMap<i32, BTreeMap<i32, i32>> = BTreeMap::new();
257         ret_map.insert(-4, inner_map_0);
258         ret_map.insert(4, inner_map_1);
259 
260         Ok(ret_map)
261     }
262 
263     /// Creates a the returned map with these values and prints it out:
264     ///     { 1 => { 2 => argument,
265     ///              3 => argument,
266     ///            },
267     ///       2 => { 6 => <empty Insanity struct>, },
268     ///     }
269     /// return map<UserId, map<Numberz,Insanity>> - a map with the above values
handle_test_insanity( &self, argument: Insanity, ) -> thrift::Result<BTreeMap<UserId, BTreeMap<Numberz, Insanity>>>270     fn handle_test_insanity(
271         &self,
272         argument: Insanity,
273     ) -> thrift::Result<BTreeMap<UserId, BTreeMap<Numberz, Insanity>>> {
274         info!("testInsanity({:?})", argument);
275         let mut map_0: BTreeMap<Numberz, Insanity> = BTreeMap::new();
276         map_0.insert(Numberz::TWO, argument.clone());
277         map_0.insert(Numberz::THREE, argument.clone());
278 
279         let mut map_1: BTreeMap<Numberz, Insanity> = BTreeMap::new();
280         let insanity = Insanity {
281             user_map: None,
282             xtructs: None,
283         };
284         map_1.insert(Numberz::SIX, insanity);
285 
286         let mut ret: BTreeMap<UserId, BTreeMap<Numberz, Insanity>> = BTreeMap::new();
287         ret.insert(1, map_0);
288         ret.insert(2, map_1);
289 
290         Ok(ret)
291     }
292 
293     /// returns an Xtruct with:
294     /// string_thing = "Hello2", byte_thing = arg0, i32_thing = arg1 and
295     /// i64_thing = arg2
handle_test_multi( &self, arg0: i8, arg1: i32, arg2: i64, _: BTreeMap<i16, String>, _: Numberz, _: UserId, ) -> thrift::Result<Xtruct>296     fn handle_test_multi(
297         &self,
298         arg0: i8,
299         arg1: i32,
300         arg2: i64,
301         _: BTreeMap<i16, String>,
302         _: Numberz,
303         _: UserId,
304     ) -> thrift::Result<Xtruct> {
305         let x_ret = Xtruct {
306             string_thing: Some("Hello2".to_owned()),
307             byte_thing: Some(arg0),
308             i32_thing: Some(arg1),
309             i64_thing: Some(arg2),
310         };
311 
312         Ok(x_ret)
313     }
314 
315     /// if arg == "Xception" throw Xception with errorCode = 1001 and message =
316     /// arg
317     /// else if arg == "TException" throw TException
318     /// else do not throw anything
handle_test_exception(&self, arg: String) -> thrift::Result<()>319     fn handle_test_exception(&self, arg: String) -> thrift::Result<()> {
320         info!("testException({})", arg);
321 
322         match &*arg {
323             "Xception" => {
324                 Err(
325                     (Xception {
326                              error_code: Some(1001),
327                              message: Some(arg),
328                          })
329                         .into(),
330                 )
331             }
332             "TException" => Err("this is a random error".into()),
333             _ => Ok(()),
334         }
335     }
336 
337     /// if arg0 == "Xception":
338     /// throw Xception with errorCode = 1001 and message = "This is an
339     /// Xception"
340     /// else if arg0 == "Xception2":
341     /// throw Xception2 with errorCode = 2002 and struct_thing.string_thing =
342     /// "This is an Xception2"
343     // else:
344     //   do not throw anything and return Xtruct with string_thing = arg1
handle_test_multi_exception(&self, arg0: String, arg1: String) -> thrift::Result<Xtruct>345     fn handle_test_multi_exception(&self, arg0: String, arg1: String) -> thrift::Result<Xtruct> {
346         match &*arg0 {
347             "Xception" => {
348                 Err(
349                     (Xception {
350                              error_code: Some(1001),
351                              message: Some("This is an Xception".to_owned()),
352                          })
353                         .into(),
354                 )
355             }
356             "Xception2" => {
357                 Err(
358                     (Xception2 {
359                              error_code: Some(2002),
360                              struct_thing: Some(
361                             Xtruct {
362                                 string_thing: Some("This is an Xception2".to_owned()),
363                                 byte_thing: None,
364                                 i32_thing: None,
365                                 i64_thing: None,
366                             },
367                         ),
368                          })
369                         .into(),
370                 )
371             }
372             _ => {
373                 Ok(
374                     Xtruct {
375                         string_thing: Some(arg1),
376                         byte_thing: None,
377                         i32_thing: None,
378                         i64_thing: None,
379                     },
380                 )
381             }
382         }
383     }
384 
handle_test_oneway(&self, seconds_to_sleep: i32) -> thrift::Result<()>385     fn handle_test_oneway(&self, seconds_to_sleep: i32) -> thrift::Result<()> {
386         thread::sleep(Duration::from_secs(seconds_to_sleep as u64));
387         Ok(())
388     }
389 }
390 
391 struct SecondServiceSyncHandlerImpl;
392 impl SecondServiceSyncHandler for SecondServiceSyncHandlerImpl {
handle_secondtest_string(&self, thing: String) -> thrift::Result<String>393     fn handle_secondtest_string(&self, thing: String) -> thrift::Result<String> {
394         info!("(second)testString({})", &thing);
395         let ret = format!("testString(\"{}\")", &thing);
396         Ok(ret)
397     }
398 }
399