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 clap::{clap_app, value_t};
19 
20 use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol};
21 use thrift::transport::{
22     ReadHalf, TFramedReadTransport, TFramedWriteTransport, TIoChannel, TTcpChannel, WriteHalf,
23 };
24 
25 use thrift_tutorial::shared::TSharedServiceSyncClient;
26 use thrift_tutorial::tutorial::{CalculatorSyncClient, Operation, TCalculatorSyncClient, Work};
27 
main()28 fn main() {
29     match run() {
30         Ok(()) => println!("tutorial client ran successfully"),
31         Err(e) => {
32             println!("tutorial client failed with error {:?}", e);
33             std::process::exit(1);
34         }
35     }
36 }
37 
run() -> thrift::Result<()>38 fn run() -> thrift::Result<()> {
39     let options = clap_app!(rust_tutorial_client =>
40         (version: "0.1.0")
41         (author: "Apache Thrift Developers <dev@thrift.apache.org>")
42         (about: "Thrift Rust tutorial client")
43         (@arg host: --host +takes_value "host on which the tutorial server listens")
44         (@arg port: --port +takes_value "port on which the tutorial server listens")
45     );
46     let matches = options.get_matches();
47 
48     // get any passed-in args or the defaults
49     let host = matches.value_of("host").unwrap_or("127.0.0.1");
50     let port = value_t!(matches, "port", u16).unwrap_or(9090);
51 
52     // build our client and connect to the host:port
53     let mut client = new_client(host, port)?;
54 
55     // alright!
56     // let's start making some calls
57 
58     // let's start with a ping; the server should respond
59     println!("ping!");
60     client.ping()?;
61 
62     // simple add
63     println!("add");
64     let res = client.add(1, 2)?;
65     println!("added 1, 2 and got {}", res);
66 
67     let logid = 32;
68 
69     // let's do...a multiply!
70     let res = client.calculate(logid, Work::new(7, 8, Operation::Multiply, None))?;
71     println!("multiplied 7 and 8 and got {}", res);
72 
73     // let's get the log for it
74     let res = client.get_struct(logid /* 32 */)?;
75     println!("got log {:?} for operation {}", res, logid);
76 
77     // ok - let's be bad :(
78     // do a divide by 0
79     // logid doesn't matter; won't be recorded
80     let res = client.calculate(77, Work::new(2, 0, Operation::Divide, "we bad".to_owned()));
81 
82     // we should have gotten an exception back
83     match res {
84         Ok(v) => panic!("should not have succeeded with result {}", v),
85         Err(e) => println!("divide by zero failed with error {:?}", e),
86     }
87 
88     // let's do a one-way call
89     println!("zip");
90     client.zip()?;
91 
92     // and then close out with a final ping
93     println!("ping!");
94     client.ping()?;
95 
96     Ok(())
97 }
98 
99 type ClientInputProtocol = TCompactInputProtocol<TFramedReadTransport<ReadHalf<TTcpChannel>>>;
100 type ClientOutputProtocol = TCompactOutputProtocol<TFramedWriteTransport<WriteHalf<TTcpChannel>>>;
101 
new_client( host: &str, port: u16, ) -> thrift::Result<CalculatorSyncClient<ClientInputProtocol, ClientOutputProtocol>>102 fn new_client(
103     host: &str,
104     port: u16,
105 ) -> thrift::Result<CalculatorSyncClient<ClientInputProtocol, ClientOutputProtocol>> {
106     let mut c = TTcpChannel::new();
107 
108     // open the underlying TCP stream
109     println!("connecting to tutorial server on {}:{}", host, port);
110     c.open(&format!("{}:{}", host, port))?;
111 
112     // clone the TCP channel into two halves, one which
113     // we'll use for reading, the other for writing
114     let (i_chan, o_chan) = c.split()?;
115 
116     // wrap the raw sockets (slow) with a buffered transport of some kind
117     let i_tran = TFramedReadTransport::new(i_chan);
118     let o_tran = TFramedWriteTransport::new(o_chan);
119 
120     // now create the protocol implementations
121     let i_prot = TCompactInputProtocol::new(i_tran);
122     let o_prot = TCompactOutputProtocol::new(o_tran);
123 
124     // we're done!
125     Ok(CalculatorSyncClient::new(i_prot, o_prot))
126 }
127