23
23
extern crate unicase;
24
24
extern crate jsonrpc_core as jsonrpc;
25
25
extern crate jsonrpc_server_utils as server_utils;
26
+ extern crate net2;
26
27
27
28
pub extern crate hyper;
28
29
@@ -39,6 +40,7 @@ use std::net::SocketAddr;
39
40
use hyper:: server;
40
41
use jsonrpc:: MetaIoHandler ;
41
42
use jsonrpc:: futures:: { self , Future , IntoFuture , BoxFuture , Stream } ;
43
+ use jsonrpc:: futures:: sync:: oneshot;
42
44
use server_utils:: reactor:: { Remote , UninitializedRemote } ;
43
45
44
46
pub use server_utils:: hosts:: { Host , DomainsValidation } ;
@@ -198,15 +200,18 @@ impl<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>> Clone for Rpc<M, S> {
198
200
}
199
201
}
200
202
203
+ type AllowedHosts = Option < Vec < Host > > ;
204
+ type CorsDomains = Option < Vec < AccessControlAllowOrigin > > ;
201
205
202
206
/// Convenient JSON-RPC HTTP Server builder.
203
207
pub struct ServerBuilder < M : jsonrpc:: Metadata = ( ) , S : jsonrpc:: Middleware < M > = jsonrpc:: NoopMiddleware > {
204
208
handler : Arc < MetaIoHandler < M , S > > ,
205
209
remote : UninitializedRemote ,
206
210
meta_extractor : Arc < MetaExtractor < M > > ,
207
211
request_middleware : Arc < RequestMiddleware > ,
208
- cors_domains : Option < Vec < AccessControlAllowOrigin > > ,
209
- allowed_hosts : Option < Vec < Host > > ,
212
+ cors_domains : CorsDomains ,
213
+ allowed_hosts : AllowedHosts ,
214
+ threads : usize ,
210
215
}
211
216
212
217
const SENDER_PROOF : & ' static str = "Server initialization awaits local address." ;
@@ -230,15 +235,33 @@ impl<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>> ServerBuilder<M, S> {
230
235
request_middleware : Arc :: new ( NoopRequestMiddleware :: default ( ) ) ,
231
236
cors_domains : None ,
232
237
allowed_hosts : None ,
238
+ threads : 1 ,
233
239
}
234
240
}
235
241
236
242
/// Utilize existing event loop remote to poll RPC results.
243
+ /// Applies only to 1 of the threads. Other threads will spawn their own Event Loops.
237
244
pub fn event_loop_remote ( mut self , remote : tokio_core:: reactor:: Remote ) -> Self {
238
245
self . remote = UninitializedRemote :: Shared ( remote) ;
239
246
self
240
247
}
241
248
249
+ /// Sets number of threads of the server to run.
250
+ /// Panics when set to `0`.
251
+ #[ cfg( not( unix) ) ]
252
+ pub fn threads ( mut self , _threads : usize ) -> Self {
253
+ warn ! ( "Multi-threaded server is not available on Windows. Falling back to single thread." ) ;
254
+ self
255
+ }
256
+
257
+ /// Sets number of threads of the server to run.
258
+ /// Panics when set to `0`.
259
+ #[ cfg( unix) ]
260
+ pub fn threads ( mut self , threads : usize ) -> Self {
261
+ self . threads = threads;
262
+ self
263
+ }
264
+
242
265
/// Configures a list of allowed CORS origins.
243
266
pub fn cors ( mut self , cors_domains : DomainsValidation < AccessControlAllowOrigin > ) -> Self {
244
267
self . cors_domains = cors_domains. into ( ) ;
@@ -274,88 +297,160 @@ impl<M: jsonrpc::Metadata, S: jsonrpc::Middleware<M>> ServerBuilder<M, S> {
274
297
let cors_domains = self . cors_domains ;
275
298
let request_middleware = self . request_middleware ;
276
299
let allowed_hosts = self . allowed_hosts ;
277
-
278
- let eloop = self . remote . initialize ( ) ?;
279
300
let jsonrpc_handler = Rpc {
280
301
handler : self . handler ,
281
302
extractor : self . meta_extractor ,
282
303
} ;
304
+ let reuse_port = self . threads > 1 ;
283
305
284
306
let ( local_addr_tx, local_addr_rx) = mpsc:: channel ( ) ;
285
- let ( close, shutdown_signal) = futures:: sync:: oneshot:: channel ( ) ;
286
- let addr = addr. to_owned ( ) ;
287
- // TODO [ToDr] Consider spawning many threads like in minihttp?
288
- eloop. remote ( ) . spawn ( move |handle| {
289
- let handle1 = handle. clone ( ) ;
290
- let bind = move || {
291
- let listener = tokio_core:: net:: TcpListener :: bind ( & addr, & handle1) ?;
292
- // Add current host to allowed headers.
293
- // NOTE: we need to use `l.local_addr()` instead of `addr`
294
- // it might be different!
295
- let local_addr = listener. local_addr ( ) ?;
296
-
297
- Ok ( ( listener, local_addr) )
298
- } ;
299
-
300
- let bind_result = match bind ( ) {
301
- Ok ( ( listener, local_addr) ) => {
302
- // Send local address
303
- local_addr_tx. send ( Ok ( local_addr) ) . expect ( SENDER_PROOF ) ;
304
-
305
- futures:: future:: ok ( ( listener, local_addr) )
306
- } ,
307
- Err ( err) => {
308
- // Send error
309
- local_addr_tx. send ( Err ( err) ) . expect ( SENDER_PROOF ) ;
310
-
311
- futures:: future:: err ( ( ) )
312
- }
313
- } ;
314
-
315
- let handle = handle. clone ( ) ;
316
- bind_result. and_then ( move |( listener, local_addr) | {
317
- let allowed_hosts = server_utils:: hosts:: update ( allowed_hosts, & local_addr) ;
318
-
319
- let http = server:: Http :: new ( ) ;
320
- listener. incoming ( )
321
- . for_each ( move |( socket, addr) | {
322
- http. bind_connection ( & handle, socket, addr, ServerHandler :: new (
323
- jsonrpc_handler. clone ( ) ,
324
- cors_domains. clone ( ) ,
325
- allowed_hosts. clone ( ) ,
326
- request_middleware. clone ( ) ,
327
- ) ) ;
328
- Ok ( ( ) )
329
- } )
330
- . map_err ( |e| {
331
- warn ! ( "Incoming streams error, closing sever: {:?}" , e) ;
332
- } )
333
- . select ( shutdown_signal. map_err ( |e| {
334
- warn ! ( "Shutdown signaller dropped, closing server: {:?}" , e) ;
335
- } ) )
336
- . map ( |_| ( ) )
337
- . map_err ( |_| ( ) )
338
- } )
339
- } ) ;
307
+ let ( close, shutdown_signal) = oneshot:: channel ( ) ;
308
+ let eloop = self . remote . init_with_name ( "http.worker0" ) ?;
309
+ serve (
310
+ ( shutdown_signal, local_addr_tx) ,
311
+ eloop. remote ( ) ,
312
+ addr. to_owned ( ) ,
313
+ cors_domains. clone ( ) ,
314
+ request_middleware. clone ( ) ,
315
+ allowed_hosts. clone ( ) ,
316
+ jsonrpc_handler. clone ( ) ,
317
+ reuse_port,
318
+ ) ;
319
+ let handles = ( 0 ..self . threads - 1 ) . map ( |i| {
320
+ let ( local_addr_tx, local_addr_rx) = mpsc:: channel ( ) ;
321
+ let ( close, shutdown_signal) = oneshot:: channel ( ) ;
322
+ let eloop = UninitializedRemote :: Unspawned . init_with_name ( format ! ( "http.worker{}" , i + 1 ) ) ?;
323
+ serve (
324
+ ( shutdown_signal, local_addr_tx) ,
325
+ eloop. remote ( ) ,
326
+ addr. to_owned ( ) ,
327
+ cors_domains. clone ( ) ,
328
+ request_middleware. clone ( ) ,
329
+ allowed_hosts. clone ( ) ,
330
+ jsonrpc_handler. clone ( ) ,
331
+ reuse_port,
332
+ ) ;
333
+ Ok ( ( eloop, close, local_addr_rx) )
334
+ } ) . collect :: < io:: Result < Vec < _ > > > ( ) ?;
340
335
341
336
// Wait for server initialization
342
- let local_addr: io:: Result < SocketAddr > = local_addr_rx. recv ( ) . map_err ( |_| {
343
- Error :: Io ( io:: Error :: new ( io:: ErrorKind :: Interrupted , "" ) )
344
- } ) ?;
337
+ let local_addr = recv_address ( local_addr_rx) ;
338
+ // Wait for other threads as well.
339
+ let mut handles = handles. into_iter ( ) . map ( |( eloop, close, local_addr_rx) | {
340
+ let _ = recv_address ( local_addr_rx) ?;
341
+ Ok ( ( eloop, close) )
342
+ } ) . collect :: < io:: Result < ( Vec < _ > ) > > ( ) ?;
343
+ handles. push ( ( eloop, close) ) ;
344
+ let ( remotes, close) = handles. into_iter ( ) . unzip ( ) ;
345
345
346
346
Ok ( Server {
347
347
address : local_addr?,
348
- remote : Some ( eloop ) ,
348
+ remote : Some ( remotes ) ,
349
349
close : Some ( close) ,
350
350
} )
351
351
}
352
352
}
353
353
354
+ fn recv_address ( local_addr_rx : mpsc:: Receiver < io:: Result < SocketAddr > > ) -> io:: Result < SocketAddr > {
355
+ local_addr_rx. recv ( ) . map_err ( |_| {
356
+ io:: Error :: new ( io:: ErrorKind :: Interrupted , "" )
357
+ } ) ?
358
+ }
359
+
360
+ fn serve < M : jsonrpc:: Metadata , S : jsonrpc:: Middleware < M > > (
361
+ signals : ( oneshot:: Receiver < ( ) > , mpsc:: Sender < io:: Result < SocketAddr > > ) ,
362
+ remote : tokio_core:: reactor:: Remote ,
363
+ addr : SocketAddr ,
364
+ cors_domains : CorsDomains ,
365
+ request_middleware : Arc < RequestMiddleware > ,
366
+ allowed_hosts : AllowedHosts ,
367
+ jsonrpc_handler : Rpc < M , S > ,
368
+ reuse_port : bool ,
369
+ ) {
370
+ let ( shutdown_signal, local_addr_tx) = signals;
371
+ remote. spawn ( move |handle| {
372
+ let handle1 = handle. clone ( ) ;
373
+ let bind = move || {
374
+ let listener = match addr {
375
+ SocketAddr :: V4 ( _) => net2:: TcpBuilder :: new_v4 ( ) ?,
376
+ SocketAddr :: V6 ( _) => net2:: TcpBuilder :: new_v6 ( ) ?,
377
+ } ;
378
+ configure_port ( reuse_port, & listener) ?;
379
+ listener. reuse_address ( true ) ?;
380
+ listener. bind ( & addr) ?;
381
+ let listener = listener. listen ( 1024 ) ?;
382
+ let listener = tokio_core:: net:: TcpListener :: from_listener ( listener, & addr, & handle1) ?;
383
+ // Add current host to allowed headers.
384
+ // NOTE: we need to use `l.local_addr()` instead of `addr`
385
+ // it might be different!
386
+ let local_addr = listener. local_addr ( ) ?;
387
+
388
+ Ok ( ( listener, local_addr) )
389
+ } ;
390
+
391
+ let bind_result = match bind ( ) {
392
+ Ok ( ( listener, local_addr) ) => {
393
+ // Send local address
394
+ local_addr_tx. send ( Ok ( local_addr) ) . expect ( SENDER_PROOF ) ;
395
+
396
+ futures:: future:: ok ( ( listener, local_addr) )
397
+ } ,
398
+ Err ( err) => {
399
+ // Send error
400
+ local_addr_tx. send ( Err ( err) ) . expect ( SENDER_PROOF ) ;
401
+
402
+ futures:: future:: err ( ( ) )
403
+ }
404
+ } ;
405
+
406
+ let handle = handle. clone ( ) ;
407
+ bind_result. and_then ( move |( listener, local_addr) | {
408
+ let allowed_hosts = server_utils:: hosts:: update ( allowed_hosts, & local_addr) ;
409
+
410
+ let http = server:: Http :: new ( ) ;
411
+ listener. incoming ( )
412
+ . for_each ( move |( socket, addr) | {
413
+ http. bind_connection ( & handle, socket, addr, ServerHandler :: new (
414
+ jsonrpc_handler. clone ( ) ,
415
+ cors_domains. clone ( ) ,
416
+ allowed_hosts. clone ( ) ,
417
+ request_middleware. clone ( ) ,
418
+ ) ) ;
419
+ Ok ( ( ) )
420
+ } )
421
+ . map_err ( |e| {
422
+ warn ! ( "Incoming streams error, closing sever: {:?}" , e) ;
423
+ } )
424
+ . select ( shutdown_signal. map_err ( |e| {
425
+ warn ! ( "Shutdown signaller dropped, closing server: {:?}" , e) ;
426
+ } ) )
427
+ . map ( |_| ( ) )
428
+ . map_err ( |_| ( ) )
429
+ } )
430
+ } ) ;
431
+ }
432
+
433
+ #[ cfg( unix) ]
434
+ fn configure_port ( reuse : bool , tcp : & net2:: TcpBuilder ) -> io:: Result < ( ) > {
435
+ use net2:: unix:: * ;
436
+
437
+ if reuse {
438
+ try!( tcp. reuse_port ( true ) ) ;
439
+ }
440
+
441
+ Ok ( ( ) )
442
+ }
443
+
444
+ #[ cfg( not( unix) ) ]
445
+ fn configure_port ( _reuse : bool , _tcp : & net2:: TcpBuilder ) -> io:: Result < ( ) > {
446
+ Ok ( ( ) )
447
+ }
448
+
354
449
/// jsonrpc http server instance
355
450
pub struct Server {
356
451
address : SocketAddr ,
357
- remote : Option < Remote > ,
358
- close : Option < futures :: sync :: oneshot:: Sender < ( ) > > ,
452
+ remote : Option < Vec < Remote > > ,
453
+ close : Option < Vec < oneshot:: Sender < ( ) > > > ,
359
454
}
360
455
361
456
const PROOF : & ' static str = "Server is always Some until self is consumed." ;
@@ -367,19 +462,28 @@ impl Server {
367
462
368
463
/// Closes the server.
369
464
pub fn close ( mut self ) {
370
- let _ = self . close . take ( ) . expect ( PROOF ) . send ( ( ) ) ;
371
- self . remote . take ( ) . expect ( PROOF ) . close ( ) ;
465
+ for close in self . close . take ( ) . expect ( PROOF ) {
466
+ let _ = close. send ( ( ) ) ;
467
+ }
468
+
469
+ for remote in self . remote . take ( ) . expect ( PROOF ) {
470
+ remote. close ( ) ;
471
+ }
372
472
}
373
473
374
474
/// Will block, waiting for the server to finish.
375
475
pub fn wait ( mut self ) {
376
- self . remote . take ( ) . expect ( PROOF ) . wait ( ) ;
476
+ for remote in self . remote . take ( ) . expect ( PROOF ) {
477
+ remote. wait ( ) ;
478
+ }
377
479
}
378
480
}
379
481
380
482
impl Drop for Server {
381
483
fn drop ( & mut self ) {
382
- self . remote . take ( ) . map ( |remote| remote. close ( ) ) ;
484
+ self . remote . take ( ) . map ( |remotes| {
485
+ for remote in remotes { remote. close ( ) ; }
486
+ } ) ;
383
487
}
384
488
}
385
489
0 commit comments