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
9 // http://www.apache.org/licenses/LICENSE-2.0
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
20 extern crate kitchen_sink
;
23 use thrift
::protocol
::{
24 TBinaryInputProtocolFactory
, TBinaryOutputProtocolFactory
, TCompactInputProtocolFactory
,
25 TCompactOutputProtocolFactory
, TInputProtocolFactory
, TOutputProtocolFactory
,
27 use thrift
::server
::TServer
;
28 use thrift
::transport
::{
29 TFramedReadTransportFactory
, TFramedWriteTransportFactory
, TReadTransportFactory
,
30 TWriteTransportFactory
,
33 use kitchen_sink
::base_one
::Noodle
;
34 use kitchen_sink
::base_two
::{
35 BrothType
, Napkin
, NapkinServiceSyncHandler
, Ramen
, RamenServiceSyncHandler
,
37 use kitchen_sink
::midlayer
::{
38 Dessert
, Meal
, MealServiceSyncHandler
, MealServiceSyncProcessor
, Pie
,
40 use kitchen_sink
::recursive
;
41 use kitchen_sink
::ultimate
::FullMealAndDrinksServiceSyncHandler
;
42 use kitchen_sink
::ultimate
::{
43 Drink
, FullMeal
, FullMealAndDrinks
, FullMealAndDrinksServiceSyncProcessor
,
44 FullMealServiceSyncHandler
,
49 Ok(()) => println
!("kitchen sink server completed successfully"),
51 println
!("kitchen sink server failed with error {:?}", e
);
52 std
::process
::exit(1);
57 fn run() -> thrift
::Result
<()> {
58 let matches
= clap_app
!(rust_kitchen_sink_server
=>
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\")")
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
);
73 println
!("binding to {}", listen_address
);
75 let r_transport_factory
= TFramedReadTransportFactory
::new();
76 let w_transport_factory
= TFramedWriteTransportFactory
::new();
78 let (i_protocol_factory
, o_protocol_factory
): (
79 Box
<TInputProtocolFactory
>,
80 Box
<TOutputProtocolFactory
>,
81 ) = match &*protocol
{
83 Box
::new(TBinaryInputProtocolFactory
::new()),
84 Box
::new(TBinaryOutputProtocolFactory
::new()),
87 Box
::new(TCompactInputProtocolFactory
::new()),
88 Box
::new(TCompactOutputProtocolFactory
::new()),
91 return Err(format
!("unsupported transport type {}", unknown
).into());
95 // FIXME: should processor be boxed as well?
97 // [sigh] I hate Rust generics implementation
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.
104 // Since what I'm doing is uncommon I'm just going to duplicate the code
106 "part" => run_meal_server(
113 "full" => run_full_meal_server(
120 "recursive" => run_recursive_server(
127 unknown
=> Err(format
!("unsupported service type {}", unknown
).into()),
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
<()>
139 RTF
: TReadTransportFactory
+ '
static,
140 IPF
: TInputProtocolFactory
+ '
static,
141 WTF
: TWriteTransportFactory
+ '
static,
142 OPF
: TOutputProtocolFactory
+ '
static,
144 let processor
= MealServiceSyncProcessor
::new(PartHandler {}
);
145 let mut server
= TServer
::new(
154 server
.listen(listen_address
)
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
<()>
165 RTF
: TReadTransportFactory
+ '
static,
166 IPF
: TInputProtocolFactory
+ '
static,
167 WTF
: TWriteTransportFactory
+ '
static,
168 OPF
: TOutputProtocolFactory
+ '
static,
170 let processor
= FullMealAndDrinksServiceSyncProcessor
::new(FullHandler {}
);
171 let mut server
= TServer
::new(
180 server
.listen(listen_address
)
185 impl MealServiceSyncHandler
for PartHandler
{
186 fn handle_meal(&self) -> thrift
::Result
<Meal
> {
187 println
!("part: handling meal call");
192 impl RamenServiceSyncHandler
for PartHandler
{
193 fn handle_ramen(&self, _
: i32) -> thrift
::Result
<Ramen
> {
194 println
!("part: handling ramen call");
199 impl NapkinServiceSyncHandler
for PartHandler
{
200 fn handle_napkin(&self) -> thrift
::Result
<Napkin
> {
201 println
!("part: handling napkin call");
211 impl FullMealAndDrinksServiceSyncHandler
for FullHandler
{
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
))
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
223 impl FullMealServiceSyncHandler
for FullHandler
{
224 fn handle_full_meal(&self) -> thrift
::Result
<FullMeal
> {
225 println
!("full: handling full meal call");
230 impl MealServiceSyncHandler
for FullHandler
{
231 fn handle_meal(&self) -> thrift
::Result
<Meal
> {
232 println
!("full: handling meal call");
237 impl RamenServiceSyncHandler
for FullHandler
{
238 fn handle_ramen(&self, _
: i32) -> thrift
::Result
<Ramen
> {
239 println
!("full: handling ramen call");
244 impl NapkinServiceSyncHandler
for FullHandler
{
245 fn handle_napkin(&self) -> thrift
::Result
<Napkin
> {
246 println
!("full: handling napkin call");
251 fn full_meal() -> FullMeal
{
252 FullMeal
::new(meal(), Dessert
::Port("Graham's Tawny".to_owned()))
256 Meal
::new(noodle(), ramen())
259 fn noodle() -> Noodle
{
260 Noodle
::new("spelt".to_owned(), 100)
263 fn ramen() -> Ramen
{
264 Ramen
::new("Mr Ramen".to_owned(), 72, BrothType
::Miso
)
267 fn napkin() -> Napkin
{
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
<()>
279 RTF
: TReadTransportFactory
+ '
static,
280 IPF
: TInputProtocolFactory
+ '
static,
281 WTF
: TWriteTransportFactory
+ '
static,
282 OPF
: TOutputProtocolFactory
+ '
static,
284 let processor
= recursive
::TestServiceSyncProcessor
::new(RecursiveTestServerHandler {}
);
285 let mut server
= TServer
::new(
294 server
.listen(listen_address
)
297 struct RecursiveTestServerHandler
;
298 impl recursive
::TestServiceSyncHandler
for RecursiveTestServerHandler
{
299 fn handle_echo_tree(&self, tree
: recursive
::RecTree
) -> thrift
::Result
<recursive
::RecTree
> {
300 println
!("{:?}", tree
);
304 fn handle_echo_list(&self, lst
: recursive
::RecList
) -> thrift
::Result
<recursive
::RecList
> {
305 println
!("{:?}", lst
);
309 fn handle_echo_co_rec(&self, item
: recursive
::CoRec
) -> thrift
::Result
<recursive
::CoRec
> {
310 println
!("{:?}", item
);