@@ -29,7 +29,7 @@ use std::thread;
29
29
use tokio:: prelude:: * ;
30
30
use futures:: sync:: mpsc;
31
31
32
- fn main ( ) {
32
+ fn main ( ) -> Result < ( ) , Box < std :: error :: Error > > {
33
33
// Determine if we're going to run in TCP or UDP mode
34
34
let mut args = env:: args ( ) . skip ( 1 ) . collect :: < Vec < _ > > ( ) ;
35
35
let tcp = match args. iter ( ) . position ( |a| a == "--udp" ) {
@@ -41,26 +41,27 @@ fn main() {
41
41
} ;
42
42
43
43
// Parse what address we're going to connect to
44
- let addr = args. first ( ) . unwrap_or_else ( || {
45
- panic ! ( "this program requires at least one argument" )
46
- } ) ;
47
- let addr = addr. parse :: < SocketAddr > ( ) . unwrap ( ) ;
44
+ let addr = match args. first ( ) {
45
+ Some ( addr) => addr,
46
+ None => Err ( "this program requires at least one argument" ) ?,
47
+ } ;
48
+ let addr = addr. parse :: < SocketAddr > ( ) ?;
48
49
49
50
// Right now Tokio doesn't support a handle to stdin running on the event
50
51
// loop, so we farm out that work to a separate thread. This thread will
51
52
// read data (with blocking I/O) from stdin and then send it to the event
52
53
// loop over a standard futures channel.
53
54
let ( stdin_tx, stdin_rx) = mpsc:: channel ( 0 ) ;
54
55
thread:: spawn ( || read_stdin ( stdin_tx) ) ;
55
- let stdin_rx = stdin_rx. map_err ( |_| panic ! ( ) ) ; // errors not possible on rx
56
+ let stdin_rx = stdin_rx. map_err ( |_| panic ! ( " errors not possible on rx" ) ) ;
56
57
57
58
// Now that we've got our stdin read we either set up our TCP connection or
58
59
// our UDP connection to get a stream of bytes we're going to emit to
59
60
// stdout.
60
61
let stdout = if tcp {
61
- tcp:: connect ( & addr, Box :: new ( stdin_rx) )
62
+ tcp:: connect ( & addr, Box :: new ( stdin_rx) ) ?
62
63
} else {
63
- udp:: connect ( & addr, Box :: new ( stdin_rx) )
64
+ udp:: connect ( & addr, Box :: new ( stdin_rx) ) ?
64
65
} ;
65
66
66
67
// And now with our stream of bytes to write to stdout, we execute that in
@@ -77,6 +78,7 @@ fn main() {
77
78
} )
78
79
. map_err ( |e| println ! ( "error reading stdout; error = {:?}" , e) )
79
80
} ) ;
81
+ Ok ( ( ) )
80
82
}
81
83
82
84
mod codec {
@@ -127,12 +129,13 @@ mod tcp {
127
129
use bytes:: BytesMut ;
128
130
use codec:: Bytes ;
129
131
132
+ use std:: error:: Error ;
130
133
use std:: io;
131
134
use std:: net:: SocketAddr ;
132
135
133
136
pub fn connect ( addr : & SocketAddr ,
134
137
stdin : Box < Stream < Item = Vec < u8 > , Error = io:: Error > + Send > )
135
- -> Box < Stream < Item = BytesMut , Error = io:: Error > + Send >
138
+ -> Result < Box < Stream < Item = BytesMut , Error = io:: Error > + Send > , Box < Error > >
136
139
{
137
140
let tcp = TcpStream :: connect ( addr) ;
138
141
@@ -151,22 +154,24 @@ mod tcp {
151
154
// You'll also note that we *spawn* the work to read stdin and write it
152
155
// to the TCP stream. This is done to ensure that happens concurrently
153
156
// with us reading data from the stream.
154
- Box :: new ( tcp. map ( move |stream| {
157
+ let stream = Box :: new ( tcp. map ( move |stream| {
155
158
let ( sink, stream) = Bytes . framed ( stream) . split ( ) ;
156
159
157
160
tokio:: spawn ( stdin. forward ( sink) . then ( |result| {
158
161
if let Err ( e) = result {
159
- panic ! ( "failed to write to socket: {}" , e)
162
+ println ! ( "failed to write to socket: {}" , e)
160
163
}
161
164
Ok ( ( ) )
162
165
} ) ) ;
163
166
164
167
stream
165
- } ) . flatten_stream ( ) )
168
+ } ) . flatten_stream ( ) ) ;
169
+ Ok ( stream)
166
170
}
167
171
}
168
172
169
173
mod udp {
174
+ use std:: error:: Error ;
170
175
use std:: io;
171
176
use std:: net:: SocketAddr ;
172
177
@@ -179,17 +184,19 @@ mod udp {
179
184
180
185
pub fn connect ( & addr: & SocketAddr ,
181
186
stdin : Box < Stream < Item = Vec < u8 > , Error = io:: Error > + Send > )
182
- -> Box < Stream < Item = BytesMut , Error = io:: Error > + Send >
187
+ -> Result < Box < Stream < Item = BytesMut , Error = io:: Error > + Send > , Box < Error > >
183
188
{
184
189
// We'll bind our UDP socket to a local IP/port, but for now we
185
190
// basically let the OS pick both of those.
186
191
let addr_to_bind = if addr. ip ( ) . is_ipv4 ( ) {
187
- "0.0.0.0:0" . parse ( ) . unwrap ( )
192
+ "0.0.0.0:0" . parse ( ) ?
188
193
} else {
189
- "[::]:0" . parse ( ) . unwrap ( )
194
+ "[::]:0" . parse ( ) ?
195
+ } ;
196
+ let udp = match UdpSocket :: bind ( & addr_to_bind) {
197
+ Ok ( udp) => udp,
198
+ Err ( _) => Err ( "failed to bind socket" ) ?,
190
199
} ;
191
- let udp = UdpSocket :: bind ( & addr_to_bind)
192
- . expect ( "failed to bind socket" ) ;
193
200
194
201
// Like above with TCP we use an instance of `Bytes` codec to transform
195
202
// this UDP socket into a framed sink/stream which operates over
@@ -203,7 +210,7 @@ mod udp {
203
210
( chunk, addr)
204
211
} ) . forward ( sink) . then ( |result| {
205
212
if let Err ( e) = result {
206
- panic ! ( "failed to write to socket: {}" , e)
213
+ println ! ( "failed to write to socket: {}" , e)
207
214
}
208
215
Ok ( ( ) )
209
216
} ) ;
@@ -218,10 +225,11 @@ mod udp {
218
225
}
219
226
} ) ;
220
227
221
- Box :: new ( future:: lazy ( || {
228
+ let stream = Box :: new ( future:: lazy ( || {
222
229
tokio:: spawn ( forward_stdin) ;
223
230
future:: ok ( receive)
224
- } ) . flatten_stream ( ) )
231
+ } ) . flatten_stream ( ) ) ;
232
+ Ok ( stream)
225
233
}
226
234
}
227
235
0 commit comments