Use hyper 0.11 in ethcore-miner and improvements in parity-reactor (#8335)
* parity-reactor: Pass over Handle in spawning fn to allow normal tokio ops * Allow fetch to work with arbitrary requests * typo: Fix missing handler closure * miner, work_notify: use fetch and parity-reactor * Fix work_notify pushing in parity CLI
This commit is contained in:
parent
86446d713a
commit
692cd10d4a
72
Cargo.lock
generated
72
Cargo.lock
generated
@ -250,15 +250,6 @@ dependencies = [
|
||||
"custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.3.2"
|
||||
@ -660,16 +651,19 @@ dependencies = [
|
||||
"ethcore-transaction 0.1.0",
|
||||
"ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethkey 0.3.0",
|
||||
"fetch 0.1.0",
|
||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)",
|
||||
"hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"keccak-hash 0.1.0",
|
||||
"linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-reactor 0.1.0",
|
||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"table 0.1.0",
|
||||
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -753,6 +747,7 @@ dependencies = [
|
||||
"serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1041,6 +1036,7 @@ dependencies = [
|
||||
name = "fetch"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1204,25 +1200,6 @@ name = "httparse"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.10.0-a.0"
|
||||
source = "git+https://github.com/paritytech/hyper#da10f69a4924cd44e98a8d1f9562bd7534d13dcc"
|
||||
dependencies = [
|
||||
"cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rotor 0.6.3 (git+https://github.com/tailhook/rotor)",
|
||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spmc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.10.13"
|
||||
@ -2634,11 +2611,6 @@ dependencies = [
|
||||
"quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.5.1"
|
||||
@ -2807,18 +2779,6 @@ dependencies = [
|
||||
"snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rotor"
|
||||
version = "0.6.3"
|
||||
source = "git+https://github.com/tailhook/rotor#80ce2e4cd82fdc7f88bb2d737407fa5106799790"
|
||||
dependencies = [
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rpassword"
|
||||
version = "1.0.2"
|
||||
@ -3054,11 +3014,6 @@ dependencies = [
|
||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spmc"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.0.0"
|
||||
@ -3612,15 +3567,6 @@ name = "vec_map"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vecio"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vergen"
|
||||
version = "0.1.1"
|
||||
@ -3831,7 +3777,6 @@ dependencies = [
|
||||
"checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6"
|
||||
"checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2"
|
||||
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
|
||||
"checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591"
|
||||
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
|
||||
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
|
||||
"checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2"
|
||||
@ -3878,7 +3823,6 @@ dependencies = [
|
||||
"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
|
||||
"checksum hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)" = "<none>"
|
||||
"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
|
||||
"checksum hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)" = "<none>"
|
||||
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
|
||||
"checksum hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)" = "df4dd5dae401458087396b6db7fabc4d6760aa456a5fa8e92bda549f39cae661"
|
||||
"checksum hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6cdc1751771a14b8175764394f025e309a28c825ed9eaf97fa62bb831dc8c5"
|
||||
@ -3973,7 +3917,6 @@ dependencies = [
|
||||
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
|
||||
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
|
||||
"checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd"
|
||||
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
|
||||
"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
|
||||
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
|
||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||
@ -3988,7 +3931,6 @@ dependencies = [
|
||||
"checksum ring 0.12.1 (git+https://github.com/paritytech/ring)" = "<none>"
|
||||
"checksum rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)" = "<none>"
|
||||
"checksum rocksdb-sys 0.3.0 (git+https://github.com/paritytech/rust-rocksdb)" = "<none>"
|
||||
"checksum rotor 0.6.3 (git+https://github.com/tailhook/rotor)" = "<none>"
|
||||
"checksum rpassword 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b273c91bd242ca03ad6d71c143b6f17a48790e61f21a6c78568fa2b6774a24a4"
|
||||
"checksum rprompt 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1601f32bc5858aae3cbfa1c645c96c4d820cc5c16be0194f089560c00b6eb625"
|
||||
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
||||
@ -4020,7 +3962,6 @@ dependencies = [
|
||||
"checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d"
|
||||
"checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>"
|
||||
"checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>"
|
||||
"checksum spmc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cd1f11d1fb5fd41834e55ce0b85a186efbf2f2afd9fdb09e2c8d72f9bff1ad1a"
|
||||
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||
"checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb"
|
||||
@ -4075,7 +4016,6 @@ dependencies = [
|
||||
"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
|
||||
"checksum vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0795a11576d29ae80525a3fda315bf7b534f8feb9d34101e5fe63fb95bb2fd24"
|
||||
"checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d"
|
||||
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
@ -53,7 +53,7 @@ impl NodeHealth {
|
||||
let tx = Arc::new(Mutex::new(Some(tx)));
|
||||
let tx2 = tx.clone();
|
||||
self.remote.spawn_with_timeout(
|
||||
move || time.then(move |result| {
|
||||
move |_| time.then(move |result| {
|
||||
let _ = tx.lock().take().expect(PROOF).send(Ok(result));
|
||||
Ok(())
|
||||
}),
|
||||
|
@ -19,8 +19,8 @@ use std::sync::{atomic, mpsc, Arc};
|
||||
use parking_lot::Mutex;
|
||||
use hyper;
|
||||
|
||||
use futures::{self, Future};
|
||||
use fetch::{self, Fetch, Url, Method};
|
||||
use futures::{self, future, Future};
|
||||
use fetch::{self, Fetch, Url, Request, Abort};
|
||||
|
||||
pub struct FetchControl {
|
||||
sender: mpsc::Sender<()>,
|
||||
@ -97,9 +97,9 @@ impl FakeFetch {
|
||||
impl Fetch for FakeFetch {
|
||||
type Result = Box<Future<Item = fetch::Response, Error = fetch::Error> + Send>;
|
||||
|
||||
fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result {
|
||||
let u = Url::parse(url).unwrap();
|
||||
self.requested.lock().push(url.into());
|
||||
fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result {
|
||||
let u = request.url().clone();
|
||||
self.requested.lock().push(u.as_str().into());
|
||||
let manual = self.manual.clone();
|
||||
let response = self.response.clone();
|
||||
|
||||
@ -115,4 +115,20 @@ impl Fetch for FakeFetch {
|
||||
|
||||
Box::new(rx.map_err(|_| fetch::Error::Aborted))
|
||||
}
|
||||
|
||||
fn get(&self, url: &str, abort: Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
|
||||
fn post(&self, url: &str, abort: Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
||||
}
|
||||
|
@ -34,3 +34,4 @@ serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
tiny-keccak = "1.3"
|
||||
url = "1"
|
||||
|
@ -17,6 +17,7 @@
|
||||
//! Encryption providers.
|
||||
|
||||
use std::io::Read;
|
||||
use std::str::FromStr;
|
||||
use std::iter::repeat;
|
||||
use std::time::{Instant, Duration};
|
||||
use std::collections::HashMap;
|
||||
@ -28,9 +29,10 @@ use ethjson;
|
||||
use ethkey::{Signature, Public};
|
||||
use ethcrypto;
|
||||
use futures::Future;
|
||||
use fetch::{Fetch, Client as FetchClient, Method, BodyReader};
|
||||
use fetch::{Fetch, Client as FetchClient, Method, BodyReader, Request};
|
||||
use bytes::{Bytes, ToPretty};
|
||||
use error::{Error, ErrorKind};
|
||||
use url::Url;
|
||||
use super::find_account_password;
|
||||
|
||||
/// Initialization vector length.
|
||||
@ -128,7 +130,8 @@ impl SecretStoreEncryptor {
|
||||
Method::Get
|
||||
};
|
||||
|
||||
let response = self.client.fetch(&url, method, Default::default()).wait()
|
||||
let url = Url::from_str(&url).map_err(|e| ErrorKind::Encrypt(e.to_string()))?;
|
||||
let response = self.client.fetch(Request::new(url, method), Default::default()).wait()
|
||||
.map_err(|e| ErrorKind::Encrypt(e.to_string()))?;
|
||||
|
||||
if response.is_not_found() {
|
||||
|
@ -41,6 +41,7 @@ extern crate keccak_hash as hash;
|
||||
extern crate parking_lot;
|
||||
extern crate patricia_trie as trie;
|
||||
extern crate rlp;
|
||||
extern crate url;
|
||||
extern crate rustc_hex;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
@ -673,4 +674,3 @@ impl ChainNotify for Provider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ use ethcore_miner::transaction_queue::{
|
||||
TransactionOrigin,
|
||||
};
|
||||
use futures_cpupool::CpuPool;
|
||||
use ethcore_miner::work_notify::{WorkPoster, NotifyWork};
|
||||
use ethcore_miner::work_notify::NotifyWork;
|
||||
use miner::service_transaction_checker::ServiceTransactionChecker;
|
||||
use miner::{MinerService, MinerStatus};
|
||||
use price_info::fetch::Client as FetchClient;
|
||||
@ -104,8 +104,6 @@ pub enum Banning {
|
||||
/// Configures the behaviour of the miner.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct MinerOptions {
|
||||
/// URLs to notify when there is new work.
|
||||
pub new_work_notify: Vec<String>,
|
||||
/// Force the miner to reseal, even when nobody has asked for work.
|
||||
pub force_sealing: bool,
|
||||
/// Reseal on receipt of new external transactions.
|
||||
@ -147,7 +145,6 @@ pub struct MinerOptions {
|
||||
impl Default for MinerOptions {
|
||||
fn default() -> Self {
|
||||
MinerOptions {
|
||||
new_work_notify: vec![],
|
||||
force_sealing: false,
|
||||
reseal_on_external_tx: false,
|
||||
reseal_on_own_tx: true,
|
||||
@ -305,10 +302,7 @@ impl Miner {
|
||||
),
|
||||
};
|
||||
|
||||
let notifiers: Vec<Box<NotifyWork>> = match options.new_work_notify.is_empty() {
|
||||
true => Vec::new(),
|
||||
false => vec![Box::new(WorkPoster::new(&options.new_work_notify))],
|
||||
};
|
||||
let notifiers: Vec<Box<NotifyWork>> = Vec::new();
|
||||
|
||||
let service_transaction_action = match options.refuse_service_transactions {
|
||||
true => ServiceTransactionAction::Refuse,
|
||||
@ -324,7 +318,6 @@ impl Miner {
|
||||
sealing_work: Mutex::new(SealingWork{
|
||||
queue: UsingQueue::new(options.work_queue_size),
|
||||
enabled: options.force_sealing
|
||||
|| !options.new_work_notify.is_empty()
|
||||
|| spec.engine.seals_internally().is_some()
|
||||
}),
|
||||
gas_range_target: RwLock::new((U256::zero(), U256::zero())),
|
||||
@ -1364,7 +1357,6 @@ mod tests {
|
||||
fn miner() -> Miner {
|
||||
Arc::try_unwrap(Miner::new(
|
||||
MinerOptions {
|
||||
new_work_notify: Vec::new(),
|
||||
force_sealing: false,
|
||||
reseal_on_external_tx: false,
|
||||
reseal_on_own_tx: true,
|
||||
|
@ -199,7 +199,7 @@ mod tests {
|
||||
use parking_lot::Mutex;
|
||||
use futures::future;
|
||||
use futures_cpupool::CpuPool;
|
||||
use fetch::{self, Fetch, Url, Method};
|
||||
use fetch::{self, Fetch, Url, Request};
|
||||
use parity_reactor::Remote;
|
||||
use urlhint::tests::{FakeRegistrar, URLHINT};
|
||||
use super::{Error, Client, HashFetch, random_temp_path};
|
||||
@ -214,15 +214,31 @@ mod tests {
|
||||
impl Fetch for FakeFetch {
|
||||
type Result = future::Ok<fetch::Response, fetch::Error>;
|
||||
|
||||
fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result {
|
||||
assert_eq!(url, "https://parity.io/assets/images/ethcore-black-horizontal.png");
|
||||
let u = Url::parse(url).unwrap();
|
||||
fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result {
|
||||
assert_eq!(request.url().as_str(), "https://parity.io/assets/images/ethcore-black-horizontal.png");
|
||||
let u = request.url().clone();
|
||||
future::ok(if self.return_success {
|
||||
fetch::client::Response::new(u, hyper::Response::new().with_body(&b"result"[..]), abort)
|
||||
} else {
|
||||
fetch::client::Response::new(u, hyper::Response::new().with_status(StatusCode::NotFound), abort)
|
||||
})
|
||||
}
|
||||
|
||||
fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
|
||||
fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
||||
}
|
||||
|
||||
fn registrar() -> FakeRegistrar {
|
||||
@ -311,4 +327,3 @@ mod tests {
|
||||
assert!(result.is_ok(), "Should return path, got: {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,6 @@ version = "1.11.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
# TODO [ToDr] Rewrite using reqwest
|
||||
hyper = { git = "https://github.com/paritytech/hyper", default-features = false }
|
||||
|
||||
common-types = { path = "../ethcore/types" }
|
||||
ethabi = "5.1"
|
||||
ethabi-contract = "5.0"
|
||||
@ -27,3 +24,7 @@ parking_lot = "0.5"
|
||||
rustc-hex = "1.0"
|
||||
table = { path = "../util/table" }
|
||||
transient-hashmap = "0.4"
|
||||
fetch = { path = "../util/fetch" }
|
||||
parity-reactor = { path = "../util/reactor" }
|
||||
url = "1"
|
||||
hyper = "0.11"
|
||||
|
@ -17,19 +17,20 @@
|
||||
//! Sends HTTP notifications to a list of URLs every time new work is available.
|
||||
|
||||
extern crate ethash;
|
||||
extern crate fetch;
|
||||
extern crate parity_reactor;
|
||||
extern crate url;
|
||||
extern crate hyper;
|
||||
|
||||
use self::hyper::header::ContentType;
|
||||
use self::hyper::method::Method;
|
||||
use self::hyper::client::{Request, Response, Client};
|
||||
use self::hyper::{Next, Url};
|
||||
use self::hyper::net::HttpStream;
|
||||
|
||||
use self::fetch::{Fetch, Request, Client as FetchClient, Method};
|
||||
use self::parity_reactor::Remote;
|
||||
use self::ethash::SeedHashCompute;
|
||||
use self::url::Url;
|
||||
use self::hyper::header::ContentType;
|
||||
|
||||
use std::io::Write;
|
||||
use ethereum_types::{H256, U256};
|
||||
use parking_lot::Mutex;
|
||||
use futures::Future;
|
||||
|
||||
/// Trait for notifying about new mining work
|
||||
pub trait NotifyWork : Send + Sync {
|
||||
@ -40,13 +41,14 @@ pub trait NotifyWork : Send + Sync {
|
||||
/// POSTs info about new work to given urls.
|
||||
pub struct WorkPoster {
|
||||
urls: Vec<Url>,
|
||||
client: Mutex<Client<PostHandler>>,
|
||||
client: FetchClient,
|
||||
remote: Remote,
|
||||
seed_compute: Mutex<SeedHashCompute>,
|
||||
}
|
||||
|
||||
impl WorkPoster {
|
||||
/// Create new `WorkPoster`.
|
||||
pub fn new(urls: &[String]) -> Self {
|
||||
pub fn new(urls: &[String], fetch: FetchClient, remote: Remote) -> Self {
|
||||
let urls = urls.into_iter().filter_map(|u| {
|
||||
match Url::parse(u) {
|
||||
Ok(url) => Some(url),
|
||||
@ -56,20 +58,13 @@ impl WorkPoster {
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
let client = WorkPoster::create_client();
|
||||
WorkPoster {
|
||||
client: Mutex::new(client),
|
||||
client: fetch,
|
||||
remote: remote,
|
||||
urls: urls,
|
||||
seed_compute: Mutex::new(SeedHashCompute::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_client() -> Client<PostHandler> {
|
||||
Client::<PostHandler>::configure()
|
||||
.keep_alive(true)
|
||||
.build()
|
||||
.expect("Error creating HTTP client")
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`.
|
||||
@ -91,51 +86,16 @@ impl NotifyWork for WorkPoster {
|
||||
r#"{{ "result": ["0x{:x}","0x{:x}","0x{:x}","0x{:x}"] }}"#,
|
||||
pow_hash, seed_hash, target, number
|
||||
);
|
||||
let mut client = self.client.lock();
|
||||
|
||||
for u in &self.urls {
|
||||
if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) {
|
||||
let u = u.clone();
|
||||
self.remote.spawn(self.client.fetch(
|
||||
Request::new(u.clone(), Method::Post)
|
||||
.with_header(ContentType::json())
|
||||
.with_body(body.clone()), Default::default()
|
||||
).map_err(move |e| {
|
||||
warn!("Error sending HTTP notification to {} : {}, retrying", u, e);
|
||||
// TODO: remove this once https://github.com/hyperium/hyper/issues/848 is fixed
|
||||
*client = WorkPoster::create_client();
|
||||
if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) {
|
||||
warn!("Error sending HTTP notification to {} : {}", u, e);
|
||||
}
|
||||
}
|
||||
}).map(|_| ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PostHandler {
|
||||
body: String,
|
||||
}
|
||||
|
||||
impl hyper::client::Handler<HttpStream> for PostHandler {
|
||||
fn on_request(&mut self, request: &mut Request) -> Next {
|
||||
request.set_method(Method::Post);
|
||||
request.headers_mut().set(ContentType::json());
|
||||
Next::write()
|
||||
}
|
||||
|
||||
fn on_request_writable(&mut self, encoder: &mut hyper::Encoder<HttpStream>) -> Next {
|
||||
if let Err(e) = encoder.write_all(self.body.as_bytes()) {
|
||||
trace!("Error posting work data: {}", e);
|
||||
}
|
||||
encoder.close();
|
||||
Next::read()
|
||||
|
||||
}
|
||||
|
||||
fn on_response(&mut self, _response: Response) -> Next {
|
||||
Next::end()
|
||||
}
|
||||
|
||||
fn on_response_readable(&mut self, _decoder: &mut hyper::Decoder<HttpStream>) -> Next {
|
||||
Next::end()
|
||||
}
|
||||
|
||||
fn on_error(&mut self, err: hyper::Error) -> Next {
|
||||
trace!("Error posting work data: {}", err);
|
||||
Next::end()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,6 +354,7 @@ impl Configuration {
|
||||
daemon: daemon,
|
||||
logger_config: logger_config.clone(),
|
||||
miner_options: self.miner_options()?,
|
||||
work_notify: self.work_notify(),
|
||||
gas_price_percentile: self.args.arg_gas_price_percentile,
|
||||
ntp_servers: self.ntp_servers(),
|
||||
ws_conf: ws_conf,
|
||||
@ -537,7 +538,6 @@ impl Configuration {
|
||||
let reseal = self.args.arg_reseal_on_txs.parse::<ResealPolicy>()?;
|
||||
|
||||
let options = MinerOptions {
|
||||
new_work_notify: self.work_notify(),
|
||||
force_sealing: self.args.flag_force_sealing,
|
||||
reseal_on_external_tx: reseal.external,
|
||||
reseal_on_own_tx: reseal.own,
|
||||
@ -1516,6 +1516,7 @@ mod tests {
|
||||
no_hardcoded_sync: false,
|
||||
no_persistent_txqueue: false,
|
||||
whisper: Default::default(),
|
||||
work_notify: Vec::new(),
|
||||
};
|
||||
expected.secretstore_conf.enabled = cfg!(feature = "secretstore");
|
||||
expected.secretstore_conf.http_enabled = cfg!(feature = "secretstore");
|
||||
|
@ -70,7 +70,7 @@ impl<T: LightChainClient + 'static> IoHandler<ClientIoMessage> for QueueCull<T>
|
||||
let start_nonce = self.client.engine().account_start_nonce(best_header.number());
|
||||
|
||||
info!(target: "cull", "Attempting to cull queued transactions from {} senders.", senders.len());
|
||||
self.remote.spawn_with_timeout(move || {
|
||||
self.remote.spawn_with_timeout(move |_| {
|
||||
let maybe_fetching = sync.with_context(move |ctx| {
|
||||
// fetch the nonce of each sender in the queue.
|
||||
let nonce_reqs = senders.iter()
|
||||
|
@ -35,6 +35,7 @@ use ethcore::verification::queue::VerifierSettings;
|
||||
use ethcore_logger::{Config as LogConfig, RotatingLogger};
|
||||
use ethcore_service::ClientService;
|
||||
use sync::{self, SyncConfig};
|
||||
use miner::work_notify::WorkPoster;
|
||||
use fdlimit::raise_fd_limit;
|
||||
use futures_cpupool::CpuPool;
|
||||
use hash_fetch::{self, fetch};
|
||||
@ -137,6 +138,7 @@ pub struct RunCmd {
|
||||
pub no_persistent_txqueue: bool,
|
||||
pub whisper: ::whisper::Config,
|
||||
pub no_hardcoded_sync: bool,
|
||||
pub work_notify: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> {
|
||||
@ -549,6 +551,9 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
|
||||
let cpu_pool = CpuPool::new(4);
|
||||
|
||||
// spin up event loop
|
||||
let event_loop = EventLoop::spawn();
|
||||
|
||||
// fetch service
|
||||
let fetch = fetch::Client::new().map_err(|e| format!("Error starting fetch client: {:?}", e))?;
|
||||
|
||||
@ -561,6 +566,9 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
miner.set_extra_data(cmd.miner_extras.extra_data);
|
||||
miner.set_minimal_gas_price(initial_min_gas_price);
|
||||
miner.recalibrate_minimal_gas_price();
|
||||
if !cmd.work_notify.is_empty() {
|
||||
miner.push_notifier(Box::new(WorkPoster::new(&cmd.work_notify, fetch.clone(), event_loop.remote())));
|
||||
}
|
||||
let engine_signer = cmd.miner_extras.engine_signer;
|
||||
|
||||
if engine_signer != Default::default() {
|
||||
@ -730,9 +738,6 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
chain_notify.start();
|
||||
}
|
||||
|
||||
// spin up event loop
|
||||
let event_loop = EventLoop::spawn();
|
||||
|
||||
let contract_client = Arc::new(::dapps::FullRegistrar::new(client.clone()));
|
||||
|
||||
// the updater service
|
||||
|
@ -140,7 +140,7 @@ mod test {
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use fetch;
|
||||
use fetch::{Fetch, Url, Method};
|
||||
use fetch::{Fetch, Url, Request};
|
||||
use futures_cpupool::CpuPool;
|
||||
use futures::future::{self, FutureResult};
|
||||
use Client;
|
||||
@ -158,9 +158,9 @@ mod test {
|
||||
impl Fetch for FakeFetch {
|
||||
type Result = FutureResult<fetch::Response, fetch::Error>;
|
||||
|
||||
fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result {
|
||||
assert_eq!(url, "https://api.etherscan.io/api?module=stats&action=ethprice");
|
||||
let u = Url::parse(url).unwrap();
|
||||
fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result {
|
||||
assert_eq!(request.url().as_str(), "https://api.etherscan.io/api?module=stats&action=ethprice");
|
||||
let u = request.url().clone();
|
||||
let mut val = self.1.lock();
|
||||
*val = *val + 1;
|
||||
if let Some(ref response) = self.0 {
|
||||
@ -171,6 +171,22 @@ mod test {
|
||||
future::ok(fetch::client::Response::new(u, r, abort))
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
|
||||
fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
||||
}
|
||||
|
||||
fn price_info_ok(response: &str) -> Client<FakeFetch> {
|
||||
|
@ -60,7 +60,6 @@ fn sync_provider() -> Arc<TestSyncProvider> {
|
||||
fn miner_service(spec: &Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> {
|
||||
Miner::new(
|
||||
MinerOptions {
|
||||
new_work_notify: vec![],
|
||||
force_sealing: true,
|
||||
reseal_on_external_tx: true,
|
||||
reseal_on_own_tx: true,
|
||||
|
@ -17,8 +17,10 @@
|
||||
//! Test implementation of fetch client.
|
||||
|
||||
use std::thread;
|
||||
use std::boxed::Box;
|
||||
use jsonrpc_core::futures::{self, Future};
|
||||
use fetch::{self, Fetch, Url, Method};
|
||||
use fetch::{self, Fetch, Url, Request};
|
||||
use futures::future;
|
||||
use hyper;
|
||||
|
||||
/// Test implementation of fetcher. Will always return the same file.
|
||||
@ -28,8 +30,8 @@ pub struct TestFetch;
|
||||
impl Fetch for TestFetch {
|
||||
type Result = Box<Future<Item = fetch::Response, Error = fetch::Error> + Send + 'static>;
|
||||
|
||||
fn fetch(&self, url: &str, _method: Method, abort: fetch::Abort) -> Self::Result {
|
||||
let u = Url::parse(url).unwrap();
|
||||
fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result {
|
||||
let u = request.url().clone();
|
||||
let (tx, rx) = futures::oneshot();
|
||||
thread::spawn(move || {
|
||||
let r = hyper::Response::new().with_body(&b"Some content"[..]);
|
||||
@ -38,4 +40,20 @@ impl Fetch for TestFetch {
|
||||
|
||||
Box::new(rx.map_err(|_| fetch::Error::Aborted))
|
||||
}
|
||||
|
||||
fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
|
||||
fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ hyper-rustls = "0.11"
|
||||
log = "0.4"
|
||||
tokio-core = "0.1"
|
||||
url = "1"
|
||||
bytes = "0.4"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
@ -20,7 +20,7 @@ use futures::{self, Future, Async, Sink, Stream};
|
||||
use futures_timer::FutureExt;
|
||||
use hyper::header::{UserAgent, Location, ContentLength, ContentType};
|
||||
use hyper::mime::Mime;
|
||||
use hyper::{self, Request, Method, StatusCode};
|
||||
use hyper::{self, Method, StatusCode};
|
||||
use hyper_rustls;
|
||||
use std;
|
||||
use std::cmp::min;
|
||||
@ -32,6 +32,7 @@ use std::time::Duration;
|
||||
use std::{io, fmt};
|
||||
use tokio_core::reactor;
|
||||
use url::{self, Url};
|
||||
use bytes::Bytes;
|
||||
|
||||
const MAX_SIZE: usize = 64 * 1024 * 1024;
|
||||
const MAX_SECS: Duration = Duration::from_secs(5);
|
||||
@ -120,22 +121,18 @@ pub trait Fetch: Clone + Send + Sync + 'static {
|
||||
type Result: Future<Item=Response, Error=Error> + Send + 'static;
|
||||
|
||||
/// Make a request to given URL
|
||||
fn fetch(&self, url: &str, method: Method, abort: Abort) -> Self::Result;
|
||||
fn fetch(&self, request: Request, abort: Abort) -> Self::Result;
|
||||
|
||||
/// Get content from some URL.
|
||||
fn get(&self, url: &str, abort: Abort) -> Self::Result {
|
||||
self.fetch(url, Method::Get, abort)
|
||||
}
|
||||
fn get(&self, url: &str, abort: Abort) -> Self::Result;
|
||||
|
||||
/// Post content to some URL.
|
||||
fn post(&self, url: &str, abort: Abort) -> Self::Result {
|
||||
self.fetch(url, Method::Post, abort)
|
||||
}
|
||||
fn post(&self, url: &str, abort: Abort) -> Self::Result;
|
||||
}
|
||||
|
||||
type TxResponse = oneshot::Sender<Result<Response, Error>>;
|
||||
type TxStartup = std::sync::mpsc::SyncSender<Result<(), io::Error>>;
|
||||
type ChanItem = Option<(Url, Method, Abort, TxResponse)>;
|
||||
type ChanItem = Option<(Request, Abort, TxResponse)>;
|
||||
|
||||
/// An implementation of `Fetch` using a `hyper` client.
|
||||
// Due to the `Send` bound of `Fetch` we spawn a background thread for
|
||||
@ -213,29 +210,37 @@ impl Client {
|
||||
|
||||
let future = rx_proto.take_while(|item| Ok(item.is_some()))
|
||||
.map(|item| item.expect("`take_while` is only passing on channel items != None; qed"))
|
||||
.for_each(|(url, method, abort, sender)|
|
||||
.for_each(|(request, abort, sender)|
|
||||
{
|
||||
trace!(target: "fetch", "new request to {}", url);
|
||||
trace!(target: "fetch", "new request to {}", request.url());
|
||||
if abort.is_aborted() {
|
||||
return future::ok(sender.send(Err(Error::Aborted)).unwrap_or(()))
|
||||
}
|
||||
let ini = (hyper.clone(), url, method, abort, 0);
|
||||
let fut = future::loop_fn(ini, |(client, url, method, abort, redirects)| {
|
||||
let url2 = url.clone();
|
||||
let ini = (hyper.clone(), request, abort, 0);
|
||||
let fut = future::loop_fn(ini, |(client, request, abort, redirects)| {
|
||||
let request2 = request.clone();
|
||||
let url2 = request2.url().clone();
|
||||
let abort2 = abort.clone();
|
||||
client.request(build_request(&url, method.clone()))
|
||||
client.request(request.into())
|
||||
.map(move |resp| Response::new(url2, resp, abort2))
|
||||
.from_err()
|
||||
.and_then(move |resp| {
|
||||
if abort.is_aborted() {
|
||||
debug!(target: "fetch", "fetch of {} aborted", url);
|
||||
debug!(target: "fetch", "fetch of {} aborted", request2.url());
|
||||
return Err(Error::Aborted)
|
||||
}
|
||||
if let Some(next_url) = redirect_location(url, &resp) {
|
||||
if let Some((next_url, preserve_method)) = redirect_location(request2.url().clone(), &resp) {
|
||||
if redirects >= abort.max_redirects() {
|
||||
return Err(Error::TooManyRedirects)
|
||||
}
|
||||
Ok(Loop::Continue((client, next_url, method, abort, redirects + 1)))
|
||||
let request = if preserve_method {
|
||||
let mut request2 = request2.clone();
|
||||
request2.set_url(next_url);
|
||||
request2
|
||||
} else {
|
||||
Request::new(next_url, Method::Get)
|
||||
};
|
||||
Ok(Loop::Continue((client, request, abort, redirects + 1)))
|
||||
} else {
|
||||
let content_len = resp.headers.get::<ContentLength>().cloned();
|
||||
if content_len.map(|n| *n > abort.max_size() as u64).unwrap_or(false) {
|
||||
@ -267,19 +272,15 @@ impl Client {
|
||||
impl Fetch for Client {
|
||||
type Result = Box<Future<Item=Response, Error=Error> + Send>;
|
||||
|
||||
fn fetch(&self, url: &str, method: Method, abort: Abort) -> Self::Result {
|
||||
debug!(target: "fetch", "fetching: {:?}", url);
|
||||
fn fetch(&self, request: Request, abort: Abort) -> Self::Result {
|
||||
debug!(target: "fetch", "fetching: {:?}", request.url());
|
||||
if abort.is_aborted() {
|
||||
return Box::new(future::err(Error::Aborted))
|
||||
}
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
let (tx_res, rx_res) = oneshot::channel();
|
||||
let maxdur = abort.max_duration();
|
||||
let sender = self.core.clone();
|
||||
let future = sender.send(Some((url.clone(), method, abort, tx_res)))
|
||||
let future = sender.send(Some((request, abort, tx_res)))
|
||||
.map_err(|e| {
|
||||
error!(target: "fetch", "failed to schedule request: {}", e);
|
||||
Error::BackgroundThreadDead
|
||||
@ -297,11 +298,33 @@ impl Fetch for Client {
|
||||
});
|
||||
Box::new(future)
|
||||
}
|
||||
|
||||
/// Get content from some URL.
|
||||
fn get(&self, url: &str, abort: Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
|
||||
/// Post content to some URL.
|
||||
fn post(&self, url: &str, abort: Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
||||
}
|
||||
|
||||
// Extract redirect location from response.
|
||||
fn redirect_location(u: Url, r: &Response) -> Option<Url> {
|
||||
// Extract redirect location from response. The second return value indicate whether the original method should be preserved.
|
||||
fn redirect_location(u: Url, r: &Response) -> Option<(Url, bool)> {
|
||||
use hyper::StatusCode::*;
|
||||
let preserve_method = match r.status() {
|
||||
TemporaryRedirect | PermanentRedirect => true,
|
||||
_ => false,
|
||||
};
|
||||
match r.status() {
|
||||
MovedPermanently
|
||||
| PermanentRedirect
|
||||
@ -309,7 +332,7 @@ fn redirect_location(u: Url, r: &Response) -> Option<Url> {
|
||||
| Found
|
||||
| SeeOther => {
|
||||
if let Some(loc) = r.headers.get::<Location>() {
|
||||
u.join(loc).ok()
|
||||
u.join(loc).ok().map(|url| (url, preserve_method))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -318,12 +341,84 @@ fn redirect_location(u: Url, r: &Response) -> Option<Url> {
|
||||
}
|
||||
}
|
||||
|
||||
// Build a simple request for the given Url and method
|
||||
fn build_request(u: &Url, method: Method) -> hyper::Request {
|
||||
let uri = u.as_ref().parse().expect("Every valid URL is aso a URI.");
|
||||
let mut rq = Request::new(method, uri);
|
||||
rq.headers_mut().set(UserAgent::new("Parity Fetch Neo"));
|
||||
rq
|
||||
/// A wrapper for hyper::Request using Url and with methods.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Request {
|
||||
url: Url,
|
||||
method: Method,
|
||||
headers: hyper::Headers,
|
||||
body: Bytes,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
/// Create a new request, with given url and method.
|
||||
pub fn new(url: Url, method: Method) -> Request {
|
||||
Request {
|
||||
url, method,
|
||||
headers: hyper::Headers::new(),
|
||||
body: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new GET request.
|
||||
pub fn get(url: Url) -> Request {
|
||||
Request::new(url, Method::Get)
|
||||
}
|
||||
|
||||
/// Create a new empty POST request.
|
||||
pub fn post(url: Url) -> Request {
|
||||
Request::new(url, Method::Post)
|
||||
}
|
||||
|
||||
/// Read the url.
|
||||
pub fn url(&self) -> &Url {
|
||||
&self.url
|
||||
}
|
||||
|
||||
/// Read the request headers.
|
||||
pub fn headers(&self) -> &hyper::Headers {
|
||||
&self.headers
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the headers.
|
||||
pub fn headers_mut(&mut self) -> &mut hyper::Headers {
|
||||
&mut self.headers
|
||||
}
|
||||
|
||||
/// Set the body of the request.
|
||||
pub fn set_body<T: Into<Bytes>>(&mut self, body: T) {
|
||||
self.body = body.into();
|
||||
}
|
||||
|
||||
/// Set the url of the request.
|
||||
pub fn set_url(&mut self, url: Url) {
|
||||
self.url = url;
|
||||
}
|
||||
|
||||
/// Consume self, and return it with the added given header.
|
||||
pub fn with_header<H: hyper::header::Header>(mut self, value: H) -> Self {
|
||||
self.headers_mut().set(value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Consume self, and return it with the body.
|
||||
pub fn with_body<T: Into<Bytes>>(mut self, body: T) -> Self {
|
||||
self.set_body(body);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<hyper::Request> for Request {
|
||||
fn into(mut self) -> hyper::Request {
|
||||
let uri = self.url.as_ref().parse().expect("Every valid URLis also a URI.");
|
||||
let mut req = hyper::Request::new(self.method, uri);
|
||||
|
||||
self.headers.set(UserAgent::new("Parity Fetch Neo"));
|
||||
*req.headers_mut() = self.headers;
|
||||
req.set_body(self.body);
|
||||
|
||||
req
|
||||
}
|
||||
}
|
||||
|
||||
/// An HTTP response.
|
||||
@ -527,7 +622,7 @@ mod test {
|
||||
use futures::future;
|
||||
use futures::sync::mpsc;
|
||||
use futures_timer::Delay;
|
||||
use hyper::{StatusCode, Method};
|
||||
use hyper::StatusCode;
|
||||
use hyper::server::{Http, Request, Response, Service};
|
||||
use std;
|
||||
use std::io::Read;
|
||||
@ -539,7 +634,7 @@ mod test {
|
||||
fn it_should_fetch() {
|
||||
let server = TestServer::run();
|
||||
let client = Client::new().unwrap();
|
||||
let future = client.fetch(&format!("http://{}?123", server.addr()), Method::Get, Default::default());
|
||||
let future = client.get(&format!("http://{}?123", server.addr()), Default::default());
|
||||
let resp = future.wait().unwrap();
|
||||
assert!(resp.is_success());
|
||||
let body = resp.concat2().wait().unwrap();
|
||||
@ -551,7 +646,7 @@ mod test {
|
||||
let server = TestServer::run();
|
||||
let client = Client::new().unwrap();
|
||||
let abort = Abort::default().with_max_duration(Duration::from_secs(1));
|
||||
match client.fetch(&format!("http://{}/delay?3", server.addr()), Method::Get, abort).wait() {
|
||||
match client.get(&format!("http://{}/delay?3", server.addr()), abort).wait() {
|
||||
Err(Error::Timeout) => {}
|
||||
other => panic!("expected timeout, got {:?}", other)
|
||||
}
|
||||
@ -562,7 +657,7 @@ mod test {
|
||||
let server = TestServer::run();
|
||||
let client = Client::new().unwrap();
|
||||
let abort = Abort::default();
|
||||
let future = client.fetch(&format!("http://{}/redirect?http://{}/", server.addr(), server.addr()), Method::Get, abort);
|
||||
let future = client.get(&format!("http://{}/redirect?http://{}/", server.addr(), server.addr()), abort);
|
||||
assert!(future.wait().unwrap().is_success())
|
||||
}
|
||||
|
||||
@ -571,7 +666,7 @@ mod test {
|
||||
let server = TestServer::run();
|
||||
let client = Client::new().unwrap();
|
||||
let abort = Abort::default().with_max_redirects(4);
|
||||
let future = client.fetch(&format!("http://{}/redirect?/", server.addr()), Method::Get, abort);
|
||||
let future = client.get(&format!("http://{}/redirect?/", server.addr()), abort);
|
||||
assert!(future.wait().unwrap().is_success())
|
||||
}
|
||||
|
||||
@ -580,7 +675,7 @@ mod test {
|
||||
let server = TestServer::run();
|
||||
let client = Client::new().unwrap();
|
||||
let abort = Abort::default().with_max_redirects(3);
|
||||
match client.fetch(&format!("http://{}/loop", server.addr()), Method::Get, abort).wait() {
|
||||
match client.get(&format!("http://{}/loop", server.addr()), abort).wait() {
|
||||
Err(Error::TooManyRedirects) => {}
|
||||
other => panic!("expected too many redirects error, got {:?}", other)
|
||||
}
|
||||
@ -591,7 +686,7 @@ mod test {
|
||||
let server = TestServer::run();
|
||||
let client = Client::new().unwrap();
|
||||
let abort = Abort::default();
|
||||
let future = client.fetch(&format!("http://{}?abcdefghijklmnopqrstuvwxyz", server.addr()), Method::Get, abort);
|
||||
let future = client.get(&format!("http://{}?abcdefghijklmnopqrstuvwxyz", server.addr()), abort);
|
||||
let resp = future.wait().unwrap();
|
||||
assert!(resp.is_success());
|
||||
assert_eq!(&resp.concat2().wait().unwrap()[..], b"abcdefghijklmnopqrstuvwxyz")
|
||||
@ -602,7 +697,7 @@ mod test {
|
||||
let server = TestServer::run();
|
||||
let client = Client::new().unwrap();
|
||||
let abort = Abort::default().with_max_size(3);
|
||||
let resp = client.fetch(&format!("http://{}/?1234", server.addr()), Method::Get, abort).wait().unwrap();
|
||||
let resp = client.get(&format!("http://{}/?1234", server.addr()), abort).wait().unwrap();
|
||||
assert!(resp.is_success());
|
||||
match resp.concat2().wait() {
|
||||
Err(Error::SizeLimit) => {}
|
||||
@ -615,7 +710,7 @@ mod test {
|
||||
let server = TestServer::run();
|
||||
let client = Client::new().unwrap();
|
||||
let abort = Abort::default().with_max_size(3);
|
||||
let resp = client.fetch(&format!("http://{}/?1234", server.addr()), Method::Get, abort).wait().unwrap();
|
||||
let resp = client.get(&format!("http://{}/?1234", server.addr()), abort).wait().unwrap();
|
||||
assert!(resp.is_success());
|
||||
let mut buffer = Vec::new();
|
||||
let mut reader = BodyReader::new(resp);
|
||||
|
@ -30,11 +30,11 @@ extern crate hyper_rustls;
|
||||
|
||||
extern crate tokio_core;
|
||||
extern crate url;
|
||||
extern crate bytes;
|
||||
|
||||
/// Fetch client implementation.
|
||||
pub mod client;
|
||||
|
||||
pub use url::Url;
|
||||
pub use self::client::{Client, Fetch, Error, Response, Abort, BodyReader};
|
||||
pub use self::client::{Client, Fetch, Error, Response, Request, Abort, BodyReader};
|
||||
pub use hyper::Method;
|
||||
|
||||
|
@ -24,7 +24,7 @@ use std::{fmt, thread};
|
||||
use std::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
use futures::{Future, IntoFuture};
|
||||
pub use tokio_core::reactor::{Remote as TokioRemote, Timeout};
|
||||
pub use tokio_core::reactor::{Remote as TokioRemote, Handle, Timeout};
|
||||
|
||||
/// Event Loop for futures.
|
||||
/// Wrapper around `tokio::reactor::Core`.
|
||||
@ -143,18 +143,22 @@ impl Remote {
|
||||
|
||||
/// Spawn a new future returned by given closure.
|
||||
pub fn spawn_fn<F, R>(&self, f: F) where
|
||||
F: FnOnce() -> R + Send + 'static,
|
||||
F: FnOnce(&Handle) -> R + Send + 'static,
|
||||
R: IntoFuture<Item=(), Error=()>,
|
||||
R::Future: 'static,
|
||||
{
|
||||
match self.inner {
|
||||
Mode::Tokio(ref remote) => remote.spawn(move |_| f()),
|
||||
Mode::Tokio(ref remote) => remote.spawn(move |handle| f(handle)),
|
||||
Mode::Sync => {
|
||||
let _ = f().into_future().wait();
|
||||
let mut core = tokio_core::reactor::Core::new().expect("Creating an event loop should not fail.");
|
||||
let handle = core.handle();
|
||||
let _ = core.run(f(&handle).into_future());
|
||||
},
|
||||
Mode::ThreadPerFuture => {
|
||||
thread::spawn(move || {
|
||||
let _= f().into_future().wait();
|
||||
let mut core = tokio_core::reactor::Core::new().expect("Creating an event loop should not fail.");
|
||||
let handle = core.handle();
|
||||
let _ = core.run(f(&handle).into_future());
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -163,13 +167,13 @@ impl Remote {
|
||||
/// Spawn a new future and wait for it or for a timeout to occur.
|
||||
pub fn spawn_with_timeout<F, R, T>(&self, f: F, duration: Duration, on_timeout: T) where
|
||||
T: FnOnce() -> () + Send + 'static,
|
||||
F: FnOnce() -> R + Send + 'static,
|
||||
F: FnOnce(&Handle) -> R + Send + 'static,
|
||||
R: IntoFuture<Item=(), Error=()>,
|
||||
R::Future: 'static,
|
||||
{
|
||||
match self.inner {
|
||||
Mode::Tokio(ref remote) => remote.spawn(move |handle| {
|
||||
let future = f().into_future();
|
||||
let future = f(handle).into_future();
|
||||
let timeout = Timeout::new(duration, handle).expect("Event loop is still up.");
|
||||
future.select(timeout.then(move |_| {
|
||||
on_timeout();
|
||||
@ -177,11 +181,25 @@ impl Remote {
|
||||
})).then(|_| Ok(()))
|
||||
}),
|
||||
Mode::Sync => {
|
||||
let _ = f().into_future().wait();
|
||||
let mut core = tokio_core::reactor::Core::new().expect("Creating an event loop should not fail.");
|
||||
let handle = core.handle();
|
||||
let future = f(&handle).into_future();
|
||||
let timeout = Timeout::new(duration, &handle).expect("Event loop is still up.");
|
||||
let _: Result<(), ()> = core.run(future.select(timeout.then(move |_| {
|
||||
on_timeout();
|
||||
Ok(())
|
||||
})).then(|_| Ok(())));
|
||||
},
|
||||
Mode::ThreadPerFuture => {
|
||||
thread::spawn(move || {
|
||||
let _ = f().into_future().wait();
|
||||
let mut core = tokio_core::reactor::Core::new().expect("Creating an event loop should not fail.");
|
||||
let handle = core.handle();
|
||||
let future = f(&handle).into_future();
|
||||
let timeout = Timeout::new(duration, &handle).expect("Event loop is still up.");
|
||||
let _: Result<(), ()> = core.run(future.select(timeout.then(move |_| {
|
||||
on_timeout();
|
||||
Ok(())
|
||||
})).then(|_| Ok(())));
|
||||
});
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user