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