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