Merge branch 'master' into lightsync
This commit is contained in:
		
						commit
						d0194f3ad3
					
				| @ -1,6 +1,7 @@ | ||||
| stages: | ||||
|   - test | ||||
|   - js-build | ||||
|   - push-release | ||||
|   - build | ||||
| variables: | ||||
|   GIT_DEPTH: "3" | ||||
| @ -20,7 +21,6 @@ linux-stable: | ||||
|     - stable | ||||
|     - triggers | ||||
|   script: | ||||
|     - curl --data "secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF | ||||
|     - cargo build -j $(nproc) --release --features final $CARGOFLAGS | ||||
|     - strip target/release/parity | ||||
|     - export SHA3=$(target/release/parity tools hash target/release/parity) | ||||
| @ -517,3 +517,15 @@ js-release: | ||||
|     - if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS rebuild since no JS files modified."; else ./js/scripts/build.sh && ./js/scripts/release.sh; fi | ||||
|   tags: | ||||
|     - javascript | ||||
| push-release: | ||||
|   stage: push-release | ||||
|   only: | ||||
|     - beta | ||||
|     - tags | ||||
|     - stable | ||||
|     - triggers | ||||
|   image: ethcore/rust:stable | ||||
|   script: | ||||
|     - curl --data "secret=$RELEASES_SECRET" http://icarus.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF | ||||
|   tags: | ||||
|     - curl | ||||
|  | ||||
							
								
								
									
										349
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										349
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -26,13 +26,14 @@ dependencies = [ | ||||
|  "ethcore-util 1.5.0", | ||||
|  "ethsync 1.5.0", | ||||
|  "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parity-hash-fetch 1.5.0", | ||||
|  "parity-reactor 0.1.0", | ||||
|  "parity-rpc-client 1.4.0", | ||||
|  "parity-updater 1.5.0", | ||||
|  "regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -42,13 +43,22 @@ dependencies = [ | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "toml 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "advapi32-sys" | ||||
| version = "0.2.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)", | ||||
|  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "aho-corasick" | ||||
| version = "0.5.1" | ||||
| @ -98,11 +108,6 @@ dependencies = [ | ||||
|  "syntex_syntax 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "base64" | ||||
| version = "0.2.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bit-set" | ||||
| version = "0.4.0" | ||||
| @ -126,6 +131,11 @@ name = "bitflags" | ||||
| version = "0.5.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bitflags" | ||||
| version = "0.7.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "blastfig" | ||||
| version = "0.3.3" | ||||
| @ -200,9 +210,35 @@ dependencies = [ | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "crossbeam" | ||||
| version = "0.2.9" | ||||
| name = "core-foundation" | ||||
| version = "0.2.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "core-foundation-sys" | ||||
| version = "0.2.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "crossbeam" | ||||
| version = "0.2.10" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "crypt32-sys" | ||||
| version = "0.2.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)", | ||||
|  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ctrlc" | ||||
| @ -281,7 +317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -305,7 +341,7 @@ dependencies = [ | ||||
|  "bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ethash 1.5.0", | ||||
| @ -364,6 +400,7 @@ dependencies = [ | ||||
|  "ethcore-rpc 1.5.0", | ||||
|  "ethcore-util 1.5.0", | ||||
|  "fetch 0.1.0", | ||||
|  "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", | ||||
|  "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", | ||||
|  "jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)", | ||||
| @ -373,10 +410,11 @@ dependencies = [ | ||||
|  "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parity-hash-fetch 1.5.0", | ||||
|  "parity-reactor 0.1.0", | ||||
|  "parity-ui 1.5.0", | ||||
|  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -396,7 +434,7 @@ dependencies = [ | ||||
| name = "ethcore-io" | ||||
| version = "1.5.0" | ||||
| dependencies = [ | ||||
|  "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "mio 0.6.1 (git+https://github.com/ethcore/mio)", | ||||
|  "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -532,16 +570,19 @@ dependencies = [ | ||||
|  "ethstore 0.1.0", | ||||
|  "ethsync 1.5.0", | ||||
|  "fetch 0.1.0", | ||||
|  "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", | ||||
|  "jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)", | ||||
|  "jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)", | ||||
|  "jsonrpc-macros 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parity-reactor 0.1.0", | ||||
|  "parity-updater 1.5.0", | ||||
|  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rlp 0.1.0", | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -638,7 +679,7 @@ version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "ethcore-util 1.5.0", | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| @ -666,11 +707,12 @@ dependencies = [ | ||||
|  "itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -721,10 +763,11 @@ dependencies = [ | ||||
| name = "fetch" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "https-fetch 0.1.0", | ||||
|  "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", | ||||
|  "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "reqwest 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| @ -744,6 +787,16 @@ dependencies = [ | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "futures-cpupool" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "gcc" | ||||
| version = "0.3.35" | ||||
| @ -752,6 +805,15 @@ dependencies = [ | ||||
|  "rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "gdi32-sys" | ||||
| version = "0.2.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)", | ||||
|  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "glob" | ||||
| version = "0.2.11" | ||||
| @ -783,19 +845,9 @@ name = "httparse" | ||||
| version = "1.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "https-fetch" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)", | ||||
|  "rustls 0.1.2 (git+https://github.com/ctz/rustls)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hyper" | ||||
| version = "0.9.10" | ||||
| version = "0.9.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -803,7 +855,7 @@ dependencies = [ | ||||
|  "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -847,7 +899,7 @@ name = "igd" | ||||
| version = "0.5.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "xml-rs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -892,7 +944,7 @@ source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec33 | ||||
| dependencies = [ | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| @ -929,7 +981,7 @@ version = "0.1.0" | ||||
| source = "git+https://github.com/ethcore/jsonrpc.git#33262d626a294a00c20435dec331058ba65e224a" | ||||
| dependencies = [ | ||||
|  "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| @ -1103,6 +1155,22 @@ dependencies = [ | ||||
|  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "mio" | ||||
| version = "0.6.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "miow" | ||||
| version = "0.1.3" | ||||
| @ -1142,6 +1210,18 @@ dependencies = [ | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "native-tls" | ||||
| version = "0.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "openssl 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "schannel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "security-framework 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "security-framework-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "net2" | ||||
| version = "0.2.23" | ||||
| @ -1276,6 +1356,14 @@ dependencies = [ | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "num_cpus" | ||||
| version = "1.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "number_prefix" | ||||
| version = "0.2.5" | ||||
| @ -1298,6 +1386,28 @@ dependencies = [ | ||||
|  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "openssl" | ||||
| version = "0.9.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "openssl-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "openssl-sys" | ||||
| version = "0.9.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "owning_ref" | ||||
| version = "0.2.2" | ||||
| @ -1324,11 +1434,23 @@ dependencies = [ | ||||
|  "ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ethcore-util 1.5.0", | ||||
|  "fetch 0.1.0", | ||||
|  "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parity-reactor 0.1.0", | ||||
|  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "parity-reactor" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "tokio-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "parity-rpc-client" | ||||
| version = "1.4.0" | ||||
| @ -1342,7 +1464,7 @@ dependencies = [ | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| @ -1368,7 +1490,7 @@ dependencies = [ | ||||
| [[package]] | ||||
| name = "parity-ui-precompiled" | ||||
| version = "1.4.0" | ||||
| source = "git+https://github.com/ethcore/js-precompiled.git#c8eb24c13e6fa57bf3b85b16209d281d89b31cbf" | ||||
| source = "git+https://github.com/ethcore/js-precompiled.git#8d16476c138e94a643ad4624df9825f34b57e1b0" | ||||
| dependencies = [ | ||||
|  "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| @ -1386,6 +1508,7 @@ dependencies = [ | ||||
|  "ipc-common-types 1.5.0", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parity-hash-fetch 1.5.0", | ||||
|  "parity-reactor 0.1.0", | ||||
|  "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| @ -1444,6 +1567,11 @@ dependencies = [ | ||||
|  "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "pkg-config" | ||||
| version = "0.3.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "podio" | ||||
| version = "0.1.5" | ||||
| @ -1574,12 +1702,17 @@ version = "0.3.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ring" | ||||
| version = "0.4.3" | ||||
| name = "reqwest" | ||||
| version = "0.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "untrusted 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_urlencoded 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| @ -1682,16 +1815,51 @@ dependencies = [ | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rustls" | ||||
| version = "0.1.2" | ||||
| source = "git+https://github.com/ctz/rustls#3d2db624997004b7b18ba4463d6081f37598b2f5" | ||||
| name = "schannel" | ||||
| version = "0.1.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "base64 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ring 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "untrusted 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "webpki 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "scoped-tls" | ||||
| version = "0.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "secur32-sys" | ||||
| version = "0.2.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)", | ||||
|  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "security-framework" | ||||
| version = "0.1.9" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "security-framework-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "security-framework-sys" | ||||
| version = "0.1.9" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| @ -1726,7 +1894,7 @@ dependencies = [ | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde" | ||||
| version = "0.8.4" | ||||
| version = "0.8.19" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| @ -1759,7 +1927,16 @@ dependencies = [ | ||||
|  "dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde_urlencoded" | ||||
| version = "0.3.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| @ -1983,6 +2160,18 @@ name = "tiny-keccak" | ||||
| version = "1.0.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "tokio-core" | ||||
| version = "0.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "mio 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "toml" | ||||
| version = "0.1.28" | ||||
| @ -2043,11 +2232,6 @@ name = "unicode-xid" | ||||
| version = "0.0.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "untrusted" | ||||
| version = "0.3.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "url" | ||||
| version = "1.2.0" | ||||
| @ -2057,6 +2241,15 @@ dependencies = [ | ||||
|  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "user32-sys" | ||||
| version = "0.2.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)", | ||||
|  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "using_queue" | ||||
| version = "0.1.0" | ||||
| @ -2089,17 +2282,6 @@ name = "void" | ||||
| version = "1.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "webpki" | ||||
| version = "0.3.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "ring 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "untrusted 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi" | ||||
| version = "0.2.8" | ||||
| @ -2167,17 +2349,18 @@ dependencies = [ | ||||
| ] | ||||
| 
 | ||||
| [metadata] | ||||
| "checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" | ||||
| "checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03" | ||||
| "checksum ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f46cd5b1d660c938e3f92dfe7a73d832b3281479363dd0cd9c1c2fbf60f7962" | ||||
| "checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4" | ||||
| "checksum arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "16e3bdb2f54b3ace0285975d59a97cf8ed3855294b2b6bc651fcf22a9c352975" | ||||
| "checksum aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07d344974f0a155f091948aa389fb1b912d3a58414fbdb9c8d446d193ee3496a" | ||||
| "checksum aster 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4df293303e8a52e1df7984ac1415e195f5fcbf51e4bb7bda54557861a3954a08" | ||||
| "checksum base64 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2015e3793554aa5b6007e3a72959e84c1070039e74f13dde08fa64afe1ddd892" | ||||
| "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" | ||||
| "checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d" | ||||
| "checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3" | ||||
| "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" | ||||
| "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" | ||||
| "checksum blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09640e0509d97d5cdff03a9f5daf087a8e04c735c3b113a75139634a19cfc7b2" | ||||
| "checksum bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f421095d2a76fc24cd3fb3f912b90df06be7689912b1bdb423caefae59c258d" | ||||
| "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" | ||||
| @ -2188,7 +2371,10 @@ dependencies = [ | ||||
| "checksum clippy_lints 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "ce96ec05bfe018a0d5d43da115e54850ea2217981ff0f2e462780ab9d594651a" | ||||
| "checksum cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90266f45846f14a1e986c77d1e9c2626b8c342ed806fe60241ec38cc8697b245" | ||||
| "checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591" | ||||
| "checksum crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "fb974f835e90390c5f9dfac00f05b06dc117299f5ea4e85fbc7bb443af4911cc" | ||||
| "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd" | ||||
| "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5" | ||||
| "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" | ||||
| "checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" | ||||
| "checksum ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)" = "<none>" | ||||
| "checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf" | ||||
| "checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf" | ||||
| @ -2201,14 +2387,16 @@ dependencies = [ | ||||
| "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" | ||||
| "checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb" | ||||
| "checksum futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bad0a2ac64b227fdc10c254051ae5af542cf19c9328704fd4092f7914196897" | ||||
| "checksum futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bb982bb25cd8fa5da6a8eb3a460354c984ff1113da82bcb4f0b0862b5795db82" | ||||
| "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" | ||||
| "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" | ||||
| "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" | ||||
| "checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1" | ||||
| "checksum heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "abb306abb8d398e053cfb1b3e7b72c2f580be048b85745c52652954f8ad1439c" | ||||
| "checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58" | ||||
| "checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae" | ||||
| "checksum hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)" = "<none>" | ||||
| "checksum hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "eb27e8a3e8f17ac43ffa41bbda9cf5ad3f9f13ef66fa4873409d4902310275f7" | ||||
| "checksum hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb3fc65554155980167fb821d05c7c66177f92464976c0b676a19d9e03387a7" | ||||
| "checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" | ||||
| "checksum igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c12b1795b8b168f577c45fa10379b3814dcb11b7ab702406001f0d63f40484" | ||||
| "checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c" | ||||
| @ -2237,10 +2425,12 @@ dependencies = [ | ||||
| "checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e" | ||||
| "checksum mio 0.6.0-dev (git+https://github.com/ethcore/mio?branch=timer-fix)" = "<none>" | ||||
| "checksum mio 0.6.1 (git+https://github.com/ethcore/mio)" = "<none>" | ||||
| "checksum mio 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "410a1a0ff76f5a226f1e4e3ff1756128e65cd30166e39c3892283e2ac09d5b67" | ||||
| "checksum miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bfc6782530ac8ace97af10a540054a37126b63b0702ddaaa243b73b5745b9a" | ||||
| "checksum msdos_time 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c04b68cc63a8480fb2550343695f7be72effdec953a9d4508161c3e69041c7d8" | ||||
| "checksum nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)" = "<none>" | ||||
| "checksum nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)" = "<none>" | ||||
| "checksum native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4e52995154bb6f0b41e4379a279482c9387c1632e3798ba4e511ef8c54ee09" | ||||
| "checksum net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a816012ca11cb47009693c1e0c6130e26d39e4d97ee2a13c50e868ec83e3204" | ||||
| "checksum nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f05c2fc965fc1cd6b73fa57fa7b89f288178737f2f3ce9e63e4a6a141189000e" | ||||
| "checksum nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a7bb1da2be7da3cbffda73fc681d509ffd9e665af478d2bee1907cee0bc64b2" | ||||
| @ -2255,9 +2445,12 @@ dependencies = [ | ||||
| "checksum num-rational 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "48cdcc9ff4ae2a8296805ac15af88b3d88ce62128ded0cb74ffb63a587502a84" | ||||
| "checksum num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "51eab148f171aefad295f8cece636fc488b9b392ef544da31ea4b8ef6b9e9c39" | ||||
| "checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09" | ||||
| "checksum num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55aabf4e2d6271a2e4e4c0f2ea1f5b07cc589cc1a9e9213013b54a76678ca4f3" | ||||
| "checksum number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "084d05f4bf60621a9ac9bde941a410df548f4de9545f06e5ee9d3aef4b97cd77" | ||||
| "checksum odds 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "b28c06e81b0f789122d415d6394b5fe849bde8067469f4c2980d3cdc10c78ec1" | ||||
| "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" | ||||
| "checksum openssl 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "12be61c7eaa23228316ff02c39807e4c1b1af84ba81420f19fd58dade304b25c" | ||||
| "checksum openssl-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d2845e841700e7b04282ceaa115407ea84e0db918ae689ad9ceb6f06fa6046bd" | ||||
| "checksum owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d91377085359426407a287ab16884a0111ba473aa6844ff01d4ec20ce3d75e7" | ||||
| "checksum parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98378dec0a185da2b7180308752f0bad73aaa949c3e0a3b0528d0e067945f7ab" | ||||
| "checksum parity-ui-precompiled 1.4.0 (git+https://github.com/ethcore/js-precompiled.git)" = "<none>" | ||||
| @ -2267,6 +2460,7 @@ dependencies = [ | ||||
| "checksum phf_codegen 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8af7ae7c3f75a502292b491e5cc0a1f69e3407744abe6e57e2a3b712bb82f01d" | ||||
| "checksum phf_generator 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "db005608fd99800c8c74106a7c894cf582055b689aa14a79462cefdcb7dc1cc3" | ||||
| "checksum phf_shared 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fee4d039930e4f45123c9b15976cf93a499847b6483dc09c42ea0ec4940f2aa6" | ||||
| "checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa" | ||||
| "checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0" | ||||
| "checksum primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0e31b86efadeaeb1235452171a66689682783149a6249ff334a2c5d8218d00a4" | ||||
| "checksum primal-bit 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "464a91febc06166783d4f5ba3577b5ed8dda8e421012df80bfe48a971ed7be8f" | ||||
| @ -2283,7 +2477,7 @@ dependencies = [ | ||||
| "checksum rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "655df67c314c30fa3055a365eae276eb88aa4f3413a352a1ab32c1320eda41ea" | ||||
| "checksum regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)" = "b4329b8928a284580a1c63ec9d846b12f6d3472317243ff7077aff11f23f2b29" | ||||
| "checksum regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "841591b1e05609a643e3b4d0045fce04f701daba7151ddcd3ad47b080693d5a9" | ||||
| "checksum ring 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2f6547bf9640f1d3cc4e771f82374ec8fd237c17eeb3ff5cd5ccbe22377a09" | ||||
| "checksum reqwest 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83186fee0d4dbeb95e610b77b05b05cf5b31703dd375222acb74c3dff4be957c" | ||||
| "checksum rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>" | ||||
| "checksum rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>" | ||||
| "checksum rotor 0.6.3 (git+https://github.com/ethcore/rotor)" = "<none>" | ||||
| @ -2292,15 +2486,20 @@ dependencies = [ | ||||
| "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" | ||||
| "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" | ||||
| "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" | ||||
| "checksum rustls 0.1.2 (git+https://github.com/ctz/rustls)" = "<none>" | ||||
| "checksum schannel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "167852e03fcd0029c3ddebb5afb0715b2996f6e262b2c2aceaa7cd84edd4b158" | ||||
| "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" | ||||
| "checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc" | ||||
| "checksum security-framework 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52186fcf3b391c9f0ccdce9a2ac708f7cc81b3f89e149b34bd9279fb1b23f9fa" | ||||
| "checksum security-framework-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c84067e6297c1f09514a8666d8bbc1268817ec4a6c0f30f12f6201e1f34bd2a1" | ||||
| "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" | ||||
| "checksum semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d5b7638a1f03815d94e88cb3b3c08e87f0db4d683ef499d1836aaf70a45623f" | ||||
| "checksum semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2ff60ecdb19c255841c066cbfa5f8c2a4ada1eb3ae47c77ab6667128da71f5" | ||||
| "checksum semver-parser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e88e43a5a74dd2a11707f9c21dfd4a423c66bd871df813227bb0a3e78f3a1ae9" | ||||
| "checksum serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b1dfda9ebb31d29fa8b94d7eb3031a86a8dcec065f0fe268a30f98867bf45775" | ||||
| "checksum serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "58a19c0871c298847e6b68318484685cd51fa5478c0c905095647540031356e5" | ||||
| "checksum serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e422ae53d7933f59c6ff57e7b5870b5c9094b1f473f78ec33d89f8a692c3ec02" | ||||
| "checksum serde_codegen_internals 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f877e2781ed0a323295d1c9f0e26556117b5a11489fc47b1848dfb98b3173d21" | ||||
| "checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc" | ||||
| "checksum serde_urlencoded 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53d4ebaa8d1d4f90d1b63dfca81ccd98ac20e1e479dbae393cbaf60f6fecd8d8" | ||||
| "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" | ||||
| "checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d" | ||||
| "checksum siphasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c44e42fa187b5a8782489cf7740cc27c3125806be2bf33563cf5e02e9533fcd" | ||||
| @ -2329,6 +2528,7 @@ dependencies = [ | ||||
| "checksum thread_local 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0694f51610ef7cfac7a1b81de7f1602ee5356e76541bcd62c40e71933338cab1" | ||||
| "checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af" | ||||
| "checksum tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f7aef43048292ca0bae4ab32180e85f6202cf2816c2a210c396a84b99dab9270" | ||||
| "checksum tokio-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52416b3e937abac22a543a7f1c66bd37feb60137ff1ab42390fa02df85347e58" | ||||
| "checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6" | ||||
| "checksum toml 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a442dfc13508e603c3f763274361db7f79d7469a0e95c411cde53662ab30fc72" | ||||
| "checksum traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07eaeb7689bb7fca7ce15628319635758eda769fed481ecfe6686ddef2600616" | ||||
| @ -2338,13 +2538,12 @@ dependencies = [ | ||||
| "checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" | ||||
| "checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" | ||||
| "checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" | ||||
| "checksum untrusted 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5d9bc0e6e73a10975d1fbff8ac3541e221181b0d8998351600fb5523de634c0d" | ||||
| "checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119" | ||||
| "checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" | ||||
| "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" | ||||
| "checksum vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0795a11576d29ae80525a3fda315bf7b534f8feb9d34101e5fe63fb95bb2fd24" | ||||
| "checksum vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56b639f935488eb40f06d17c3e3bcc3054f6f75d264e187b1107c8d1cba8d31c" | ||||
| "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" | ||||
| "checksum webpki 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "813503a5985585e0812d430cd1328ee322f47f66629c8ed4ecab939cf9e92f91" | ||||
| "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" | ||||
| "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" | ||||
| "checksum ws 0.5.3 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)" = "<none>" | ||||
|  | ||||
| @ -52,6 +52,7 @@ parity-rpc-client = { path = "rpc_client" } | ||||
| ethcore-light = { path = "ethcore/light" } | ||||
| parity-hash-fetch = { path = "hash-fetch" } | ||||
| parity-updater = { path = "updater" } | ||||
| parity-reactor = { path = "util/reactor" } | ||||
| 
 | ||||
| [target.'cfg(windows)'.dependencies] | ||||
| winapi = "0.2" | ||||
|  | ||||
| @ -12,6 +12,7 @@ build = "build.rs" | ||||
| rand = "0.3.14" | ||||
| log = "0.3" | ||||
| env_logger = "0.3" | ||||
| futures = "0.1" | ||||
| jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" } | ||||
| jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" } | ||||
| hyper = { default-features = false, git = "https://github.com/ethcore/hyper" } | ||||
| @ -33,6 +34,7 @@ ethcore-util = { path = "../util" } | ||||
| fetch = { path = "../util/fetch" } | ||||
| parity-ui = { path = "./ui" } | ||||
| parity-hash-fetch = { path = "../hash-fetch" } | ||||
| parity-reactor = { path = "../util/reactor" } | ||||
| 
 | ||||
| clippy = { version = "0.0.103", optional = true} | ||||
| 
 | ||||
|  | ||||
| @ -23,7 +23,7 @@ use hyper::header::AccessControlAllowOrigin; | ||||
| 
 | ||||
| use api::types::{App, ApiError}; | ||||
| use api::response; | ||||
| use apps::fetcher::ContentFetcher; | ||||
| use apps::fetcher::Fetcher; | ||||
| 
 | ||||
| use handlers::extract_url; | ||||
| use endpoint::{Endpoint, Endpoints, Handler, EndpointPath}; | ||||
| @ -33,11 +33,11 @@ use jsonrpc_http_server::cors; | ||||
| pub struct RestApi { | ||||
| 	cors_domains: Option<Vec<AccessControlAllowOrigin>>, | ||||
| 	endpoints: Arc<Endpoints>, | ||||
| 	fetcher: Arc<ContentFetcher>, | ||||
| 	fetcher: Arc<Fetcher>, | ||||
| } | ||||
| 
 | ||||
| impl RestApi { | ||||
| 	pub fn new(cors_domains: Vec<String>, endpoints: Arc<Endpoints>, fetcher: Arc<ContentFetcher>) -> Box<Endpoint> { | ||||
| 	pub fn new(cors_domains: Vec<String>, endpoints: Arc<Endpoints>, fetcher: Arc<Fetcher>) -> Box<Endpoint> { | ||||
| 		Box::new(RestApi { | ||||
| 			cors_domains: Some(cors_domains.into_iter().map(AccessControlAllowOrigin::Value).collect()), | ||||
| 			endpoints: endpoints, | ||||
|  | ||||
| @ -1,445 +0,0 @@ | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| 
 | ||||
| // Parity is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||
| // GNU General Public License for more details.
 | ||||
| 
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| //! Fetchable Dapps support.
 | ||||
| //! Manages downloaded (cached) Dapps and downloads them when necessary.
 | ||||
| //! Uses `URLHint` to resolve addresses into Dapps bundle file location.
 | ||||
| 
 | ||||
| use zip; | ||||
| use std::{fs, env, fmt}; | ||||
| use std::io::{self, Read, Write}; | ||||
| use std::path::PathBuf; | ||||
| use std::sync::Arc; | ||||
| use rustc_serialize::hex::FromHex; | ||||
| use hash_fetch::urlhint::{URLHintContract, URLHint, URLHintResult}; | ||||
| 
 | ||||
| use hyper; | ||||
| use hyper::status::StatusCode; | ||||
| 
 | ||||
| use random_filename; | ||||
| use SyncStatus; | ||||
| use util::{Mutex, H256}; | ||||
| use util::sha3::sha3; | ||||
| use page::{LocalPageEndpoint, PageCache}; | ||||
| use handlers::{ContentHandler, ContentFetcherHandler, ContentValidator}; | ||||
| use endpoint::{Endpoint, EndpointPath, Handler}; | ||||
| use apps::cache::{ContentCache, ContentStatus}; | ||||
| use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; | ||||
| 
 | ||||
| /// Limit of cached dapps/content
 | ||||
| const MAX_CACHED_DAPPS: usize = 20; | ||||
| 
 | ||||
| pub struct ContentFetcher<R: URLHint = URLHintContract> { | ||||
| 	dapps_path: PathBuf, | ||||
| 	resolver: R, | ||||
| 	cache: Arc<Mutex<ContentCache>>, | ||||
| 	sync: Arc<SyncStatus>, | ||||
| 	embeddable_on: Option<(String, u16)>, | ||||
| } | ||||
| 
 | ||||
| impl<R: URLHint> Drop for ContentFetcher<R> { | ||||
| 	fn drop(&mut self) { | ||||
| 		// Clear cache path
 | ||||
| 		let _ = fs::remove_dir_all(&self.dapps_path); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<R: URLHint> ContentFetcher<R> { | ||||
| 
 | ||||
| 	pub fn new(resolver: R, sync_status: Arc<SyncStatus>, embeddable_on: Option<(String, u16)>) -> Self { | ||||
| 		let mut dapps_path = env::temp_dir(); | ||||
| 		dapps_path.push(random_filename()); | ||||
| 
 | ||||
| 		ContentFetcher { | ||||
| 			dapps_path: dapps_path, | ||||
| 			resolver: resolver, | ||||
| 			sync: sync_status, | ||||
| 			cache: Arc::new(Mutex::new(ContentCache::default())), | ||||
| 			embeddable_on: embeddable_on, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn still_syncing(address: Option<(String, u16)>) -> Box<Handler> { | ||||
| 		Box::new(ContentHandler::error( | ||||
| 			StatusCode::ServiceUnavailable, | ||||
| 			"Sync In Progress", | ||||
| 			"Your node is still syncing. We cannot resolve any content before it's fully synced.", | ||||
| 			Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"), | ||||
| 			address, | ||||
| 		)) | ||||
| 	} | ||||
| 
 | ||||
| 	#[cfg(test)] | ||||
| 	fn set_status(&self, content_id: &str, status: ContentStatus) { | ||||
| 		self.cache.lock().insert(content_id.to_owned(), status); | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn contains(&self, content_id: &str) -> bool { | ||||
| 		{ | ||||
| 			let mut cache = self.cache.lock(); | ||||
| 			// Check if we already have the app
 | ||||
| 			if cache.get(content_id).is_some() { | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		// fallback to resolver
 | ||||
| 		if let Ok(content_id) = content_id.from_hex() { | ||||
| 			// else try to resolve the app_id
 | ||||
| 			let has_content = self.resolver.resolve(content_id).is_some(); | ||||
| 			// if there is content or we are syncing return true
 | ||||
| 			has_content || self.sync.is_major_importing() | ||||
| 		} else { | ||||
| 			false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn to_async_handler(&self, path: EndpointPath, control: hyper::Control) -> Box<Handler> { | ||||
| 		let mut cache = self.cache.lock(); | ||||
| 		let content_id = path.app_id.clone(); | ||||
| 
 | ||||
| 		let (new_status, handler) = { | ||||
| 			let status = cache.get(&content_id); | ||||
| 			match status { | ||||
| 				// Just serve the content
 | ||||
| 				Some(&mut ContentStatus::Ready(ref endpoint)) => { | ||||
| 					(None, endpoint.to_async_handler(path, control)) | ||||
| 				}, | ||||
| 				// Content is already being fetched
 | ||||
| 				Some(&mut ContentStatus::Fetching(ref fetch_control)) => { | ||||
| 					trace!(target: "dapps", "Content fetching in progress. Waiting..."); | ||||
| 					(None, fetch_control.to_async_handler(path, control)) | ||||
| 				}, | ||||
| 				// We need to start fetching the content
 | ||||
| 				None => { | ||||
| 					trace!(target: "dapps", "Content unavailable. Fetching... {:?}", content_id); | ||||
| 					let content_hex = content_id.from_hex().expect("to_handler is called only when `contains` returns true."); | ||||
| 					let content = self.resolver.resolve(content_hex); | ||||
| 
 | ||||
| 					let cache = self.cache.clone(); | ||||
| 					let id = content_id.clone(); | ||||
| 					let on_done = move |result: Option<LocalPageEndpoint>| { | ||||
| 						let mut cache = cache.lock(); | ||||
| 						match result { | ||||
| 							Some(endpoint) => { | ||||
| 								cache.insert(id.clone(), ContentStatus::Ready(endpoint)); | ||||
| 							}, | ||||
| 							// In case of error
 | ||||
| 							None => { | ||||
| 								cache.remove(&id); | ||||
| 							}, | ||||
| 						} | ||||
| 					}; | ||||
| 
 | ||||
| 					match content { | ||||
| 						// Don't serve dapps if we are still syncing (but serve content)
 | ||||
| 						Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => { | ||||
| 							(None, Self::still_syncing(self.embeddable_on.clone())) | ||||
| 						}, | ||||
| 						Some(URLHintResult::Dapp(dapp)) => { | ||||
| 							let (handler, fetch_control) = ContentFetcherHandler::new( | ||||
| 								dapp.url(), | ||||
| 								path, | ||||
| 								control, | ||||
| 								DappInstaller { | ||||
| 									id: content_id.clone(), | ||||
| 									dapps_path: self.dapps_path.clone(), | ||||
| 									on_done: Box::new(on_done), | ||||
| 									embeddable_on: self.embeddable_on.clone(), | ||||
| 								}, | ||||
| 								self.embeddable_on.clone(), | ||||
| 							); | ||||
| 
 | ||||
| 							(Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>) | ||||
| 						}, | ||||
| 						Some(URLHintResult::Content(content)) => { | ||||
| 							let (handler, fetch_control) = ContentFetcherHandler::new( | ||||
| 								content.url, | ||||
| 								path, | ||||
| 								control, | ||||
| 								ContentInstaller { | ||||
| 									id: content_id.clone(), | ||||
| 									mime: content.mime, | ||||
| 									content_path: self.dapps_path.clone(), | ||||
| 									on_done: Box::new(on_done), | ||||
| 								}, | ||||
| 								self.embeddable_on.clone(), | ||||
| 							); | ||||
| 
 | ||||
| 							(Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>) | ||||
| 						}, | ||||
| 						None if self.sync.is_major_importing() => { | ||||
| 							(None, Self::still_syncing(self.embeddable_on.clone())) | ||||
| 						}, | ||||
| 						None => { | ||||
| 							// This may happen when sync status changes in between
 | ||||
| 							// `contains` and `to_handler`
 | ||||
| 							(None, Box::new(ContentHandler::error( | ||||
| 								StatusCode::NotFound, | ||||
| 								"Resource Not Found", | ||||
| 								"Requested resource was not found.", | ||||
| 								None, | ||||
| 								self.embeddable_on.clone(), | ||||
| 							)) as Box<Handler>) | ||||
| 						}, | ||||
| 					} | ||||
| 				}, | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 		if let Some(status) = new_status { | ||||
| 			cache.clear_garbage(MAX_CACHED_DAPPS); | ||||
| 			cache.insert(content_id, status); | ||||
| 		} | ||||
| 
 | ||||
| 		handler | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum ValidationError { | ||||
| 	Io(io::Error), | ||||
| 	Zip(zip::result::ZipError), | ||||
| 	InvalidContentId, | ||||
| 	ManifestNotFound, | ||||
| 	ManifestSerialization(String), | ||||
| 	HashMismatch { expected: H256, got: H256, }, | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for ValidationError { | ||||
| 	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { | ||||
| 		match *self { | ||||
| 			ValidationError::Io(ref io) => write!(f, "Unexpected IO error occured: {:?}", io), | ||||
| 			ValidationError::Zip(ref zip) => write!(f, "Unable to read ZIP archive: {:?}", zip), | ||||
| 			ValidationError::InvalidContentId => write!(f, "ID is invalid. It should be 256 bits keccak hash of content."), | ||||
| 			ValidationError::ManifestNotFound => write!(f, "Downloaded Dapp bundle did not contain valid manifest.json file."), | ||||
| 			ValidationError::ManifestSerialization(ref err) => { | ||||
| 				write!(f, "There was an error during Dapp Manifest serialization: {:?}", err) | ||||
| 			}, | ||||
| 			ValidationError::HashMismatch { ref expected, ref got } => { | ||||
| 				write!(f, "Hash of downloaded content did not match. Expected:{:?}, Got:{:?}.", expected, got) | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl From<io::Error> for ValidationError { | ||||
| 	fn from(err: io::Error) -> Self { | ||||
| 		ValidationError::Io(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl From<zip::result::ZipError> for ValidationError { | ||||
| 	fn from(err: zip::result::ZipError) -> Self { | ||||
| 		ValidationError::Zip(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct ContentInstaller { | ||||
| 	id: String, | ||||
| 	mime: String, | ||||
| 	content_path: PathBuf, | ||||
| 	on_done: Box<Fn(Option<LocalPageEndpoint>) + Send>, | ||||
| } | ||||
| 
 | ||||
| impl ContentValidator for ContentInstaller { | ||||
| 	type Error = ValidationError; | ||||
| 
 | ||||
| 	fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, ValidationError> { | ||||
| 		let validate = || { | ||||
| 			// Create dir
 | ||||
| 			try!(fs::create_dir_all(&self.content_path)); | ||||
| 
 | ||||
| 			// Validate hash
 | ||||
| 			let mut file_reader = io::BufReader::new(try!(fs::File::open(&path))); | ||||
| 			let hash = try!(sha3(&mut file_reader)); | ||||
| 			let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId)); | ||||
| 			if id != hash { | ||||
| 				return Err(ValidationError::HashMismatch { | ||||
| 					expected: id, | ||||
| 					got: hash, | ||||
| 				}); | ||||
| 			} | ||||
| 
 | ||||
| 			// And prepare path for a file
 | ||||
| 			let filename = path.file_name().expect("We always fetch a file."); | ||||
| 			let mut content_path = self.content_path.clone(); | ||||
| 			content_path.push(&filename); | ||||
| 
 | ||||
| 			if content_path.exists() { | ||||
| 				try!(fs::remove_dir_all(&content_path)) | ||||
| 			} | ||||
| 
 | ||||
| 			try!(fs::copy(&path, &content_path)); | ||||
| 			Ok(LocalPageEndpoint::single_file(content_path, self.mime.clone(), PageCache::Enabled)) | ||||
| 		}; | ||||
| 
 | ||||
| 		// Make sure to always call on_done (even in case of errors)!
 | ||||
| 		let result = validate(); | ||||
| 		(self.on_done)(result.as_ref().ok().cloned()); | ||||
| 		result | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct DappInstaller { | ||||
| 	id: String, | ||||
| 	dapps_path: PathBuf, | ||||
| 	on_done: Box<Fn(Option<LocalPageEndpoint>) + Send>, | ||||
| 	embeddable_on: Option<(String, u16)>, | ||||
| } | ||||
| 
 | ||||
| impl DappInstaller { | ||||
| 	fn find_manifest(zip: &mut zip::ZipArchive<fs::File>) -> Result<(Manifest, PathBuf), ValidationError> { | ||||
| 		for i in 0..zip.len() { | ||||
| 			let mut file = try!(zip.by_index(i)); | ||||
| 
 | ||||
| 			if !file.name().ends_with(MANIFEST_FILENAME) { | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			// try to read manifest
 | ||||
| 			let mut manifest = String::new(); | ||||
| 			let manifest = file | ||||
| 				.read_to_string(&mut manifest).ok() | ||||
| 				.and_then(|_| deserialize_manifest(manifest).ok()); | ||||
| 
 | ||||
| 			if let Some(manifest) = manifest { | ||||
| 				let mut manifest_location = PathBuf::from(file.name()); | ||||
| 				manifest_location.pop(); // get rid of filename
 | ||||
| 				return Ok((manifest, manifest_location)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		Err(ValidationError::ManifestNotFound) | ||||
| 	} | ||||
| 
 | ||||
| 	fn dapp_target_path(&self, manifest: &Manifest) -> PathBuf { | ||||
| 		let mut target = self.dapps_path.clone(); | ||||
| 		target.push(&manifest.id); | ||||
| 		target | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl ContentValidator for DappInstaller { | ||||
| 	type Error = ValidationError; | ||||
| 
 | ||||
| 	fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, ValidationError> { | ||||
| 		trace!(target: "dapps", "Opening dapp bundle at {:?}", path); | ||||
| 		let validate = || { | ||||
| 			let mut file_reader = io::BufReader::new(try!(fs::File::open(path))); | ||||
| 			let hash = try!(sha3(&mut file_reader)); | ||||
| 			let id = try!(self.id.as_str().parse().map_err(|_| ValidationError::InvalidContentId)); | ||||
| 			if id != hash { | ||||
| 				return Err(ValidationError::HashMismatch { | ||||
| 					expected: id, | ||||
| 					got: hash, | ||||
| 				}); | ||||
| 			} | ||||
| 			let file = file_reader.into_inner(); | ||||
| 			// Unpack archive
 | ||||
| 			let mut zip = try!(zip::ZipArchive::new(file)); | ||||
| 			// First find manifest file
 | ||||
| 			let (mut manifest, manifest_dir) = try!(Self::find_manifest(&mut zip)); | ||||
| 			// Overwrite id to match hash
 | ||||
| 			manifest.id = self.id.clone(); | ||||
| 
 | ||||
| 			let target = self.dapp_target_path(&manifest); | ||||
| 
 | ||||
| 			// Remove old directory
 | ||||
| 			if target.exists() { | ||||
| 				warn!(target: "dapps", "Overwriting existing dapp: {}", manifest.id); | ||||
| 				try!(fs::remove_dir_all(target.clone())); | ||||
| 			} | ||||
| 
 | ||||
| 			// Unpack zip
 | ||||
| 			for i in 0..zip.len() { | ||||
| 				let mut file = try!(zip.by_index(i)); | ||||
| 				// TODO [todr] Check if it's consistent on windows.
 | ||||
| 				let is_dir = file.name().chars().rev().next() == Some('/'); | ||||
| 
 | ||||
| 				let file_path = PathBuf::from(file.name()); | ||||
| 				let location_in_manifest_base = file_path.strip_prefix(&manifest_dir); | ||||
| 				// Create files that are inside manifest directory
 | ||||
| 				if let Ok(location_in_manifest_base) = location_in_manifest_base { | ||||
| 					let p = target.join(location_in_manifest_base); | ||||
| 					// Check if it's a directory
 | ||||
| 					if is_dir { | ||||
| 						try!(fs::create_dir_all(p)); | ||||
| 					} else { | ||||
| 						let mut target = try!(fs::File::create(p)); | ||||
| 						try!(io::copy(&mut file, &mut target)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Write manifest
 | ||||
| 			let manifest_str = try!(serialize_manifest(&manifest).map_err(ValidationError::ManifestSerialization)); | ||||
| 			let manifest_path = target.join(MANIFEST_FILENAME); | ||||
| 			let mut manifest_file = try!(fs::File::create(manifest_path)); | ||||
| 			try!(manifest_file.write_all(manifest_str.as_bytes())); | ||||
| 			// Create endpoint
 | ||||
| 			let endpoint = LocalPageEndpoint::new(target, manifest.clone().into(), PageCache::Enabled, self.embeddable_on.clone()); | ||||
| 			Ok(endpoint) | ||||
| 		}; | ||||
| 
 | ||||
| 		let result = validate(); | ||||
| 		(self.on_done)(result.as_ref().ok().cloned()); | ||||
| 		result | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
| 	use std::env; | ||||
| 	use std::sync::Arc; | ||||
| 	use util::Bytes; | ||||
| 	use hash_fetch::urlhint::{URLHint, URLHintResult}; | ||||
| 
 | ||||
| 	use apps::cache::ContentStatus; | ||||
| 	use endpoint::EndpointInfo; | ||||
| 	use page::LocalPageEndpoint; | ||||
| 	use super::ContentFetcher; | ||||
| 
 | ||||
| 	struct FakeResolver; | ||||
| 	impl URLHint for FakeResolver { | ||||
| 		fn resolve(&self, _id: Bytes) -> Option<URLHintResult> { | ||||
| 			None | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	#[test] | ||||
| 	fn should_true_if_contains_the_app() { | ||||
| 		// given
 | ||||
| 		let path = env::temp_dir(); | ||||
| 		let fetcher = ContentFetcher::new(FakeResolver, Arc::new(|| false), None); | ||||
| 		let handler = LocalPageEndpoint::new(path, EndpointInfo { | ||||
| 			name: "fake".into(), | ||||
| 			description: "".into(), | ||||
| 			version: "".into(), | ||||
| 			author: "".into(), | ||||
| 			icon_url: "".into(), | ||||
| 		}, Default::default(), None); | ||||
| 
 | ||||
| 		// when
 | ||||
| 		fetcher.set_status("test", ContentStatus::Ready(handler)); | ||||
| 		fetcher.set_status("test2", ContentStatus::Fetching(Default::default())); | ||||
| 
 | ||||
| 		// then
 | ||||
| 		assert_eq!(fetcher.contains("test"), true); | ||||
| 		assert_eq!(fetcher.contains("test2"), true); | ||||
| 		assert_eq!(fetcher.contains("test3"), false); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										255
									
								
								dapps/src/apps/fetcher/installers.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								dapps/src/apps/fetcher/installers.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,255 @@ | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| 
 | ||||
| // Parity is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||
| // GNU General Public License for more details.
 | ||||
| 
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| use zip; | ||||
| use std::{fs, fmt}; | ||||
| use std::io::{self, Read, Write}; | ||||
| use std::path::PathBuf; | ||||
| use fetch::{self, Mime}; | ||||
| use util::H256; | ||||
| 
 | ||||
| use util::sha3::sha3; | ||||
| use page::{LocalPageEndpoint, PageCache}; | ||||
| use handlers::ContentValidator; | ||||
| use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; | ||||
| 
 | ||||
| type OnDone = Box<Fn(Option<LocalPageEndpoint>) + Send>; | ||||
| 
 | ||||
| fn write_response_and_check_hash( | ||||
| 	id: &str, | ||||
| 	mut content_path: PathBuf, | ||||
| 	filename: &str, | ||||
| 	response: fetch::Response | ||||
| ) -> Result<(fs::File, PathBuf), ValidationError> { | ||||
| 	// try to parse id
 | ||||
| 	let id = try!(id.parse().map_err(|_| ValidationError::InvalidContentId)); | ||||
| 
 | ||||
| 	// check if content exists
 | ||||
| 	if content_path.exists() { | ||||
| 		warn!(target: "dapps", "Overwriting existing content at 0x{:?}", id); | ||||
| 		try!(fs::remove_dir_all(&content_path)) | ||||
| 	} | ||||
| 
 | ||||
| 	// create directory
 | ||||
| 	try!(fs::create_dir_all(&content_path)); | ||||
| 
 | ||||
| 	// append filename
 | ||||
| 	content_path.push(filename); | ||||
| 
 | ||||
| 	// Now write the response
 | ||||
| 	let mut file = io::BufWriter::new(try!(fs::File::create(&content_path))); | ||||
| 	let mut reader = io::BufReader::new(response); | ||||
| 	try!(io::copy(&mut reader, &mut file)); | ||||
| 	try!(file.flush()); | ||||
| 
 | ||||
| 	// Validate hash
 | ||||
| 	// TODO [ToDr] calculate sha3 in-flight while reading the response
 | ||||
| 	let mut file = io::BufReader::new(try!(fs::File::open(&content_path))); | ||||
| 	let hash = try!(sha3(&mut file)); | ||||
| 	if id == hash { | ||||
| 		Ok((file.into_inner(), content_path)) | ||||
| 	} else { | ||||
| 		Err(ValidationError::HashMismatch { | ||||
| 			expected: id, | ||||
| 			got: hash, | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub struct Content { | ||||
| 	id: String, | ||||
| 	mime: Mime, | ||||
| 	content_path: PathBuf, | ||||
| 	on_done: OnDone, | ||||
| } | ||||
| 
 | ||||
| impl Content { | ||||
| 	pub fn new(id: String, mime: Mime, content_path: PathBuf, on_done: OnDone) -> Self { | ||||
| 		Content { | ||||
| 			id: id, | ||||
| 			mime: mime, | ||||
| 			content_path: content_path, | ||||
| 			on_done: on_done, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl ContentValidator for Content { | ||||
| 	type Error = ValidationError; | ||||
| 
 | ||||
| 	fn validate_and_install(&self, response: fetch::Response) -> Result<LocalPageEndpoint, ValidationError> { | ||||
| 		let validate = |content_path: PathBuf| { | ||||
| 			// Create dir
 | ||||
| 			let (_, content_path) = try!(write_response_and_check_hash(self.id.as_str(), content_path.clone(), self.id.as_str(), response)); | ||||
| 
 | ||||
| 			Ok(LocalPageEndpoint::single_file(content_path, self.mime.clone(), PageCache::Enabled)) | ||||
| 		}; | ||||
| 
 | ||||
| 		// Prepare path for a file
 | ||||
| 		let content_path = self.content_path.join(&self.id); | ||||
| 		// Make sure to always call on_done (even in case of errors)!
 | ||||
| 		let result = validate(content_path.clone()); | ||||
| 		// remove the file if there was an error
 | ||||
| 		if result.is_err() { | ||||
| 			// Ignore errors since the file might not exist
 | ||||
| 			let _ = fs::remove_dir_all(&content_path); | ||||
| 		} | ||||
| 		(self.on_done)(result.as_ref().ok().cloned()); | ||||
| 		result | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub struct Dapp { | ||||
| 	id: String, | ||||
| 	dapps_path: PathBuf, | ||||
| 	on_done: OnDone, | ||||
| 	embeddable_on: Option<(String, u16)>, | ||||
| } | ||||
| 
 | ||||
| impl Dapp { | ||||
| 	pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, embeddable_on: Option<(String, u16)>) -> Self { | ||||
| 		Dapp { | ||||
| 			id: id, | ||||
| 			dapps_path: dapps_path, | ||||
| 			on_done: on_done, | ||||
| 			embeddable_on: embeddable_on, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn find_manifest(zip: &mut zip::ZipArchive<fs::File>) -> Result<(Manifest, PathBuf), ValidationError> { | ||||
| 		for i in 0..zip.len() { | ||||
| 			let mut file = try!(zip.by_index(i)); | ||||
| 
 | ||||
| 			if !file.name().ends_with(MANIFEST_FILENAME) { | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			// try to read manifest
 | ||||
| 			let mut manifest = String::new(); | ||||
| 			let manifest = file | ||||
| 				.read_to_string(&mut manifest).ok() | ||||
| 				.and_then(|_| deserialize_manifest(manifest).ok()); | ||||
| 
 | ||||
| 			if let Some(manifest) = manifest { | ||||
| 				let mut manifest_location = PathBuf::from(file.name()); | ||||
| 				manifest_location.pop(); // get rid of filename
 | ||||
| 				return Ok((manifest, manifest_location)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		Err(ValidationError::ManifestNotFound) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl ContentValidator for Dapp { | ||||
| 	type Error = ValidationError; | ||||
| 
 | ||||
| 	fn validate_and_install(&self, response: fetch::Response) -> Result<LocalPageEndpoint, ValidationError> { | ||||
| 		let validate = |dapp_path: PathBuf| { | ||||
| 			let (file, zip_path) = try!(write_response_and_check_hash(self.id.as_str(), dapp_path.clone(), &format!("{}.zip", self.id), response)); | ||||
| 			trace!(target: "dapps", "Opening dapp bundle at {:?}", zip_path); | ||||
| 			// Unpack archive
 | ||||
| 			let mut zip = try!(zip::ZipArchive::new(file)); | ||||
| 			// First find manifest file
 | ||||
| 			let (mut manifest, manifest_dir) = try!(Self::find_manifest(&mut zip)); | ||||
| 			// Overwrite id to match hash
 | ||||
| 			manifest.id = self.id.clone(); | ||||
| 
 | ||||
| 			// Unpack zip
 | ||||
| 			for i in 0..zip.len() { | ||||
| 				let mut file = try!(zip.by_index(i)); | ||||
| 				let is_dir = file.name().chars().rev().next() == Some('/'); | ||||
| 
 | ||||
| 				let file_path = PathBuf::from(file.name()); | ||||
| 				let location_in_manifest_base = file_path.strip_prefix(&manifest_dir); | ||||
| 				// Create files that are inside manifest directory
 | ||||
| 				if let Ok(location_in_manifest_base) = location_in_manifest_base { | ||||
| 					let p = dapp_path.join(location_in_manifest_base); | ||||
| 					// Check if it's a directory
 | ||||
| 					if is_dir { | ||||
| 						try!(fs::create_dir_all(p)); | ||||
| 					} else { | ||||
| 						let mut target = try!(fs::File::create(p)); | ||||
| 						try!(io::copy(&mut file, &mut target)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Remove zip
 | ||||
| 			try!(fs::remove_file(&zip_path)); | ||||
| 
 | ||||
| 			// Write manifest
 | ||||
| 			let manifest_str = try!(serialize_manifest(&manifest).map_err(ValidationError::ManifestSerialization)); | ||||
| 			let manifest_path = dapp_path.join(MANIFEST_FILENAME); | ||||
| 			let mut manifest_file = try!(fs::File::create(manifest_path)); | ||||
| 			try!(manifest_file.write_all(manifest_str.as_bytes())); | ||||
| 			// Create endpoint
 | ||||
| 			let endpoint = LocalPageEndpoint::new(dapp_path, manifest.clone().into(), PageCache::Enabled, self.embeddable_on.clone()); | ||||
| 			Ok(endpoint) | ||||
| 		}; | ||||
| 
 | ||||
| 		// Prepare directory for dapp
 | ||||
| 		let target = self.dapps_path.join(&self.id); | ||||
| 		// Validate the dapp
 | ||||
| 		let result = validate(target.clone()); | ||||
| 		// remove the file if there was an error
 | ||||
| 		if result.is_err() { | ||||
| 			// Ignore errors since the file might not exist
 | ||||
| 			let _ = fs::remove_dir_all(&target); | ||||
| 		} | ||||
| 		(self.on_done)(result.as_ref().ok().cloned()); | ||||
| 		result | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum ValidationError { | ||||
| 	Io(io::Error), | ||||
| 	Zip(zip::result::ZipError), | ||||
| 	InvalidContentId, | ||||
| 	ManifestNotFound, | ||||
| 	ManifestSerialization(String), | ||||
| 	HashMismatch { expected: H256, got: H256, }, | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for ValidationError { | ||||
| 	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { | ||||
| 		match *self { | ||||
| 			ValidationError::Io(ref io) => write!(f, "Unexpected IO error occured: {:?}", io), | ||||
| 			ValidationError::Zip(ref zip) => write!(f, "Unable to read ZIP archive: {:?}", zip), | ||||
| 			ValidationError::InvalidContentId => write!(f, "ID is invalid. It should be 256 bits keccak hash of content."), | ||||
| 			ValidationError::ManifestNotFound => write!(f, "Downloaded Dapp bundle did not contain valid manifest.json file."), | ||||
| 			ValidationError::ManifestSerialization(ref err) => { | ||||
| 				write!(f, "There was an error during Dapp Manifest serialization: {:?}", err) | ||||
| 			}, | ||||
| 			ValidationError::HashMismatch { ref expected, ref got } => { | ||||
| 				write!(f, "Hash of downloaded content did not match. Expected:{:?}, Got:{:?}.", expected, got) | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl From<io::Error> for ValidationError { | ||||
| 	fn from(err: io::Error) -> Self { | ||||
| 		ValidationError::Io(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl From<zip::result::ZipError> for ValidationError { | ||||
| 	fn from(err: zip::result::ZipError) -> Self { | ||||
| 		ValidationError::Zip(err) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										265
									
								
								dapps/src/apps/fetcher/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								dapps/src/apps/fetcher/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,265 @@ | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| 
 | ||||
| // Parity is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||
| // GNU General Public License for more details.
 | ||||
| 
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| //! Fetchable Dapps support.
 | ||||
| //! Manages downloaded (cached) Dapps and downloads them when necessary.
 | ||||
| //! Uses `URLHint` to resolve addresses into Dapps bundle file location.
 | ||||
| 
 | ||||
| mod installers; | ||||
| 
 | ||||
| use std::{fs, env}; | ||||
| use std::path::PathBuf; | ||||
| use std::sync::Arc; | ||||
| use rustc_serialize::hex::FromHex; | ||||
| use fetch::{Client as FetchClient, Fetch}; | ||||
| use hash_fetch::urlhint::{URLHintContract, URLHint, URLHintResult}; | ||||
| use parity_reactor::Remote; | ||||
| 
 | ||||
| use hyper; | ||||
| use hyper::status::StatusCode; | ||||
| 
 | ||||
| use {SyncStatus, random_filename}; | ||||
| use util::Mutex; | ||||
| use page::LocalPageEndpoint; | ||||
| use handlers::{ContentHandler, ContentFetcherHandler}; | ||||
| use endpoint::{Endpoint, EndpointPath, Handler}; | ||||
| use apps::cache::{ContentCache, ContentStatus}; | ||||
| 
 | ||||
| /// Limit of cached dapps/content
 | ||||
| const MAX_CACHED_DAPPS: usize = 20; | ||||
| 
 | ||||
| pub trait Fetcher: Send + Sync + 'static { | ||||
| 	fn contains(&self, content_id: &str) -> bool; | ||||
| 
 | ||||
| 	fn to_async_handler(&self, path: EndpointPath, control: hyper::Control) -> Box<Handler>; | ||||
| } | ||||
| 
 | ||||
| pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + Send + Sync + 'static = URLHintContract> { | ||||
| 	dapps_path: PathBuf, | ||||
| 	resolver: R, | ||||
| 	cache: Arc<Mutex<ContentCache>>, | ||||
| 	sync: Arc<SyncStatus>, | ||||
| 	embeddable_on: Option<(String, u16)>, | ||||
| 	remote: Remote, | ||||
| 	fetch: F, | ||||
| } | ||||
| 
 | ||||
| impl<R: URLHint + Send + Sync + 'static, F: Fetch> Drop for ContentFetcher<F, R> { | ||||
| 	fn drop(&mut self) { | ||||
| 		// Clear cache path
 | ||||
| 		let _ = fs::remove_dir_all(&self.dapps_path); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<R: URLHint + Send + Sync + 'static, F: Fetch> ContentFetcher<F, R> { | ||||
| 
 | ||||
| 	pub fn new(resolver: R, sync_status: Arc<SyncStatus>, embeddable_on: Option<(String, u16)>, remote: Remote, fetch: F) -> Self { | ||||
| 		let mut dapps_path = env::temp_dir(); | ||||
| 		dapps_path.push(random_filename()); | ||||
| 
 | ||||
| 		ContentFetcher { | ||||
| 			dapps_path: dapps_path, | ||||
| 			resolver: resolver, | ||||
| 			sync: sync_status, | ||||
| 			cache: Arc::new(Mutex::new(ContentCache::default())), | ||||
| 			embeddable_on: embeddable_on, | ||||
| 			remote: remote, | ||||
| 			fetch: fetch, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn still_syncing(address: Option<(String, u16)>) -> Box<Handler> { | ||||
| 		Box::new(ContentHandler::error( | ||||
| 			StatusCode::ServiceUnavailable, | ||||
| 			"Sync In Progress", | ||||
| 			"Your node is still syncing. We cannot resolve any content before it's fully synced.", | ||||
| 			Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"), | ||||
| 			address, | ||||
| 		)) | ||||
| 	} | ||||
| 
 | ||||
| 	#[cfg(test)] | ||||
| 	fn set_status(&self, content_id: &str, status: ContentStatus) { | ||||
| 		self.cache.lock().insert(content_id.to_owned(), status); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<R: URLHint + Send + Sync + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> { | ||||
| 	fn contains(&self, content_id: &str) -> bool { | ||||
| 		{ | ||||
| 			let mut cache = self.cache.lock(); | ||||
| 			// Check if we already have the app
 | ||||
| 			if cache.get(content_id).is_some() { | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		// fallback to resolver
 | ||||
| 		if let Ok(content_id) = content_id.from_hex() { | ||||
| 			// else try to resolve the app_id
 | ||||
| 			let has_content = self.resolver.resolve(content_id).is_some(); | ||||
| 			// if there is content or we are syncing return true
 | ||||
| 			has_content || self.sync.is_major_importing() | ||||
| 		} else { | ||||
| 			false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn to_async_handler(&self, path: EndpointPath, control: hyper::Control) -> Box<Handler> { | ||||
| 		let mut cache = self.cache.lock(); | ||||
| 		let content_id = path.app_id.clone(); | ||||
| 
 | ||||
| 		let (new_status, handler) = { | ||||
| 			let status = cache.get(&content_id); | ||||
| 			match status { | ||||
| 				// Just serve the content
 | ||||
| 				Some(&mut ContentStatus::Ready(ref endpoint)) => { | ||||
| 					(None, endpoint.to_async_handler(path, control)) | ||||
| 				}, | ||||
| 				// Content is already being fetched
 | ||||
| 				Some(&mut ContentStatus::Fetching(ref fetch_control)) => { | ||||
| 					trace!(target: "dapps", "Content fetching in progress. Waiting..."); | ||||
| 					(None, fetch_control.to_async_handler(path, control)) | ||||
| 				}, | ||||
| 				// We need to start fetching the content
 | ||||
| 				None => { | ||||
| 					trace!(target: "dapps", "Content unavailable. Fetching... {:?}", content_id); | ||||
| 					let content_hex = content_id.from_hex().expect("to_handler is called only when `contains` returns true."); | ||||
| 					let content = self.resolver.resolve(content_hex); | ||||
| 
 | ||||
| 					let cache = self.cache.clone(); | ||||
| 					let id = content_id.clone(); | ||||
| 					let on_done = move |result: Option<LocalPageEndpoint>| { | ||||
| 						let mut cache = cache.lock(); | ||||
| 						match result { | ||||
| 							Some(endpoint) => cache.insert(id.clone(), ContentStatus::Ready(endpoint)), | ||||
| 							// In case of error
 | ||||
| 							None => cache.remove(&id), | ||||
| 						}; | ||||
| 					}; | ||||
| 
 | ||||
| 					match content { | ||||
| 						// Don't serve dapps if we are still syncing (but serve content)
 | ||||
| 						Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => { | ||||
| 							(None, Self::still_syncing(self.embeddable_on.clone())) | ||||
| 						}, | ||||
| 						Some(URLHintResult::Dapp(dapp)) => { | ||||
| 							let (handler, fetch_control) = ContentFetcherHandler::new( | ||||
| 								dapp.url(), | ||||
| 								path, | ||||
| 								control, | ||||
| 								installers::Dapp::new( | ||||
| 									content_id.clone(), | ||||
| 									self.dapps_path.clone(), | ||||
| 									Box::new(on_done), | ||||
| 									self.embeddable_on.clone(), | ||||
| 								), | ||||
| 								self.embeddable_on.clone(), | ||||
| 								self.remote.clone(), | ||||
| 								self.fetch.clone(), | ||||
| 							); | ||||
| 
 | ||||
| 							(Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>) | ||||
| 						}, | ||||
| 						Some(URLHintResult::Content(content)) => { | ||||
| 							let (handler, fetch_control) = ContentFetcherHandler::new( | ||||
| 								content.url, | ||||
| 								path, | ||||
| 								control, | ||||
| 								installers::Content::new( | ||||
| 									content_id.clone(), | ||||
| 									content.mime, | ||||
| 									self.dapps_path.clone(), | ||||
| 									Box::new(on_done), | ||||
| 								), | ||||
| 								self.embeddable_on.clone(), | ||||
| 								self.remote.clone(), | ||||
| 								self.fetch.clone(), | ||||
| 							); | ||||
| 
 | ||||
| 							(Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>) | ||||
| 						}, | ||||
| 						None if self.sync.is_major_importing() => { | ||||
| 							(None, Self::still_syncing(self.embeddable_on.clone())) | ||||
| 						}, | ||||
| 						None => { | ||||
| 							// This may happen when sync status changes in between
 | ||||
| 							// `contains` and `to_handler`
 | ||||
| 							(None, Box::new(ContentHandler::error( | ||||
| 								StatusCode::NotFound, | ||||
| 								"Resource Not Found", | ||||
| 								"Requested resource was not found.", | ||||
| 								None, | ||||
| 								self.embeddable_on.clone(), | ||||
| 							)) as Box<Handler>) | ||||
| 						}, | ||||
| 					} | ||||
| 				}, | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 		if let Some(status) = new_status { | ||||
| 			cache.clear_garbage(MAX_CACHED_DAPPS); | ||||
| 			cache.insert(content_id, status); | ||||
| 		} | ||||
| 
 | ||||
| 		handler | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
| 	use std::env; | ||||
| 	use std::sync::Arc; | ||||
| 	use util::Bytes; | ||||
| 	use fetch::Client; | ||||
| 	use hash_fetch::urlhint::{URLHint, URLHintResult}; | ||||
| 	use parity_reactor::Remote; | ||||
| 
 | ||||
| 	use apps::cache::ContentStatus; | ||||
| 	use endpoint::EndpointInfo; | ||||
| 	use page::LocalPageEndpoint; | ||||
| 	use super::{ContentFetcher, Fetcher}; | ||||
| 
 | ||||
| 	struct FakeResolver; | ||||
| 	impl URLHint for FakeResolver { | ||||
| 		fn resolve(&self, _id: Bytes) -> Option<URLHintResult> { | ||||
| 			None | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	#[test] | ||||
| 	fn should_true_if_contains_the_app() { | ||||
| 		// given
 | ||||
| 		let path = env::temp_dir(); | ||||
| 		let fetcher = ContentFetcher::new(FakeResolver, Arc::new(|| false), None, Remote::new_sync(), Client::new().unwrap()); | ||||
| 		let handler = LocalPageEndpoint::new(path, EndpointInfo { | ||||
| 			name: "fake".into(), | ||||
| 			description: "".into(), | ||||
| 			version: "".into(), | ||||
| 			author: "".into(), | ||||
| 			icon_url: "".into(), | ||||
| 		}, Default::default(), None); | ||||
| 
 | ||||
| 		// when
 | ||||
| 		fetcher.set_status("test", ContentStatus::Ready(handler)); | ||||
| 		fetcher.set_status("test2", ContentStatus::Fetching(Default::default())); | ||||
| 
 | ||||
| 		// then
 | ||||
| 		assert_eq!(fetcher.contains("test"), true); | ||||
| 		assert_eq!(fetcher.contains("test2"), true); | ||||
| 		assert_eq!(fetcher.contains("test3"), false); | ||||
| 	} | ||||
| } | ||||
| @ -17,7 +17,10 @@ | ||||
| use endpoint::{Endpoints, Endpoint}; | ||||
| use page::PageEndpoint; | ||||
| use proxypac::ProxyPac; | ||||
| use web::Web; | ||||
| use fetch::Fetch; | ||||
| use parity_dapps::WebApp; | ||||
| use parity_reactor::Remote; | ||||
| 
 | ||||
| mod cache; | ||||
| mod fs; | ||||
| @ -31,18 +34,20 @@ pub const DAPPS_DOMAIN : &'static str = ".parity"; | ||||
| pub const RPC_PATH: &'static str =  "rpc"; | ||||
| pub const API_PATH: &'static str =  "api"; | ||||
| pub const UTILS_PATH: &'static str =  "parity-utils"; | ||||
| pub const WEB_PATH: &'static str = "web"; | ||||
| 
 | ||||
| pub fn utils() -> Box<Endpoint> { | ||||
| 	Box::new(PageEndpoint::with_prefix(parity_ui::App::default(), UTILS_PATH.to_owned())) | ||||
| } | ||||
| 
 | ||||
| pub fn all_endpoints(dapps_path: String, signer_address: Option<(String, u16)>) -> Endpoints { | ||||
| pub fn all_endpoints<F: Fetch>(dapps_path: String, signer_address: Option<(String, u16)>, remote: Remote, fetch: F) -> Endpoints { | ||||
| 	// fetch fs dapps at first to avoid overwriting builtins
 | ||||
| 	let mut pages = fs::local_endpoints(dapps_path, signer_address.clone()); | ||||
| 
 | ||||
| 	// NOTE [ToDr] Dapps will be currently embeded on 8180
 | ||||
| 	insert::<parity_ui::App>(&mut pages, "ui", Embeddable::Yes(signer_address.clone())); | ||||
| 	pages.insert("proxy".into(), ProxyPac::boxed(signer_address)); | ||||
| 	pages.insert(WEB_PATH.into(), Web::boxed(remote, fetch)); | ||||
| 
 | ||||
| 	pages | ||||
| } | ||||
|  | ||||
| @ -16,13 +16,14 @@ | ||||
| 
 | ||||
| //! Hyper Server Handler that fetches a file during a request (proxy).
 | ||||
| 
 | ||||
| use std::{fs, fmt}; | ||||
| use std::path::PathBuf; | ||||
| use std::fmt; | ||||
| use std::sync::{mpsc, Arc}; | ||||
| use std::sync::atomic::{AtomicBool, Ordering}; | ||||
| use std::time::{Instant, Duration}; | ||||
| use fetch::{self, Fetch}; | ||||
| use futures::Future; | ||||
| use parity_reactor::Remote; | ||||
| use util::Mutex; | ||||
| use fetch::{Client, Fetch, FetchResult}; | ||||
| 
 | ||||
| use hyper::{server, Decoder, Encoder, Next, Method, Control}; | ||||
| use hyper::net::HttpStream; | ||||
| @ -39,7 +40,7 @@ enum FetchState { | ||||
| 	Waiting, | ||||
| 	NotStarted(String), | ||||
| 	Error(ContentHandler), | ||||
| 	InProgress(mpsc::Receiver<FetchResult>), | ||||
| 	InProgress(mpsc::Receiver<FetchState>), | ||||
| 	Done(LocalPageEndpoint, Box<PageHandlerWaiting>), | ||||
| } | ||||
| 
 | ||||
| @ -48,10 +49,10 @@ enum WaitResult { | ||||
| 	Done(LocalPageEndpoint), | ||||
| } | ||||
| 
 | ||||
| pub trait ContentValidator { | ||||
| pub trait ContentValidator: Send + 'static { | ||||
| 	type Error: fmt::Debug + fmt::Display; | ||||
| 
 | ||||
| 	fn validate_and_install(&self, path: PathBuf) -> Result<LocalPageEndpoint, Self::Error>; | ||||
| 	fn validate_and_install(&self, fetch::Response) -> Result<LocalPageEndpoint, Self::Error>; | ||||
| } | ||||
| 
 | ||||
| pub struct FetchControl { | ||||
| @ -160,33 +161,36 @@ impl server::Handler<HttpStream> for WaitingHandler { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub struct ContentFetcherHandler<H: ContentValidator> { | ||||
| pub struct ContentFetcherHandler<H: ContentValidator, F: Fetch> { | ||||
| 	fetch_control: Arc<FetchControl>, | ||||
| 	control: Option<Control>, | ||||
| 	control: Control, | ||||
| 	remote: Remote, | ||||
| 	status: FetchState, | ||||
| 	client: Option<Client>, | ||||
| 	installer: H, | ||||
| 	fetch: F, | ||||
| 	installer: Option<H>, | ||||
| 	path: EndpointPath, | ||||
| 	uri: RequestUri, | ||||
| 	embeddable_on: Option<(String, u16)>, | ||||
| } | ||||
| 
 | ||||
| impl<H: ContentValidator> ContentFetcherHandler<H> { | ||||
| impl<H: ContentValidator, F: Fetch> ContentFetcherHandler<H, F> { | ||||
| 	pub fn new( | ||||
| 		url: String, | ||||
| 		path: EndpointPath, | ||||
| 		control: Control, | ||||
| 		handler: H, | ||||
| 		embeddable_on: Option<(String, u16)>, | ||||
| 		remote: Remote, | ||||
| 		fetch: F, | ||||
| 	) -> (Self, Arc<FetchControl>) { | ||||
| 		let fetch_control = Arc::new(FetchControl::default()); | ||||
| 		let client = Client::default(); | ||||
| 		let handler = ContentFetcherHandler { | ||||
| 			fetch_control: fetch_control.clone(), | ||||
| 			control: Some(control), | ||||
| 			client: Some(client), | ||||
| 			control: control, | ||||
| 			remote: remote, | ||||
| 			fetch: fetch, | ||||
| 			status: FetchState::NotStarted(url), | ||||
| 			installer: handler, | ||||
| 			installer: Some(handler), | ||||
| 			path: path, | ||||
| 			uri: RequestUri::default(), | ||||
| 			embeddable_on: embeddable_on, | ||||
| @ -195,41 +199,74 @@ impl<H: ContentValidator> ContentFetcherHandler<H> { | ||||
| 		(handler, fetch_control) | ||||
| 	} | ||||
| 
 | ||||
| 	fn close_client(client: &mut Option<Client>) { | ||||
| 		client.take() | ||||
| 			.expect("After client is closed we are going into write, hence we can never close it again") | ||||
| 			.close(); | ||||
| 	} | ||||
| 	fn fetch_content(&self, url: &str, installer: H) -> mpsc::Receiver<FetchState> { | ||||
| 		let (tx, rx) = mpsc::channel(); | ||||
| 		let abort = self.fetch_control.abort.clone(); | ||||
| 
 | ||||
| 	fn fetch_content(client: &mut Client, url: &str, abort: Arc<AtomicBool>, control: Control) -> Result<mpsc::Receiver<FetchResult>, String> { | ||||
| 		client.request(url, abort, Box::new(move || { | ||||
| 			trace!(target: "dapps", "Fetching finished."); | ||||
| 		let control = self.control.clone(); | ||||
| 		let embeddable_on = self.embeddable_on.clone(); | ||||
| 		let uri = self.uri.clone(); | ||||
| 		let path = self.path.clone(); | ||||
| 
 | ||||
| 		let future = self.fetch.fetch_with_abort(url, abort.into()).then(move |result| { | ||||
| 			trace!(target: "dapps", "Fetching content finished. Starting validation: {:?}", result); | ||||
| 			let new_state = match result { | ||||
| 				Ok(response) => match installer.validate_and_install(response) { | ||||
| 					Ok(endpoint) => { | ||||
| 						trace!(target: "dapps", "Validation OK. Returning response."); | ||||
| 						let mut handler = endpoint.to_page_handler(path); | ||||
| 						handler.set_uri(&uri); | ||||
| 						FetchState::Done(endpoint, handler) | ||||
| 					}, | ||||
| 					Err(e) => { | ||||
| 						trace!(target: "dapps", "Error while validating content: {:?}", e); | ||||
| 						FetchState::Error(ContentHandler::error( | ||||
| 							StatusCode::BadGateway, | ||||
| 							"Invalid Dapp", | ||||
| 							"Downloaded bundle does not contain a valid content.", | ||||
| 							Some(&format!("{:?}", e)), | ||||
| 							embeddable_on, | ||||
| 						)) | ||||
| 					}, | ||||
| 				}, | ||||
| 				Err(e) => { | ||||
| 					warn!(target: "dapps", "Unable to fetch content: {:?}", e); | ||||
| 					FetchState::Error(ContentHandler::error( | ||||
| 						StatusCode::BadGateway, | ||||
| 						"Download Error", | ||||
| 						"There was an error when fetching the content.", | ||||
| 						Some(&format!("{:?}", e)), | ||||
| 						embeddable_on, | ||||
| 					)) | ||||
| 				}, | ||||
| 			}; | ||||
| 			// Content may be resolved when the connection is already dropped.
 | ||||
| 			let _ = tx.send(new_state); | ||||
| 			// Ignoring control errors
 | ||||
| 			let _ = control.ready(Next::read()); | ||||
| 		})).map_err(|e| format!("{:?}", e)) | ||||
| 			Ok(()) as Result<(), ()> | ||||
| 		}); | ||||
| 
 | ||||
| 		// make sure to run within fetch thread pool.
 | ||||
| 		let future = self.fetch.process(future); | ||||
| 		// spawn to event loop
 | ||||
| 		self.remote.spawn(future); | ||||
| 
 | ||||
| 		rx | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<H> { | ||||
| impl<H: ContentValidator, F: Fetch> server::Handler<HttpStream> for ContentFetcherHandler<H, F> { | ||||
| 	fn on_request(&mut self, request: server::Request<HttpStream>) -> Next { | ||||
| 		self.uri = request.uri().clone(); | ||||
| 		let installer = self.installer.take().expect("Installer always set initialy; installer used only in on_request; on_request invoked only once; qed"); | ||||
| 		let status = if let FetchState::NotStarted(ref url) = self.status { | ||||
| 			Some(match *request.method() { | ||||
| 				// Start fetching content
 | ||||
| 				Method::Get => { | ||||
| 					trace!(target: "dapps", "Fetching content from: {:?}", url); | ||||
| 					let control = self.control.take().expect("on_request is called only once, thus control is always Some"); | ||||
| 					let client = self.client.as_mut().expect("on_request is called before client is closed."); | ||||
| 					let fetch = Self::fetch_content(client, url, self.fetch_control.abort.clone(), control); | ||||
| 					match fetch { | ||||
| 						Ok(receiver) => FetchState::InProgress(receiver), | ||||
| 						Err(e) => FetchState::Error(ContentHandler::error( | ||||
| 							StatusCode::BadGateway, | ||||
| 							"Unable To Start Content Download", | ||||
| 							"Could not initialize download of the content. It might be a problem with the remote server.", | ||||
| 							Some(&format!("{}", e)), | ||||
| 							self.embeddable_on.clone(), | ||||
| 						)), | ||||
| 					} | ||||
| 					let receiver = self.fetch_content(url, installer); | ||||
| 					FetchState::InProgress(receiver) | ||||
| 				}, | ||||
| 				// or return error
 | ||||
| 				_ => FetchState::Error(ContentHandler::error( | ||||
| @ -246,7 +283,6 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler< | ||||
| 			self.fetch_control.set_status(&status); | ||||
| 			self.status = status; | ||||
| 		} | ||||
| 		self.uri = request.uri().clone(); | ||||
| 
 | ||||
| 		Next::read() | ||||
| 	} | ||||
| @ -263,50 +299,14 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler< | ||||
| 					None, | ||||
| 					self.embeddable_on.clone(), | ||||
| 				); | ||||
| 				Self::close_client(&mut self.client); | ||||
| 				(Some(FetchState::Error(timeout)), Next::write()) | ||||
| 			}, | ||||
| 			FetchState::InProgress(ref receiver) => { | ||||
| 				// Check if there is an answer
 | ||||
| 				let rec = receiver.try_recv(); | ||||
| 				match rec { | ||||
| 					// Unpack and validate
 | ||||
| 					Ok(Ok(path)) => { | ||||
| 						trace!(target: "dapps", "Fetching content finished. Starting validation ({:?})", path); | ||||
| 						Self::close_client(&mut self.client); | ||||
| 						// Unpack and verify
 | ||||
| 						let state = match self.installer.validate_and_install(path.clone()) { | ||||
| 							Err(e) => { | ||||
| 								trace!(target: "dapps", "Error while validating content: {:?}", e); | ||||
| 								FetchState::Error(ContentHandler::error( | ||||
| 									StatusCode::BadGateway, | ||||
| 									"Invalid Dapp", | ||||
| 									"Downloaded bundle does not contain a valid content.", | ||||
| 									Some(&format!("{:?}", e)), | ||||
| 									self.embeddable_on.clone(), | ||||
| 								)) | ||||
| 							}, | ||||
| 							Ok(endpoint) => { | ||||
| 								let mut handler = endpoint.to_page_handler(self.path.clone()); | ||||
| 								handler.set_uri(&self.uri); | ||||
| 								FetchState::Done(endpoint, handler) | ||||
| 							}, | ||||
| 						}; | ||||
| 						// Remove temporary zip file
 | ||||
| 						let _ = fs::remove_file(path); | ||||
| 						(Some(state), Next::write()) | ||||
| 					}, | ||||
| 					Ok(Err(e)) => { | ||||
| 						warn!(target: "dapps", "Unable to fetch content: {:?}", e); | ||||
| 						let error = ContentHandler::error( | ||||
| 							StatusCode::BadGateway, | ||||
| 							"Download Error", | ||||
| 							"There was an error when fetching the content.", | ||||
| 							Some(&format!("{:?}", e)), | ||||
| 							self.embeddable_on.clone(), | ||||
| 						); | ||||
| 						(Some(FetchState::Error(error)), Next::write()) | ||||
| 					}, | ||||
| 					// just return the new state
 | ||||
| 					Ok(state) => (Some(state), Next::write()), | ||||
| 					// wait some more
 | ||||
| 					_ => (None, Next::wait()) | ||||
| 				} | ||||
|  | ||||
| @ -61,6 +61,9 @@ extern crate parity_hash_fetch as hash_fetch; | ||||
| extern crate linked_hash_map; | ||||
| extern crate fetch; | ||||
| extern crate parity_dapps_glue as parity_dapps; | ||||
| extern crate futures; | ||||
| extern crate parity_reactor; | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate log; | ||||
| #[macro_use] | ||||
| @ -81,6 +84,7 @@ mod rpc; | ||||
| mod api; | ||||
| mod proxypac; | ||||
| mod url; | ||||
| mod web; | ||||
| #[cfg(test)] | ||||
| mod tests; | ||||
| 
 | ||||
| @ -89,9 +93,11 @@ use std::net::SocketAddr; | ||||
| use std::collections::HashMap; | ||||
| 
 | ||||
| use hash_fetch::urlhint::ContractClient; | ||||
| use fetch::{Fetch, Client as FetchClient}; | ||||
| use jsonrpc_core::{IoHandler, IoDelegate}; | ||||
| use router::auth::{Authorization, NoAuth, HttpBasicAuth}; | ||||
| use ethcore_rpc::Extendable; | ||||
| use parity_reactor::Remote; | ||||
| 
 | ||||
| use self::apps::{HOME_PAGE, DAPPS_DOMAIN}; | ||||
| 
 | ||||
| @ -112,6 +118,8 @@ pub struct ServerBuilder { | ||||
| 	registrar: Arc<ContractClient>, | ||||
| 	sync_status: Arc<SyncStatus>, | ||||
| 	signer_address: Option<(String, u16)>, | ||||
| 	remote: Remote, | ||||
| 	fetch: Option<FetchClient>, | ||||
| } | ||||
| 
 | ||||
| impl Extendable for ServerBuilder { | ||||
| @ -122,16 +130,23 @@ impl Extendable for ServerBuilder { | ||||
| 
 | ||||
| impl ServerBuilder { | ||||
| 	/// Construct new dapps server
 | ||||
| 	pub fn new(dapps_path: String, registrar: Arc<ContractClient>) -> Self { | ||||
| 	pub fn new(dapps_path: String, registrar: Arc<ContractClient>, remote: Remote) -> Self { | ||||
| 		ServerBuilder { | ||||
| 			dapps_path: dapps_path, | ||||
| 			handler: Arc::new(IoHandler::new()), | ||||
| 			registrar: registrar, | ||||
| 			sync_status: Arc::new(|| false), | ||||
| 			signer_address: None, | ||||
| 			remote: remote, | ||||
| 			fetch: None, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/// Set a fetch client to use.
 | ||||
| 	pub fn with_fetch(&mut self, fetch: FetchClient) { | ||||
| 		self.fetch = Some(fetch); | ||||
| 	} | ||||
| 
 | ||||
| 	/// Change default sync status.
 | ||||
| 	pub fn with_sync_status(&mut self, status: Arc<SyncStatus>) { | ||||
| 		self.sync_status = status; | ||||
| @ -154,6 +169,8 @@ impl ServerBuilder { | ||||
| 			self.signer_address.clone(), | ||||
| 			self.registrar.clone(), | ||||
| 			self.sync_status.clone(), | ||||
| 			self.remote.clone(), | ||||
| 			try!(self.fetch()), | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
| @ -169,8 +186,17 @@ impl ServerBuilder { | ||||
| 			self.signer_address.clone(), | ||||
| 			self.registrar.clone(), | ||||
| 			self.sync_status.clone(), | ||||
| 			self.remote.clone(), | ||||
| 			try!(self.fetch()), | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
| 	fn fetch(&self) -> Result<FetchClient, ServerError> { | ||||
| 		match self.fetch.clone() { | ||||
| 			Some(fetch) => Ok(fetch), | ||||
| 			None => FetchClient::new().map_err(|_| ServerError::FetchInitialization), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Webapps HTTP server.
 | ||||
| @ -206,7 +232,7 @@ impl Server { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn start_http<A: Authorization + 'static>( | ||||
| 	fn start_http<A: Authorization + 'static, F: Fetch>( | ||||
| 		addr: &SocketAddr, | ||||
| 		hosts: Option<Vec<String>>, | ||||
| 		authorization: A, | ||||
| @ -215,11 +241,19 @@ impl Server { | ||||
| 		signer_address: Option<(String, u16)>, | ||||
| 		registrar: Arc<ContractClient>, | ||||
| 		sync_status: Arc<SyncStatus>, | ||||
| 		remote: Remote, | ||||
| 		fetch: F, | ||||
| 	) -> Result<Server, ServerError> { | ||||
| 		let panic_handler = Arc::new(Mutex::new(None)); | ||||
| 		let authorization = Arc::new(authorization); | ||||
| 		let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(hash_fetch::urlhint::URLHintContract::new(registrar), sync_status, signer_address.clone())); | ||||
| 		let endpoints = Arc::new(apps::all_endpoints(dapps_path, signer_address.clone())); | ||||
| 		let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( | ||||
| 			hash_fetch::urlhint::URLHintContract::new(registrar), | ||||
| 			sync_status, | ||||
| 			signer_address.clone(), | ||||
| 			remote.clone(), | ||||
| 			fetch.clone(), | ||||
| 		)); | ||||
| 		let endpoints = Arc::new(apps::all_endpoints(dapps_path, signer_address.clone(), remote.clone(), fetch.clone())); | ||||
| 		let cors_domains = Self::cors_domains(signer_address.clone()); | ||||
| 
 | ||||
| 		let special = Arc::new({ | ||||
| @ -287,6 +321,8 @@ pub enum ServerError { | ||||
| 	IoError(std::io::Error), | ||||
| 	/// Other `hyper` error
 | ||||
| 	Other(hyper::error::Error), | ||||
| 	/// Fetch service initialization error
 | ||||
| 	FetchInitialization, | ||||
| } | ||||
| 
 | ||||
| impl From<hyper::error::Error> for ServerError { | ||||
| @ -299,7 +335,7 @@ impl From<hyper::error::Error> for ServerError { | ||||
| } | ||||
| 
 | ||||
| /// Random filename
 | ||||
| pub fn random_filename() -> String { | ||||
| fn random_filename() -> String { | ||||
| 	use ::rand::Rng; | ||||
| 	let mut rng = ::rand::OsRng::new().unwrap(); | ||||
| 	rng.gen_ascii_chars().take(12).collect() | ||||
|  | ||||
| @ -20,11 +20,12 @@ use std::fs; | ||||
| use std::path::{Path, PathBuf}; | ||||
| use page::handler::{self, PageCache, PageHandlerWaiting}; | ||||
| use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; | ||||
| use mime::Mime; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct LocalPageEndpoint { | ||||
| 	path: PathBuf, | ||||
| 	mime: Option<String>, | ||||
| 	mime: Option<Mime>, | ||||
| 	info: Option<EndpointInfo>, | ||||
| 	cache: PageCache, | ||||
| 	embeddable_on: Option<(String, u16)>, | ||||
| @ -41,7 +42,7 @@ impl LocalPageEndpoint { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn single_file(path: PathBuf, mime: String, cache: PageCache) -> Self { | ||||
| 	pub fn single_file(path: PathBuf, mime: Mime, cache: PageCache) -> Self { | ||||
| 		LocalPageEndpoint { | ||||
| 			path: path, | ||||
| 			mime: Some(mime), | ||||
| @ -55,9 +56,9 @@ impl LocalPageEndpoint { | ||||
| 		self.path.clone() | ||||
| 	} | ||||
| 
 | ||||
| 	fn page_handler_with_mime(&self, path: EndpointPath, mime: &str) -> handler::PageHandler<LocalSingleFile> { | ||||
| 	fn page_handler_with_mime(&self, path: EndpointPath, mime: &Mime) -> handler::PageHandler<LocalSingleFile> { | ||||
| 		handler::PageHandler { | ||||
| 			app: LocalSingleFile { path: self.path.clone(), mime: mime.into() }, | ||||
| 			app: LocalSingleFile { path: self.path.clone(), mime: format!("{}", mime) }, | ||||
| 			prefix: None, | ||||
| 			path: path, | ||||
| 			file: handler::ServedFile::new(None), | ||||
|  | ||||
| @ -27,7 +27,7 @@ use url::{Url, Host}; | ||||
| use hyper::{self, server, Next, Encoder, Decoder, Control, StatusCode}; | ||||
| use hyper::net::HttpStream; | ||||
| use apps::{self, DAPPS_DOMAIN}; | ||||
| use apps::fetcher::ContentFetcher; | ||||
| use apps::fetcher::Fetcher; | ||||
| use endpoint::{Endpoint, Endpoints, EndpointPath}; | ||||
| use handlers::{Redirection, extract_url, ContentHandler}; | ||||
| use self::auth::{Authorization, Authorized}; | ||||
| @ -45,7 +45,7 @@ pub struct Router<A: Authorization + 'static> { | ||||
| 	control: Option<Control>, | ||||
| 	signer_address: Option<(String, u16)>, | ||||
| 	endpoints: Arc<Endpoints>, | ||||
| 	fetch: Arc<ContentFetcher>, | ||||
| 	fetch: Arc<Fetcher>, | ||||
| 	special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>, | ||||
| 	authorization: Arc<A>, | ||||
| 	allowed_hosts: Option<Vec<String>>, | ||||
| @ -169,7 +169,7 @@ impl<A: Authorization> Router<A> { | ||||
| 	pub fn new( | ||||
| 		control: Control, | ||||
| 		signer_address: Option<(String, u16)>, | ||||
| 		content_fetcher: Arc<ContentFetcher>, | ||||
| 		content_fetcher: Arc<Fetcher>, | ||||
| 		endpoints: Arc<Endpoints>, | ||||
| 		special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>, | ||||
| 		authorization: Arc<A>, | ||||
|  | ||||
| @ -25,6 +25,7 @@ use Server; | ||||
| use hash_fetch::urlhint::ContractClient; | ||||
| use util::{Bytes, Address, Mutex, ToPretty}; | ||||
| use devtools::http_client; | ||||
| use parity_reactor::Remote; | ||||
| 
 | ||||
| const REGISTRAR: &'static str = "8e4e9b13d4b45cb0befc93c3061b1408f67316b2"; | ||||
| const URLHINT: &'static str = "deadbeefcafe0000000000000000000000000000"; | ||||
| @ -74,7 +75,7 @@ pub fn init_server(hosts: Option<Vec<String>>, is_syncing: bool) -> (Server, Arc | ||||
| 	let registrar = Arc::new(FakeRegistrar::new()); | ||||
| 	let mut dapps_path = env::temp_dir(); | ||||
| 	dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading"); | ||||
| 	let mut builder = ServerBuilder::new(dapps_path.to_str().unwrap().into(), registrar.clone()); | ||||
| 	let mut builder = ServerBuilder::new(dapps_path.to_str().unwrap().into(), registrar.clone(), Remote::new_sync()); | ||||
| 	builder.with_sync_status(Arc::new(move || is_syncing)); | ||||
| 	builder.with_signer_address(Some(("127.0.0.1".into(), SIGNER_PORT))); | ||||
| 	( | ||||
| @ -88,7 +89,7 @@ pub fn serve_with_auth(user: &str, pass: &str) -> Server { | ||||
| 	let registrar = Arc::new(FakeRegistrar::new()); | ||||
| 	let mut dapps_path = env::temp_dir(); | ||||
| 	dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading"); | ||||
| 	let mut builder = ServerBuilder::new(dapps_path.to_str().unwrap().into(), registrar); | ||||
| 	let mut builder = ServerBuilder::new(dapps_path.to_str().unwrap().into(), registrar.clone(), Remote::new_sync()); | ||||
| 	builder.with_signer_address(Some(("127.0.0.1".into(), SIGNER_PORT))); | ||||
| 	builder.start_basic_auth_http(&"127.0.0.1:0".parse().unwrap(), None, user, pass).unwrap() | ||||
| } | ||||
|  | ||||
							
								
								
									
										180
									
								
								dapps/src/web.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								dapps/src/web.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,180 @@ | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| 
 | ||||
| // Parity is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||
| // GNU General Public License for more details.
 | ||||
| 
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| //! Serving web-based content (proxying)
 | ||||
| 
 | ||||
| use endpoint::{Endpoint, Handler, EndpointPath}; | ||||
| use handlers::{ContentFetcherHandler, ContentHandler, ContentValidator, Redirection, extract_url}; | ||||
| use page::{LocalPageEndpoint}; | ||||
| use fetch::{self, Fetch}; | ||||
| use url::Url; | ||||
| use hyper::{self, server, net, Next, Encoder, Decoder}; | ||||
| use hyper::status::StatusCode; | ||||
| use parity_reactor::Remote; | ||||
| use apps::WEB_PATH; | ||||
| 
 | ||||
| pub struct Web<F> { | ||||
| 	remote: Remote, | ||||
| 	fetch: F, | ||||
| } | ||||
| 
 | ||||
| impl<F: Fetch> Web<F> { | ||||
| 	pub fn boxed(remote: Remote, fetch: F) -> Box<Endpoint> { | ||||
| 		Box::new(Web { | ||||
| 			remote: remote, | ||||
| 			fetch: fetch, | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<F: Fetch> Endpoint for Web<F> { | ||||
| 	fn to_async_handler(&self, path: EndpointPath, control: hyper::Control) -> Box<Handler> { | ||||
| 		Box::new(WebHandler { | ||||
| 			control: control, | ||||
| 			state: State::Initial, | ||||
| 			path: path, | ||||
| 			remote: self.remote.clone(), | ||||
| 			fetch: self.fetch.clone(), | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub struct WebInstaller; | ||||
| 
 | ||||
| impl ContentValidator for WebInstaller { | ||||
| 	type Error = String; | ||||
| 
 | ||||
| 	fn validate_and_install(&self, _response: fetch::Response) -> Result<LocalPageEndpoint, String> { | ||||
| 		// let path = unimplemented!();
 | ||||
| 		// let mime = response.content_type().unwrap_or(mime!(Text/Html));
 | ||||
| 		// Ok(LocalPageEndpoint::single_file(path, mime, PageCache::Enabled))
 | ||||
| 		Err("unimplemented".into()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| enum State<F: Fetch> { | ||||
| 	Initial, | ||||
| 	Error(ContentHandler), | ||||
| 	Redirecting(Redirection), | ||||
| 	Fetching(ContentFetcherHandler<WebInstaller, F>), | ||||
| } | ||||
| 
 | ||||
| struct WebHandler<F: Fetch> { | ||||
| 	control: hyper::Control, | ||||
| 	state: State<F>, | ||||
| 	path: EndpointPath, | ||||
| 	remote: Remote, | ||||
| 	fetch: F, | ||||
| } | ||||
| 
 | ||||
| impl<F: Fetch> WebHandler<F> { | ||||
| 	fn extract_target_url(url: Option<Url>) -> Result<String, State<F>> { | ||||
| 		let path = match url { | ||||
| 			Some(url) => url.path, | ||||
| 			None => { | ||||
| 				return Err(State::Error( | ||||
| 					ContentHandler::error(StatusCode::BadRequest, "Invalid URL", "Couldn't parse URL", None, None) | ||||
| 				)); | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 		// TODO [ToDr] Check if token supplied in URL is correct.
 | ||||
| 
 | ||||
| 		// Support domain based routing.
 | ||||
| 		let idx = match path.get(0).map(|m| m.as_ref()) { | ||||
| 			Some(WEB_PATH) => 1, | ||||
| 			_ => 0, | ||||
| 		}; | ||||
| 
 | ||||
| 		// Validate protocol
 | ||||
| 		let protocol = match path.get(idx).map(|a| a.as_str()) { | ||||
| 			Some("http") => "http", | ||||
| 			Some("https") => "https", | ||||
| 			_ => { | ||||
| 				return Err(State::Error( | ||||
| 					ContentHandler::error(StatusCode::BadRequest, "Invalid Protocol", "Invalid protocol used", None, None) | ||||
| 				)); | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 		// Redirect if address to main page does not end with /
 | ||||
| 		if let None = path.get(idx + 2) { | ||||
| 			return Err(State::Redirecting( | ||||
| 				Redirection::new(&format!("/{}/", path.join("/"))) | ||||
| 			)); | ||||
| 		} | ||||
| 
 | ||||
| 		Ok(format!("{}://{}", protocol, path[2..].join("/"))) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<F: Fetch> server::Handler<net::HttpStream> for WebHandler<F> { | ||||
| 	fn on_request(&mut self, request: server::Request<net::HttpStream>) -> Next { | ||||
| 		let url = extract_url(&request); | ||||
| 
 | ||||
| 		// First extract the URL (reject invalid URLs)
 | ||||
| 		let target_url = match Self::extract_target_url(url) { | ||||
| 			Ok(url) => url, | ||||
| 			Err(error) => { | ||||
| 				self.state = error; | ||||
| 				return Next::write(); | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
| 		let (mut handler, _control) = ContentFetcherHandler::new( | ||||
| 			target_url, | ||||
| 			self.path.clone(), | ||||
| 			self.control.clone(), | ||||
| 			WebInstaller, | ||||
| 			None, | ||||
| 			self.remote.clone(), | ||||
| 			self.fetch.clone(), | ||||
| 		); | ||||
| 		let res = handler.on_request(request); | ||||
| 		self.state = State::Fetching(handler); | ||||
| 
 | ||||
| 		res | ||||
| 	} | ||||
| 
 | ||||
| 	fn on_request_readable(&mut self, decoder: &mut Decoder<net::HttpStream>) -> Next { | ||||
| 		match self.state { | ||||
| 			State::Initial => Next::end(), | ||||
| 			State::Error(ref mut handler) => handler.on_request_readable(decoder), | ||||
| 			State::Redirecting(ref mut handler) => handler.on_request_readable(decoder), | ||||
| 			State::Fetching(ref mut handler) => handler.on_request_readable(decoder), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn on_response(&mut self, res: &mut server::Response) -> Next { | ||||
| 		match self.state { | ||||
| 			State::Initial => Next::end(), | ||||
| 			State::Error(ref mut handler) => handler.on_response(res), | ||||
| 			State::Redirecting(ref mut handler) => handler.on_response(res), | ||||
| 			State::Fetching(ref mut handler) => handler.on_response(res), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn on_response_writable(&mut self, encoder: &mut Encoder<net::HttpStream>) -> Next { | ||||
| 		match self.state { | ||||
| 			State::Initial => Next::end(), | ||||
| 			State::Error(ref mut handler) => handler.on_response_writable(encoder), | ||||
| 			State::Redirecting(ref mut handler) => handler.on_response_writable(encoder), | ||||
| 			State::Fetching(ref mut handler) => handler.on_response_writable(encoder), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -20,7 +20,7 @@ use util::H256; | ||||
| 
 | ||||
| /// Either a hash or a number.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum HashOrNumber { | ||||
| 	/// Block hash variant.
 | ||||
| 	Hash(H256), | ||||
| @ -42,7 +42,7 @@ impl From<u64> for HashOrNumber { | ||||
| 
 | ||||
| /// A request for block headers.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Headers { | ||||
| 	/// Starting block number or hash.
 | ||||
| 	pub start: HashOrNumber, | ||||
| @ -56,7 +56,7 @@ pub struct Headers { | ||||
| 
 | ||||
| /// A request for specific block bodies.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Bodies { | ||||
| 	/// Hashes which bodies are being requested for.
 | ||||
| 	pub block_hashes: Vec<H256> | ||||
| @ -67,7 +67,7 @@ pub struct Bodies { | ||||
| /// This request is answered with a list of transaction receipts for each block
 | ||||
| /// requested.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Receipts { | ||||
| 	/// Block hashes to return receipts for.
 | ||||
| 	pub block_hashes: Vec<H256>, | ||||
| @ -75,7 +75,7 @@ pub struct Receipts { | ||||
| 
 | ||||
| /// A request for a state proof
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct StateProof { | ||||
| 	/// Block hash to query state from.
 | ||||
| 	pub block: H256, | ||||
| @ -90,7 +90,7 @@ pub struct StateProof { | ||||
| 
 | ||||
| /// A request for state proofs.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct StateProofs { | ||||
| 	/// All the proof requests.
 | ||||
| 	pub requests: Vec<StateProof>, | ||||
| @ -98,7 +98,7 @@ pub struct StateProofs { | ||||
| 
 | ||||
| /// A request for contract code.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct ContractCode { | ||||
| 	/// Block hash
 | ||||
| 	pub block_hash: H256, | ||||
| @ -108,7 +108,7 @@ pub struct ContractCode { | ||||
| 
 | ||||
| /// A request for contract code.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct ContractCodes { | ||||
| 	/// Block hash and account key (== sha3(address)) pairs to fetch code for.
 | ||||
| 	pub code_requests: Vec<ContractCode>, | ||||
| @ -116,7 +116,7 @@ pub struct ContractCodes { | ||||
| 
 | ||||
| /// A request for a header proof from the Canonical Hash Trie.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct HeaderProof { | ||||
| 	/// Number of the CHT.
 | ||||
| 	pub cht_number: u64, | ||||
| @ -128,7 +128,7 @@ pub struct HeaderProof { | ||||
| 
 | ||||
| /// A request for header proofs from the CHT.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct HeaderProofs { | ||||
| 	/// All the proof requests.
 | ||||
| 	pub requests: Vec<HeaderProof>, | ||||
| @ -136,7 +136,7 @@ pub struct HeaderProofs { | ||||
| 
 | ||||
| /// Kinds of requests.
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum Kind { | ||||
| 	/// Requesting headers.
 | ||||
| 	Headers, | ||||
| @ -154,7 +154,7 @@ pub enum Kind { | ||||
| 
 | ||||
| /// Encompasses all possible types of requests in a single structure.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", derive(Binary))] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum Request { | ||||
| 	/// Requesting headers.
 | ||||
| 	Headers(Headers), | ||||
|  | ||||
| @ -17,7 +17,6 @@ | ||||
| //! Types used in the public (IPC) api which require custom code generation.
 | ||||
| #![cfg_attr(feature = "ipc", allow(dead_code, unused_assignments, unused_variables))] // codegen issues
 | ||||
| 
 | ||||
| 
 | ||||
| #[cfg(feature = "ipc")] | ||||
| include!(concat!(env!("OUT_DIR"), "/mod.rs.in")); | ||||
| 
 | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| 		"maximumExtraDataSize": "0x20", | ||||
| 		"minGasLimit": "0x1388", | ||||
| 		"networkID" : "0x1", | ||||
| 		"chainID": "0x3d", | ||||
| 		"forkBlock": "0x1d4c00", | ||||
| 		"forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" | ||||
| 	}, | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| 		"maximumExtraDataSize": "0x20", | ||||
| 		"minGasLimit": "0x1388", | ||||
| 		"networkID" : "0x2", | ||||
| 		"chainID": "0x3e", | ||||
| 		"forkBlock": "0x1b34d8", | ||||
| 		"forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145" | ||||
| 	}, | ||||
|  | ||||
| @ -167,7 +167,7 @@ impl Engine for Ethash { | ||||
| 
 | ||||
| 	fn signing_network_id(&self, env_info: &EnvInfo) -> Option<u64> { | ||||
| 		if env_info.number >= self.ethash_params.eip155_transition { | ||||
| 			Some(self.params().network_id) | ||||
| 			Some(self.params().chain_id) | ||||
| 		} else { | ||||
| 			None | ||||
| 		} | ||||
| @ -316,7 +316,7 @@ impl Engine for Ethash { | ||||
| 		} | ||||
| 
 | ||||
| 		if let Some(n) = t.network_id() { | ||||
| 			if header.number() < self.ethash_params.eip155_transition || n != self.params().network_id { | ||||
| 			if header.number() < self.ethash_params.eip155_transition || n != self.params().chain_id { | ||||
| 				return Err(TransactionError::InvalidNetworkId.into()) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @ -38,6 +38,8 @@ pub struct CommonParams { | ||||
| 	pub maximum_extra_data_size: usize, | ||||
| 	/// Network id.
 | ||||
| 	pub network_id: u64, | ||||
| 	/// Chain id.
 | ||||
| 	pub chain_id: u64, | ||||
| 	/// Main subprotocol name.
 | ||||
| 	pub subprotocol_name: String, | ||||
| 	/// Minimum gas limit.
 | ||||
| @ -52,6 +54,7 @@ impl From<ethjson::spec::Params> for CommonParams { | ||||
| 			account_start_nonce: p.account_start_nonce.into(), | ||||
| 			maximum_extra_data_size: p.maximum_extra_data_size.into(), | ||||
| 			network_id: p.network_id.into(), | ||||
| 			chain_id: if let Some(n) = p.chain_id { n.into() } else { p.network_id.into() }, | ||||
| 			subprotocol_name: p.subprotocol_name.unwrap_or_else(|| "eth".to_owned()), | ||||
| 			min_gas_limit: p.min_gas_limit.into(), | ||||
| 			fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None }, | ||||
|  | ||||
| @ -22,7 +22,8 @@ use std::collections::BTreeMap; | ||||
| use util::{U256, H256, Uint, Bytes}; | ||||
| use ipc::binary::BinaryConvertable; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Eq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// Diff type for specifying a change (or not).
 | ||||
| pub enum Diff<T> where T: Eq + BinaryConvertable { | ||||
| 	/// Both sides are the same.
 | ||||
| @ -49,7 +50,8 @@ impl<T> Diff<T> where T: Eq + BinaryConvertable { | ||||
| 	pub fn is_same(&self) -> bool { match *self { Diff::Same => true, _ => false }} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Eq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// Account diff.
 | ||||
| pub struct AccountDiff { | ||||
| 	/// Change in balance, allowed to be `Diff::Same`.
 | ||||
| @ -62,7 +64,8 @@ pub struct AccountDiff { | ||||
| 	pub storage: BTreeMap<H256, Diff<H256>>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Eq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// Change in existance type.
 | ||||
| // TODO: include other types of change.
 | ||||
| pub enum Existance { | ||||
|  | ||||
| @ -20,7 +20,8 @@ use error::{ImportError, BlockError, Error}; | ||||
| use std::convert::From; | ||||
| 
 | ||||
| /// Error dedicated to import block function
 | ||||
| #[derive(Binary, Debug)] | ||||
| #[derive(Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum BlockImportError { | ||||
| 	/// Import error
 | ||||
| 	Import(ImportError), | ||||
|  | ||||
| @ -18,7 +18,8 @@ | ||||
| use verification::queue::Status as QueueStatus; | ||||
| 
 | ||||
| /// General block status
 | ||||
| #[derive(Debug, Eq, PartialEq, Binary)] | ||||
| #[derive(Debug, Eq, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum BlockStatus { | ||||
| 	/// Part of the blockchain.
 | ||||
| 	InChain, | ||||
|  | ||||
| @ -21,7 +21,8 @@ use header::BlockNumber; | ||||
| use types::security_level::SecurityLevel; | ||||
| 
 | ||||
| /// Information about the blockchain gathered together.
 | ||||
| #[derive(Clone, Debug, Binary)] | ||||
| #[derive(Clone, Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct BlockChainInfo { | ||||
| 	/// Blockchain difficulty.
 | ||||
| 	pub total_difficulty: U256, | ||||
|  | ||||
| @ -17,7 +17,8 @@ | ||||
| //! Call analytics related types
 | ||||
| 
 | ||||
| /// Options concerning what analytics we run on the call.
 | ||||
| #[derive(Eq, PartialEq, Default, Clone, Copy, Debug, Binary)] | ||||
| #[derive(Eq, PartialEq, Default, Clone, Copy, Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct CallAnalytics { | ||||
| 	/// Make a transaction trace.
 | ||||
| 	pub transaction_tracing: bool, | ||||
|  | ||||
| @ -24,7 +24,8 @@ use types::state_diff::StateDiff; | ||||
| use std::fmt; | ||||
| 
 | ||||
| /// The type of the call-like instruction.
 | ||||
| #[derive(Debug, PartialEq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum CallType { | ||||
| 	/// Not a CALL.
 | ||||
| 	None, | ||||
| @ -61,7 +62,8 @@ impl Decodable for CallType { | ||||
| } | ||||
| 
 | ||||
| /// Transaction execution receipt.
 | ||||
| #[derive(Debug, PartialEq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Executed { | ||||
| 	/// Gas paid up front for execution of transaction.
 | ||||
| 	pub gas: U256, | ||||
| @ -101,7 +103,8 @@ pub struct Executed { | ||||
| } | ||||
| 
 | ||||
| /// Result of executing the transaction.
 | ||||
| #[derive(PartialEq, Debug, Clone, Binary)] | ||||
| #[derive(PartialEq, Debug, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum ExecutionError { | ||||
| 	/// Returned when there gas paid for transaction execution is
 | ||||
| 	/// lower than base gas required.
 | ||||
| @ -168,7 +171,8 @@ impl fmt::Display for ExecutionError { | ||||
| } | ||||
| 
 | ||||
| /// Result of executing the transaction.
 | ||||
| #[derive(PartialEq, Debug, Clone, Binary)] | ||||
| #[derive(PartialEq, Debug, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum CallError { | ||||
| 	/// Couldn't find the transaction in the chain.
 | ||||
| 	TransactionNotFound, | ||||
|  | ||||
| @ -22,7 +22,8 @@ use client::BlockId; | ||||
| use log_entry::LogEntry; | ||||
| 
 | ||||
| /// Blockchain Filter.
 | ||||
| #[derive(Binary, Debug, PartialEq)] | ||||
| #[derive(Debug, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Filter { | ||||
| 	/// Blockchain will be searched from this block.
 | ||||
| 	pub from_block: BlockId, | ||||
|  | ||||
| @ -20,7 +20,8 @@ use util::hash::H256; | ||||
| use header::BlockNumber; | ||||
| 
 | ||||
| /// Uniquely identifies block.
 | ||||
| #[derive(Debug, PartialEq, Copy, Clone, Hash, Eq, Binary)] | ||||
| #[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum BlockId { | ||||
| 	/// Block's sha3.
 | ||||
| 	/// Querying by hash is always faster.
 | ||||
| @ -36,7 +37,8 @@ pub enum BlockId { | ||||
| } | ||||
| 
 | ||||
| /// Uniquely identifies transaction.
 | ||||
| #[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)] | ||||
| #[derive(Debug, PartialEq, Clone, Hash, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum TransactionId { | ||||
| 	/// Transaction's sha3.
 | ||||
| 	Hash(H256), | ||||
| @ -46,7 +48,7 @@ pub enum TransactionId { | ||||
| } | ||||
| 
 | ||||
| /// Uniquely identifies Trace.
 | ||||
| #[derive(Binary)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct TraceId { | ||||
| 	/// Transaction
 | ||||
| 	pub transaction: TransactionId, | ||||
| @ -55,7 +57,8 @@ pub struct TraceId { | ||||
| } | ||||
| 
 | ||||
| /// Uniquely identifies Uncle.
 | ||||
| #[derive(Debug, PartialEq, Eq, Copy, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Eq, Copy, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct UncleId { | ||||
| 	/// Block id.
 | ||||
| 	pub block: BlockId, | ||||
|  | ||||
| @ -26,7 +26,8 @@ use header::BlockNumber; | ||||
| use ethjson; | ||||
| 
 | ||||
| /// A record of execution for a `LOG` operation.
 | ||||
| #[derive(Default, Debug, Clone, PartialEq, Eq, Binary)] | ||||
| #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct LogEntry { | ||||
| 	/// The address of the contract executing at the point of the `LOG` operation.
 | ||||
| 	pub address: Address, | ||||
| @ -81,7 +82,8 @@ impl From<ethjson::state::Log> for LogEntry { | ||||
| } | ||||
| 
 | ||||
| /// Log localized in a blockchain.
 | ||||
| #[derive(Default, Debug, PartialEq, Clone, Binary)] | ||||
| #[derive(Default, Debug, PartialEq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct LocalizedLogEntry { | ||||
| 	/// Plain log entry.
 | ||||
| 	pub entry: LogEntry, | ||||
|  | ||||
| @ -16,5 +16,10 @@ | ||||
| 
 | ||||
| //! Types used in the public api
 | ||||
| 
 | ||||
| #![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
 | ||||
| #![cfg_attr(feature = "ipc", allow(dead_code, unused_assignments, unused_variables))] // codegen issues
 | ||||
| 
 | ||||
| #[cfg(feature = "ipc")] | ||||
| include!(concat!(env!("OUT_DIR"), "/mod.rs.in")); | ||||
| 
 | ||||
| #[cfg(not(feature = "ipc"))] | ||||
| include!("mod.rs.in"); | ||||
|  | ||||
| @ -20,7 +20,8 @@ pub use std::time::Duration; | ||||
| use client::Mode as ClientMode; | ||||
| 
 | ||||
| /// IPC-capable shadow-type for `client::config::Mode`
 | ||||
| #[derive(Clone, Binary, Debug)] | ||||
| #[derive(Clone, Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum Mode { | ||||
| 	/// Same as `ClientMode::Off`.
 | ||||
| 	Off, | ||||
|  | ||||
| @ -21,7 +21,8 @@ | ||||
| //! of which portions of the ancient chain and current state trie are stored as well.
 | ||||
| 
 | ||||
| /// Client pruning info. See module-level docs for more details.
 | ||||
| #[derive(Debug, Clone, Binary)] | ||||
| #[derive(Debug, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct PruningInfo { | ||||
| 	/// The first block which everything can be served after.
 | ||||
| 	pub earliest_chain: u64, | ||||
|  | ||||
| @ -25,7 +25,8 @@ use header::BlockNumber; | ||||
| use log_entry::{LogEntry, LocalizedLogEntry}; | ||||
| 
 | ||||
| /// Information describing execution of a transaction.
 | ||||
| #[derive(Default, Debug, Clone, Binary)] | ||||
| #[derive(Default, Debug, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Receipt { | ||||
| 	/// The state root after executing the transaction.
 | ||||
| 	pub state_root: H256, | ||||
| @ -79,7 +80,8 @@ impl HeapSizeOf for Receipt { | ||||
| } | ||||
| 
 | ||||
| /// Receipt with additional info.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct RichReceipt { | ||||
| 	/// Transaction hash.
 | ||||
| 	pub transaction_hash: H256, | ||||
| @ -100,7 +102,8 @@ pub struct RichReceipt { | ||||
| } | ||||
| 
 | ||||
| /// Receipt with additional info.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct LocalizedReceipt { | ||||
| 	/// Transaction hash.
 | ||||
| 	pub transaction_hash: H256, | ||||
|  | ||||
| @ -17,7 +17,8 @@ | ||||
| //! Restoration status type definition
 | ||||
| 
 | ||||
| /// Statuses for restorations.
 | ||||
| #[derive(PartialEq, Eq, Clone, Copy, Debug, Binary)] | ||||
| #[derive(PartialEq, Eq, Clone, Copy, Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum RestorationStatus { | ||||
| 	///	No restoration.
 | ||||
| 	Inactive, | ||||
|  | ||||
| @ -19,7 +19,8 @@ | ||||
| use header::BlockNumber; | ||||
| 
 | ||||
| /// Indication of how secure the chain is.
 | ||||
| #[derive(Debug, PartialEq, Copy, Clone, Hash, Eq, Binary)] | ||||
| #[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum SecurityLevel { | ||||
| 	/// All blocks from genesis to chain head are known to have valid state transitions and PoW.
 | ||||
| 	FullState, | ||||
|  | ||||
| @ -21,7 +21,8 @@ use rlp::*; | ||||
| use util::Bytes; | ||||
| 
 | ||||
| /// Manifest data.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct ManifestData { | ||||
| 	/// List of state chunk hashes.
 | ||||
| 	pub state_hashes: Vec<H256>, | ||||
|  | ||||
| @ -22,7 +22,8 @@ use std::collections::BTreeMap; | ||||
| use util::Address; | ||||
| use account_diff::*; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Eq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// Expression for the delta between two system states. Encoded the
 | ||||
| /// delta of every altered account.
 | ||||
| pub struct StateDiff { | ||||
|  | ||||
| @ -21,7 +21,7 @@ use util::{Address}; | ||||
| use types::ids::BlockId; | ||||
| 
 | ||||
| /// Easy to use trace filter.
 | ||||
| #[derive(Binary)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Filter { | ||||
| 	/// Range of filtering.
 | ||||
| 	pub range: Range<BlockId>, | ||||
|  | ||||
| @ -21,7 +21,8 @@ use rlp::{Encodable, RlpStream, Decodable, Decoder, DecoderError, Stream, View}; | ||||
| use evm::Error as EvmError; | ||||
| 
 | ||||
| /// Trace evm errors.
 | ||||
| #[derive(Debug, PartialEq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum Error { | ||||
| 	/// `OutOfGas` is returned when transaction execution runs out of gas.
 | ||||
| 	OutOfGas, | ||||
|  | ||||
| @ -28,7 +28,8 @@ use types::trace_types::trace::{Action, Res}; | ||||
| /// Addresses filter.
 | ||||
| ///
 | ||||
| /// Used to create bloom possibilities and match filters.
 | ||||
| #[derive(Debug, Binary)] | ||||
| #[derive(Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct AddressesFilter { | ||||
| 	list: Vec<Address> | ||||
| } | ||||
| @ -74,7 +75,8 @@ impl AddressesFilter { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Binary)] | ||||
| #[derive(Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// Traces filter.
 | ||||
| pub struct Filter { | ||||
| 	/// Block range.
 | ||||
|  | ||||
| @ -25,7 +25,8 @@ use super::trace::{Action, Res}; | ||||
| /// Trace localized in vector of traces produced by a single transaction.
 | ||||
| ///
 | ||||
| /// Parent and children indexes refer to positions in this vector.
 | ||||
| #[derive(Debug, PartialEq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct FlatTrace { | ||||
| 	/// Type of action performed by a transaction.
 | ||||
| 	pub action: Action, | ||||
|  | ||||
| @ -21,7 +21,8 @@ use super::trace::{Action, Res}; | ||||
| use header::BlockNumber; | ||||
| 
 | ||||
| /// Localized trace.
 | ||||
| #[derive(Debug, PartialEq, Clone, Binary)] | ||||
| #[derive(Debug, PartialEq, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct LocalizedTrace { | ||||
| 	/// Type of action performed by a transaction.
 | ||||
| 	pub action: Action, | ||||
|  | ||||
| @ -27,7 +27,8 @@ use types::executed::CallType; | ||||
| use super::error::Error; | ||||
| 
 | ||||
| /// `Call` result.
 | ||||
| #[derive(Debug, Clone, PartialEq, Default, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq, Default)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct CallResult { | ||||
| 	/// Gas used by call.
 | ||||
| 	pub gas_used: U256, | ||||
| @ -56,7 +57,8 @@ impl Decodable for CallResult { | ||||
| } | ||||
| 
 | ||||
| /// `Create` result.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct CreateResult { | ||||
| 	/// Gas used by create.
 | ||||
| 	pub gas_used: U256, | ||||
| @ -96,7 +98,8 @@ impl CreateResult { | ||||
| } | ||||
| 
 | ||||
| /// Description of a _call_ action, either a `CALL` operation or a message transction.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Call { | ||||
| 	/// The sending account.
 | ||||
| 	pub from: Address, | ||||
| @ -163,7 +166,8 @@ impl Call { | ||||
| } | ||||
| 
 | ||||
| /// Description of a _create_ action, either a `CREATE` operation or a create transction.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Create { | ||||
| 	/// The address of the creator.
 | ||||
| 	pub from: Address, | ||||
| @ -219,7 +223,8 @@ impl Create { | ||||
| } | ||||
| 
 | ||||
| /// Suicide action.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Suicide { | ||||
| 	/// Suicided address.
 | ||||
| 	pub address: Address, | ||||
| @ -261,7 +266,8 @@ impl Decodable for Suicide { | ||||
| 
 | ||||
| 
 | ||||
| /// Description of an action that we trace; will be either a call or a create.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum Action { | ||||
| 	/// It's a call action.
 | ||||
| 	Call(Call), | ||||
| @ -316,7 +322,8 @@ impl Action { | ||||
| } | ||||
| 
 | ||||
| /// The result of the performed action.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum Res { | ||||
| 	/// Successful call action result.
 | ||||
| 	Call(CallResult), | ||||
| @ -386,7 +393,8 @@ impl Res { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// A diff of some chunk of memory.
 | ||||
| pub struct MemoryDiff { | ||||
| 	/// Offset into memory the change begins.
 | ||||
| @ -413,7 +421,8 @@ impl Decodable for MemoryDiff { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// A diff of some storage value.
 | ||||
| pub struct StorageDiff { | ||||
| 	/// Which key in storage is changed.
 | ||||
| @ -440,7 +449,8 @@ impl Decodable for StorageDiff { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// A record of an executed VM operation.
 | ||||
| pub struct VMExecutedOperation { | ||||
| 	/// The total gas used.
 | ||||
| @ -475,7 +485,8 @@ impl Decodable for VMExecutedOperation { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary, Default)] | ||||
| #[derive(Debug, Clone, PartialEq, Default)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// A record of the execution of a single VM operation.
 | ||||
| pub struct VMOperation { | ||||
| 	/// The program counter.
 | ||||
| @ -512,7 +523,8 @@ impl Decodable for VMOperation { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary, Default)] | ||||
| #[derive(Debug, Clone, PartialEq, Default)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// A record of a full VM trace for a CALL/CREATE.
 | ||||
| pub struct VMTrace { | ||||
| 	/// The step (i.e. index into operations) at which this trace corresponds.
 | ||||
|  | ||||
| @ -27,7 +27,8 @@ use evm::Schedule; | ||||
| use header::BlockNumber; | ||||
| use ethjson; | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| /// Transaction action type.
 | ||||
| pub enum Action { | ||||
| 	/// Create creates new contract.
 | ||||
| @ -54,7 +55,8 @@ impl Decodable for Action { | ||||
| 
 | ||||
| /// A set of information describing an externally-originating message call
 | ||||
| /// or contract creation operation.
 | ||||
| #[derive(Default, Debug, Clone, PartialEq, Eq, Binary)] | ||||
| #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct Transaction { | ||||
| 	/// Nonce.
 | ||||
| 	pub nonce: U256, | ||||
| @ -205,7 +207,8 @@ impl Transaction { | ||||
| } | ||||
| 
 | ||||
| /// Signed transaction information.
 | ||||
| #[derive(Debug, Clone, Eq, Binary)] | ||||
| #[derive(Debug, Clone, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct SignedTransaction { | ||||
| 	/// Plain Transaction.
 | ||||
| 	unsigned: Transaction, | ||||
| @ -370,7 +373,8 @@ impl SignedTransaction { | ||||
| } | ||||
| 
 | ||||
| /// Signed Transaction that is a part of canon blockchain.
 | ||||
| #[derive(Debug, PartialEq, Eq, Binary)] | ||||
| #[derive(Debug, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct LocalizedTransaction { | ||||
| 	/// Signed part.
 | ||||
| 	pub signed: SignedTransaction, | ||||
| @ -391,7 +395,8 @@ impl Deref for LocalizedTransaction { | ||||
| } | ||||
| 
 | ||||
| /// Queued transaction with additional information.
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct PendingTransaction { | ||||
| 	/// Signed transaction data.
 | ||||
| 	pub transaction: SignedTransaction, | ||||
| @ -495,14 +500,14 @@ fn should_agree_with_vitalik() { | ||||
| 		flushln!("networkid: {:?}", signed.network_id()); | ||||
| 	}; | ||||
| 
 | ||||
| 	test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce") | ||||
| 	test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112") | ||||
| 	test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be") | ||||
| 	test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0") | ||||
| 	test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554") | ||||
| 	test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4") | ||||
| 	test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35") | ||||
| 	test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332") | ||||
| 	test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029") | ||||
| 	test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f") | ||||
| 	test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"); | ||||
| 	test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112"); | ||||
| 	test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be"); | ||||
| 	test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0"); | ||||
| 	test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554"); | ||||
| 	test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4"); | ||||
| 	test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35"); | ||||
| 	test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332"); | ||||
| 	test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029"); | ||||
| 	test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"); | ||||
| } | ||||
|  | ||||
| @ -31,7 +31,8 @@ pub enum TransactionImportResult { | ||||
| binary_fixed_size!(TransactionImportResult); | ||||
| 
 | ||||
| /// Api-level error for transaction import
 | ||||
| #[derive(Debug, Clone, Binary)] | ||||
| #[derive(Debug, Clone)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub enum TransactionImportError { | ||||
| 	/// Transaction error
 | ||||
| 	Transaction(TransactionError), | ||||
|  | ||||
| @ -19,7 +19,8 @@ | ||||
| use util::H256; | ||||
| 
 | ||||
| /// Represents a tree route between `from` block and `to` block:
 | ||||
| #[derive(Debug, Binary)] | ||||
| #[derive(Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct TreeRoute { | ||||
| 	/// A vector of hashes of all blocks, ordered from `from` to `to`.
 | ||||
| 	pub blocks: Vec<H256>, | ||||
|  | ||||
| @ -17,7 +17,8 @@ | ||||
| //! Verification queue info types
 | ||||
| 
 | ||||
| /// Verification queue status
 | ||||
| #[derive(Debug, Binary)] | ||||
| #[derive(Debug)] | ||||
| #[cfg_attr(feature = "ipc", binary)] | ||||
| pub struct VerificationQueueInfo { | ||||
| 	/// Number of queued items pending verification
 | ||||
| 	pub unverified_queue_size: usize, | ||||
|  | ||||
| @ -5,6 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"] | ||||
| build = "build.rs" | ||||
| 
 | ||||
| [dependencies] | ||||
| log = "0.3" | ||||
| libc = "0.2.11" | ||||
| rand = "0.3.14" | ||||
| ethkey = { path = "../ethkey" } | ||||
|  | ||||
| @ -22,7 +22,7 @@ use {json, SafeAccount, Error}; | ||||
| use json::Uuid; | ||||
| use super::KeyDirectory; | ||||
| 
 | ||||
| const IGNORED_FILES: &'static [&'static str] = &["thumbs.db", "address_book.json"]; | ||||
| const IGNORED_FILES: &'static [&'static str] = &["thumbs.db", "address_book.json", "dapps_policy.json"]; | ||||
| 
 | ||||
| #[cfg(not(windows))] | ||||
| fn restrict_permissions_to_owner(file_path: &Path) -> Result<(), i32>  { | ||||
| @ -78,7 +78,7 @@ impl DiskDirectory { | ||||
| 			.map(|entry| entry.path()) | ||||
| 			.collect::<Vec<PathBuf>>(); | ||||
| 
 | ||||
| 		paths | ||||
| 		Ok(paths | ||||
| 			.iter() | ||||
| 			.map(|p| ( | ||||
| 				fs::File::open(p) | ||||
| @ -86,13 +86,17 @@ impl DiskDirectory { | ||||
| 					.and_then(|r| json::KeyFile::load(r).map_err(|e| Error::Custom(format!("{:?}", e)))), | ||||
| 				p | ||||
| 			)) | ||||
| 			.map(|(file, path)| match file { | ||||
| 				Ok(file) => Ok((path.clone(), SafeAccount::from_file( | ||||
| 			.filter_map(|(file, path)| match file { | ||||
| 				Ok(file) => Some((path.clone(), SafeAccount::from_file( | ||||
| 					file, Some(path.file_name().and_then(|n| n.to_str()).expect("Keys have valid UTF8 names only.").to_owned()) | ||||
| 				))), | ||||
| 				Err(err) => Err(Error::InvalidKeyFile(format!("{:?}: {}", path, err))), | ||||
| 				Err(err) => { | ||||
| 					warn!("Invalid key file: {:?} ({})", path, err); | ||||
| 					None | ||||
| 				}, | ||||
| 			}) | ||||
| 			.collect() | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -32,6 +32,9 @@ extern crate parking_lot; | ||||
| extern crate ethkey as _ethkey; | ||||
| extern crate ethcrypto as crypto; | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate log; | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate lazy_static; | ||||
| 
 | ||||
|  | ||||
| @ -7,9 +7,13 @@ version = "1.5.0" | ||||
| authors = ["Parity Technologies <admin@parity.io>"] | ||||
| 
 | ||||
| [dependencies] | ||||
| log = "0.3" | ||||
| rustc-serialize = "0.3" | ||||
| ethabi = "0.2.2" | ||||
| futures = "0.1" | ||||
| log = "0.3" | ||||
| mime = "0.2" | ||||
| mime_guess = "1.6.1" | ||||
| rand = "0.3" | ||||
| rustc-serialize = "0.3" | ||||
| fetch = { path = "../util/fetch" } | ||||
| ethcore-util = { path = "../util" } | ||||
| parity-reactor = { path = "../util/reactor" } | ||||
|  | ||||
| @ -17,13 +17,15 @@ | ||||
| //! Hash-addressed content resolver & fetcher.
 | ||||
| 
 | ||||
| use std::{io, fs}; | ||||
| use std::io::Write; | ||||
| use std::sync::Arc; | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| use util::{Mutex, H256, sha3}; | ||||
| use fetch::{Fetch, FetchError, Client as FetchClient}; | ||||
| 
 | ||||
| use fetch::{Fetch, Response, Error as FetchError, Client as FetchClient}; | ||||
| use futures::Future; | ||||
| use parity_reactor::Remote; | ||||
| use urlhint::{ContractClient, URLHintContract, URLHint, URLHintResult}; | ||||
| use util::{H256, sha3}; | ||||
| 
 | ||||
| /// API for fetching by hash.
 | ||||
| pub trait HashFetch: Send + Sync + 'static { | ||||
| @ -33,7 +35,7 @@ pub trait HashFetch: Send + Sync + 'static { | ||||
| 	/// 2. `on_done` - callback function invoked when the content is ready (or there was error during fetch)
 | ||||
| 	///
 | ||||
| 	/// This function may fail immediately when fetch cannot be initialized or content cannot be resolved.
 | ||||
| 	fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>) -> Result<(), Error>; | ||||
| 	fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>); | ||||
| } | ||||
| 
 | ||||
| /// Hash-fetching error.
 | ||||
| @ -67,44 +69,61 @@ impl From<io::Error> for Error { | ||||
| } | ||||
| 
 | ||||
| /// Default Hash-fetching client using on-chain contract to resolve hashes to URLs.
 | ||||
| pub struct Client { | ||||
| pub struct Client<F: Fetch + 'static = FetchClient> { | ||||
| 	contract: URLHintContract, | ||||
| 	fetch: Mutex<FetchClient>, | ||||
| 	fetch: F, | ||||
| 	remote: Remote, | ||||
| } | ||||
| 
 | ||||
| impl Client { | ||||
| 	/// Creates new instance of the `Client` given on-chain contract client.
 | ||||
| 	pub fn new(contract: Arc<ContractClient>) -> Self { | ||||
| 	/// Creates new instance of the `Client` given on-chain contract client and task runner.
 | ||||
| 	pub fn new(contract: Arc<ContractClient>, remote: Remote) -> Self { | ||||
| 		Client::with_fetch(contract, FetchClient::new().unwrap(), remote) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl<F: Fetch + 'static> Client<F> { | ||||
| 
 | ||||
| 	/// Creates new instance of the `Client` given on-chain contract client, fetch service and task runner.
 | ||||
| 	pub fn with_fetch(contract: Arc<ContractClient>, fetch: F, remote: Remote) -> Self { | ||||
| 		Client { | ||||
| 			contract: URLHintContract::new(contract), | ||||
| 			fetch: Mutex::new(FetchClient::default()), | ||||
| 			fetch: fetch, | ||||
| 			remote: remote, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl HashFetch for Client { | ||||
| 	fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>) -> Result<(), Error> { | ||||
| impl<F: Fetch + 'static> HashFetch for Client<F> { | ||||
| 	fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>) { | ||||
| 		debug!(target: "fetch", "Fetching: {:?}", hash); | ||||
| 
 | ||||
| 		let url = try!( | ||||
| 			self.contract.resolve(hash.to_vec()).map(|content| match content { | ||||
| 		let url = self.contract.resolve(hash.to_vec()).map(|content| match content { | ||||
| 				URLHintResult::Dapp(dapp) => { | ||||
| 					dapp.url() | ||||
| 				}, | ||||
| 				URLHintResult::Content(content) => { | ||||
| 					content.url | ||||
| 				}, | ||||
| 			}).ok_or_else(|| Error::NoResolution) | ||||
| 		); | ||||
| 		}).ok_or_else(|| Error::NoResolution); | ||||
| 
 | ||||
| 		debug!(target: "fetch", "Resolved {:?} to {:?}. Fetching...", hash, url); | ||||
| 
 | ||||
| 		self.fetch.lock().request_async(&url, Default::default(), Box::new(move |result| { | ||||
| 			fn validate_hash(hash: H256, result: Result<PathBuf, FetchError>) -> Result<PathBuf, Error> { | ||||
| 				let path = try!(result); | ||||
| 		match url { | ||||
| 			Err(err) => on_done(Err(err)), | ||||
| 			Ok(url) => { | ||||
| 				let future = self.fetch.fetch(&url).then(move |result| { | ||||
| 					fn validate_hash(path: PathBuf, hash: H256, result: Result<Response, FetchError>) -> Result<PathBuf, Error> { | ||||
| 						let response = try!(result); | ||||
| 						// Read the response
 | ||||
| 						let mut reader = io::BufReader::new(response); | ||||
| 						let mut writer = io::BufWriter::new(try!(fs::File::create(&path))); | ||||
| 						try!(io::copy(&mut reader, &mut writer)); | ||||
| 						try!(writer.flush()); | ||||
| 
 | ||||
| 						// And validate the hash
 | ||||
| 						let mut file_reader = io::BufReader::new(try!(fs::File::open(&path))); | ||||
| 						let content_hash = try!(sha3(&mut file_reader)); | ||||
| 
 | ||||
| 						if content_hash != hash { | ||||
| 							Err(Error::HashMismatch{ got: content_hash, expected: hash }) | ||||
| 						} else { | ||||
| @ -113,7 +132,31 @@ impl HashFetch for Client { | ||||
| 					} | ||||
| 
 | ||||
| 					debug!(target: "fetch", "Content fetched, validating hash ({:?})", hash); | ||||
| 			on_done(validate_hash(hash, result)) | ||||
| 		})).map_err(Into::into) | ||||
| 					let path = random_temp_path(); | ||||
| 					let res = validate_hash(path.clone(), hash, result); | ||||
| 					if let Err(ref err) = res { | ||||
| 						trace!(target: "fetch", "Error: {:?}", err); | ||||
| 						// Remove temporary file in case of error
 | ||||
| 						let _ = fs::remove_dir_all(&path); | ||||
| 					} | ||||
| 					on_done(res); | ||||
| 
 | ||||
| 					Ok(()) as Result<(), ()> | ||||
| 				}); | ||||
| 				self.remote.spawn(self.fetch.process(future)); | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn random_temp_path() -> PathBuf { | ||||
| 	use ::rand::Rng; | ||||
| 	use ::std::env; | ||||
| 
 | ||||
| 	let mut rng = ::rand::OsRng::new().expect("Reliable random source is required to work."); | ||||
| 	let file: String = rng.gen_ascii_chars().take(12).collect(); | ||||
| 
 | ||||
| 	let mut path = env::temp_dir(); | ||||
| 	path.push(file); | ||||
| 	path | ||||
| } | ||||
|  | ||||
| @ -20,11 +20,17 @@ | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate log; | ||||
| extern crate rustc_serialize; | ||||
| extern crate mime_guess; | ||||
| #[macro_use] | ||||
| extern crate mime; | ||||
| 
 | ||||
| extern crate ethabi; | ||||
| extern crate ethcore_util as util; | ||||
| extern crate fetch; | ||||
| pub extern crate fetch; | ||||
| extern crate futures; | ||||
| extern crate mime_guess; | ||||
| extern crate rand; | ||||
| extern crate rustc_serialize; | ||||
| extern crate parity_reactor; | ||||
| 
 | ||||
| mod client; | ||||
| 
 | ||||
|  | ||||
| @ -19,6 +19,7 @@ | ||||
| use std::fmt; | ||||
| use std::sync::Arc; | ||||
| use rustc_serialize::hex::ToHex; | ||||
| use mime::Mime; | ||||
| use mime_guess; | ||||
| 
 | ||||
| use ethabi::{Interface, Contract, Token}; | ||||
| @ -76,7 +77,7 @@ pub struct Content { | ||||
| 	/// URL of the content
 | ||||
| 	pub url: String, | ||||
| 	/// MIME type of the content
 | ||||
| 	pub mime: String, | ||||
| 	pub mime: Mime, | ||||
| 	/// Content owner address
 | ||||
| 	pub owner: Address, | ||||
| } | ||||
| @ -183,7 +184,7 @@ impl URLHintContract { | ||||
| 
 | ||||
| 					let commit = GithubApp::commit(&commit); | ||||
| 					if commit == Some(Default::default()) { | ||||
| 						let mime = guess_mime_type(&account_slash_repo).unwrap_or("application/octet-stream".into()); | ||||
| 						let mime = guess_mime_type(&account_slash_repo).unwrap_or(mime!(Application/_)); | ||||
| 						return Some(URLHintResult::Content(Content { | ||||
| 							url: account_slash_repo, | ||||
| 							mime: mime, | ||||
| @ -235,7 +236,7 @@ impl URLHint for URLHintContract { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn guess_mime_type(url: &str) -> Option<String> { | ||||
| fn guess_mime_type(url: &str) -> Option<Mime> { | ||||
| 	const CONTENT_TYPE: &'static str = "content-type="; | ||||
| 
 | ||||
| 	let mut it = url.split('#'); | ||||
| @ -247,14 +248,14 @@ fn guess_mime_type(url: &str) -> Option<String> { | ||||
| 		for meta in metas.split('&') { | ||||
| 			let meta = meta.to_lowercase(); | ||||
| 			if meta.starts_with(CONTENT_TYPE) { | ||||
| 				return Some(meta[CONTENT_TYPE.len()..].to_owned()); | ||||
| 				return meta[CONTENT_TYPE.len()..].parse().ok(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	url.and_then(|url| { | ||||
| 		url.split('.').last() | ||||
| 	}).and_then(|extension| { | ||||
| 		mime_guess::get_mime_type_str(extension).map(Into::into) | ||||
| 		mime_guess::get_mime_type_opt(extension) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| @ -369,7 +370,7 @@ mod tests { | ||||
| 		// then
 | ||||
| 		assert_eq!(res, Some(URLHintResult::Content(Content { | ||||
| 			url: "https://ethcore.io/assets/images/ethcore-black-horizontal.png".into(), | ||||
| 			mime: "image/png".into(), | ||||
| 			mime: mime!(Image/Png), | ||||
| 			owner: Address::from_str("deadcafebeefbeefcafedeaddeedfeedffffffff").unwrap(), | ||||
| 		}))) | ||||
| 	} | ||||
| @ -401,9 +402,9 @@ mod tests { | ||||
| 
 | ||||
| 
 | ||||
| 		assert_eq!(guess_mime_type(url1), None); | ||||
| 		assert_eq!(guess_mime_type(url2), Some("image/png".into())); | ||||
| 		assert_eq!(guess_mime_type(url3), Some("image/png".into())); | ||||
| 		assert_eq!(guess_mime_type(url4), Some("image/jpeg".into())); | ||||
| 		assert_eq!(guess_mime_type(url5), Some("image/png".into())); | ||||
| 		assert_eq!(guess_mime_type(url2), Some(mime!(Image/Png))); | ||||
| 		assert_eq!(guess_mime_type(url3), Some(mime!(Image/Png))); | ||||
| 		assert_eq!(guess_mime_type(url4), Some(mime!(Image/Jpeg))); | ||||
| 		assert_eq!(guess_mime_type(url5), Some(mime!(Image/Png))); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -19,7 +19,8 @@ | ||||
| use std::fmt; | ||||
| 
 | ||||
| /// A release's track.
 | ||||
| #[derive(PartialEq, Eq, Clone, Copy, Debug, Binary)] | ||||
| #[derive(PartialEq, Eq, Clone, Copy, Debug)] | ||||
| #[binary] | ||||
| pub enum ReleaseTrack { | ||||
| 	/// Stable track.
 | ||||
| 	Stable, | ||||
|  | ||||
| @ -23,7 +23,8 @@ use util::misc::raw_package_info; | ||||
| use release_track::ReleaseTrack; | ||||
| 
 | ||||
| /// Version information of a particular release.
 | ||||
| #[derive(Debug, Clone, PartialEq, Binary)] | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| #[binary] | ||||
| pub struct VersionInfo { | ||||
| 	/// The track on which it was released.
 | ||||
| 	pub track: ReleaseTrack, | ||||
|  | ||||
| @ -111,7 +111,7 @@ fn push_invoke_signature_aster( | ||||
| 			let arg_ty = &inputs[skip-1].ty; | ||||
| 
 | ||||
| 			let mut tree = builder.item() | ||||
| 				.attr().word("derive(Binary)") | ||||
| 				.attr().word("binary") | ||||
| 				.attr().word("allow(non_camel_case_types)") | ||||
| 				.struct_(name_str.as_str()) | ||||
| 				.field(arg_name.as_str()) | ||||
| @ -140,7 +140,7 @@ fn push_invoke_signature_aster( | ||||
| 		FunctionRetTy::Ty(ref ty) => { | ||||
| 			let name_str = format!("{}_output", named_signature.ident.name.as_str()); | ||||
| 			let tree = builder.item() | ||||
| 				.attr().word("derive(Binary)") | ||||
| 				.attr().word("binary") | ||||
| 				.attr().word("allow(non_camel_case_types)") | ||||
| 				.struct_(name_str.as_str()) | ||||
| 				.field(format!("payload")).ty().build(ty.clone()); | ||||
| @ -326,7 +326,7 @@ pub fn has_ptr(ty: &P<ast::Ty>) -> bool { | ||||
| ///   fn commit(&self, f: u32) -> u32
 | ||||
| ///
 | ||||
| /// the expanded implementation will generate method for the client like that
 | ||||
| ///    #[derive(Serialize)]
 | ||||
| ///    #[binary]
 | ||||
| ///    struct Request<'a> {
 | ||||
| ///	     f: &'a u32,
 | ||||
| ///    }
 | ||||
| @ -358,7 +358,7 @@ fn implement_client_method_body( | ||||
| 			.build(static_ty.clone()); | ||||
| 
 | ||||
| 		let mut tree = builder.item() | ||||
| 			.attr().word("derive(Binary)") | ||||
| 			.attr().word("binary") | ||||
| 			.struct_("Request") | ||||
| 			.generics() | ||||
| 			.lifetime_name("'a") | ||||
|  | ||||
| @ -42,6 +42,10 @@ extern crate rustc_plugin; | ||||
| #[cfg(not(feature = "with-syntex"))] | ||||
| use syntax::feature_gate::AttributeType; | ||||
| 
 | ||||
| #[cfg(feature = "with-syntex")] | ||||
| use syntax::{ast, fold}; | ||||
| 
 | ||||
| 
 | ||||
| #[cfg(feature = "with-syntex")] | ||||
| include!(concat!(env!("OUT_DIR"), "/lib.rs")); | ||||
| 
 | ||||
| @ -56,17 +60,16 @@ pub fn expand(src: &std::path::Path, dst: &std::path::Path) { | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "with-syntex")] | ||||
| pub fn register_cleaner(reg: &mut syntex::Registry) { | ||||
| 	use syntax::{ast, fold}; | ||||
| struct StripAttributeFolder<'a> { | ||||
| 	attr_title: &'a str, | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "with-syntex")] | ||||
| 	fn strip_attributes(krate: ast::Crate) -> ast::Crate { | ||||
| 		struct StripAttributeFolder; | ||||
| 		impl fold::Folder for StripAttributeFolder { | ||||
| impl<'a> fold::Folder for StripAttributeFolder<'a> { | ||||
| 	fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> { | ||||
| 		match attr.node.value.node { | ||||
| 					ast::MetaItemKind::List(ref n, _) if n == &"ipc" => { return None; } | ||||
| 					ast::MetaItemKind::Word(ref n) if n == &"ipc" => { return None; } | ||||
| 			ast::MetaItemKind::List(ref n, _) if n == self.attr_title => { return None; } | ||||
| 			ast::MetaItemKind::Word(ref n) if n == self.attr_title => { return None; } | ||||
| 			_ => {} | ||||
| 		} | ||||
| 
 | ||||
| @ -78,7 +81,23 @@ pub fn register_cleaner(reg: &mut syntex::Registry) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 		fold::Folder::fold_crate(&mut StripAttributeFolder, krate) | ||||
| #[cfg(feature = "with-syntex")] | ||||
| pub fn register_cleaner_ipc(reg: &mut syntex::Registry) { | ||||
| 	#[cfg(feature = "with-syntex")] | ||||
| 	fn strip_attributes(krate: ast::Crate) -> ast::Crate { | ||||
| 		let mut folder = StripAttributeFolder { attr_title: "ipc" }; | ||||
| 		fold::Folder::fold_crate(&mut folder, krate) | ||||
| 	} | ||||
| 
 | ||||
| 	reg.add_post_expansion_pass(strip_attributes); | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature = "with-syntex")] | ||||
| pub fn register_cleaner_binary(reg: &mut syntex::Registry) { | ||||
| 	#[cfg(feature = "with-syntex")] | ||||
| 	fn strip_attributes(krate: ast::Crate) -> ast::Crate { | ||||
| 		let mut folder = StripAttributeFolder { attr_title: "binary" }; | ||||
| 		fold::Folder::fold_crate(&mut folder, krate) | ||||
| 	} | ||||
| 
 | ||||
| 	reg.add_post_expansion_pass(strip_attributes); | ||||
| @ -90,9 +109,10 @@ pub fn register(reg: &mut syntex::Registry) { | ||||
| 	reg.add_attr("feature(custom_attribute)"); | ||||
| 
 | ||||
| 	reg.add_decorator("ipc", codegen::expand_ipc_implementation); | ||||
| 	reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation); | ||||
| 	reg.add_decorator("binary", serialization::expand_serialization_implementation); | ||||
| 
 | ||||
| 	register_cleaner(reg); | ||||
| 	register_cleaner_ipc(reg); | ||||
| 	register_cleaner_binary(reg); | ||||
| } | ||||
| 
 | ||||
| #[cfg(not(feature = "with-syntex"))] | ||||
| @ -102,11 +122,12 @@ pub fn register(reg: &mut rustc_plugin::Registry) { | ||||
| 		syntax::ext::base::MultiDecorator( | ||||
| 			Box::new(codegen::expand_ipc_implementation))); | ||||
| 	reg.register_syntax_extension( | ||||
| 		syntax::parse::token::intern("derive_Binary"), | ||||
| 		syntax::parse::token::intern("binary"), | ||||
| 		syntax::ext::base::MultiDecorator( | ||||
| 			Box::new(serialization::expand_serialization_implementation))); | ||||
| 
 | ||||
| 	reg.register_attribute("ipc".to_owned(), AttributeType::Normal); | ||||
| 	reg.register_attribute("binary".to_owned(), AttributeType::Normal); | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| @ -124,13 +145,31 @@ pub fn derive_ipc_cond(src_path: &str, has_feature: bool) -> Result<(), Error> { | ||||
| } | ||||
| 
 | ||||
| pub fn cleanup_ipc(src_path: &str) -> Result<(), Error> { | ||||
| 	cleanup(src_path, AttributeKind::Ipc) | ||||
| } | ||||
| 
 | ||||
| pub fn cleanup_binary(src_path: &str) -> Result<(), Error> { | ||||
| 	cleanup(src_path, AttributeKind::Binary) | ||||
| } | ||||
| 
 | ||||
| enum AttributeKind { | ||||
| 	Ipc, | ||||
| 	Binary, | ||||
| } | ||||
| 
 | ||||
| fn cleanup(src_path: &str, attr: AttributeKind) -> Result<(), Error> { | ||||
| 	use std::env; | ||||
| 	use std::path::{Path, PathBuf}; | ||||
| 
 | ||||
| 	let out_dir = env::var_os("OUT_DIR").unwrap(); | ||||
| 	let file_name = try!(PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned())); | ||||
| 	let mut registry = syntex::Registry::new(); | ||||
| 	register_cleaner(&mut registry); | ||||
| 
 | ||||
| 	match attr { | ||||
| 		AttributeKind::Ipc => { register_cleaner_ipc(&mut registry); } | ||||
| 		AttributeKind::Binary => { register_cleaner_binary(&mut registry); } | ||||
| 	} | ||||
| 
 | ||||
| 	if let Err(_) = registry.expand("", &Path::new(src_path), &Path::new(&out_dir).join(&file_name)) | ||||
| 	{ | ||||
| 		// will be reported by compiler
 | ||||
| @ -190,3 +229,8 @@ pub fn derive_binary(src_path: &str) -> Result<(), Error> { | ||||
| 
 | ||||
| 	Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub fn derive_binary_cond(src_path: &str, has_feature: bool) -> Result<(), Error> { | ||||
| 	if has_feature { derive_binary(src_path) } | ||||
| 	else { cleanup_binary(src_path) } | ||||
| } | ||||
|  | ||||
| @ -17,37 +17,40 @@ | ||||
| 
 | ||||
| use util::Bytes; | ||||
| 
 | ||||
| #[derive(Binary)] | ||||
| #[binary] | ||||
| pub enum Root { | ||||
| 	Top, | ||||
| 	Middle(u32, u64), | ||||
| } | ||||
| 
 | ||||
| #[derive(Binary, PartialEq, Debug)] | ||||
| #[derive(PartialEq, Debug)] | ||||
| #[binary] | ||||
| pub struct DoubleRoot { | ||||
| 	pub x1: u32, | ||||
| 	pub x2: u64, | ||||
| 	pub x3: u32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Binary, PartialEq, Debug)] | ||||
| #[derive(PartialEq, Debug)] | ||||
| #[binary] | ||||
| pub struct ReferenceStruct<'a> { | ||||
| 	pub ref_data: &'a u64, | ||||
| } | ||||
| 
 | ||||
| #[derive(Binary, PartialEq, Debug)] | ||||
| #[derive(PartialEq, Debug)] | ||||
| #[binary] | ||||
| pub enum EnumWithStruct { | ||||
| 	Left, | ||||
| 	Right { how_much: u64 }, | ||||
| } | ||||
| 
 | ||||
| #[derive(Binary)] | ||||
| #[binary] | ||||
| pub struct TwoVec { | ||||
| 	v1: Vec<u8>, | ||||
| 	v2: Vec<u8>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Binary)] | ||||
| #[binary] | ||||
| struct ChunkSet { | ||||
|     items: Vec<Bytes>, | ||||
| } | ||||
|  | ||||
| @ -30,7 +30,7 @@ pub trait DBWriter { | ||||
| 
 | ||||
| impl IpcConfig for DBWriter {} | ||||
| 
 | ||||
| #[derive(Binary)] | ||||
| #[binary] | ||||
| pub enum DBError { Write, Read } | ||||
| 
 | ||||
| #[ipc] | ||||
|  | ||||
| @ -22,7 +22,7 @@ pub struct Service { | ||||
| 	pub rollbacks: RwLock<usize>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Binary)] | ||||
| #[binary] | ||||
| pub struct CustomData { | ||||
| 	pub a: u64, | ||||
| 	pub b: u64, | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "parity.js", | ||||
|   "version": "0.2.131", | ||||
|   "version": "0.2.141", | ||||
|   "main": "release/index.js", | ||||
|   "jsnext:main": "src/index.js", | ||||
|   "author": "Parity Team <admin@parity.io>", | ||||
| @ -53,7 +53,7 @@ | ||||
|     "babel-cli": "6.18.0", | ||||
|     "babel-core": "6.20.0", | ||||
|     "babel-eslint": "7.1.1", | ||||
|     "babel-loader": "6.2.8", | ||||
|     "babel-loader": "6.2.10", | ||||
|     "babel-plugin-lodash": "3.2.10", | ||||
|     "babel-plugin-react-intl": "2.2.0", | ||||
|     "babel-plugin-transform-class-properties": "6.18.0", | ||||
| @ -117,6 +117,7 @@ | ||||
|     "react-hot-loader": "3.0.0-beta.6", | ||||
|     "react-intl-aggregate-webpack-plugin": "0.0.1", | ||||
|     "rucksack-css": "0.9.1", | ||||
|     "script-ext-html-webpack-plugin": "1.3.4", | ||||
|     "serviceworker-webpack-plugin": "0.1.7", | ||||
|     "sinon": "1.17.6", | ||||
|     "sinon-as-promised": "4.0.2", | ||||
| @ -125,7 +126,7 @@ | ||||
|     "stylelint": "7.6.0", | ||||
|     "stylelint-config-standard": "15.0.0", | ||||
|     "url-loader": "0.5.7", | ||||
|     "webpack": "2.1.0-beta.27", | ||||
|     "webpack": "2.2.0-rc.2", | ||||
|     "webpack-dev-middleware": "1.8.4", | ||||
|     "webpack-error-notification": "0.1.6", | ||||
|     "webpack-hot-middleware": "2.13.2", | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| // test script 6
 | ||||
| // test script 7
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/email-verification/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/email-verification/index.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/etherscan/account.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/etherscan/account.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/etherscan/account.spec.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/etherscan/account.spec.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/etherscan/call.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/etherscan/call.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/etherscan/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/etherscan/index.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/etherscan/links.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/etherscan/links.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/etherscan/stats.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/etherscan/stats.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/etherscan/stats.spec.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/etherscan/stats.spec.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/shapeshift/helpers.spec.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/shapeshift/helpers.spec.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/shapeshift/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/shapeshift/index.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/shapeshift/rpc.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/shapeshift/rpc.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/shapeshift/rpc.spec.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/shapeshift/rpc.spec.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/shapeshift/shapeshift.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/shapeshift/shapeshift.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								js/src/3rdparty/sms-verification/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								js/src/3rdparty/sms-verification/index.js
									
									
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| // Copyright 2015, 2016 Ethcore (UK) Ltd.
 | ||||
| // Copyright 2015, 2016 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
|  | ||||
| @ -66,6 +66,20 @@ export function outBlock (block) { | ||||
|   return block; | ||||
| } | ||||
| 
 | ||||
| export function outChainStatus (status) { | ||||
|   if (status) { | ||||
|     Object.keys(status).forEach((key) => { | ||||
|       switch (key) { | ||||
|         case 'blockGap': | ||||
|           status[key] = status[key].map(outNumber); | ||||
|           break; | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   return status; | ||||
| } | ||||
| 
 | ||||
| export function outDate (date) { | ||||
|   return new Date(outNumber(date).toNumber() * 1000); | ||||
| } | ||||
| @ -77,6 +91,7 @@ export function outHistogram (histogram) { | ||||
|         case 'bucketBounds': | ||||
|         case 'counts': | ||||
|           histogram[key] = histogram[key].map(outNumber); | ||||
|           break; | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| @ -16,7 +16,7 @@ | ||||
| 
 | ||||
| import BigNumber from 'bignumber.js'; | ||||
| 
 | ||||
| import { outBlock, outAccountInfo, outAddress, outDate, outHistogram, outNumber, outPeers, outReceipt, outSyncing, outTransaction, outTrace } from './output'; | ||||
| import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outNumber, outPeers, outReceipt, outSyncing, outTransaction, outTrace } from './output'; | ||||
| import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types'; | ||||
| 
 | ||||
| describe('api/format/output', () => { | ||||
| @ -114,6 +114,18 @@ describe('api/format/output', () => { | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('outChainStatus', () => { | ||||
|     it('formats blockGap values', () => { | ||||
|       const status = { | ||||
|         blockGap: [0x1234, '0x5678'] | ||||
|       }; | ||||
| 
 | ||||
|       expect(outChainStatus(status)).to.deep.equal({ | ||||
|         blockGap: [new BigNumber(0x1234), new BigNumber(0x5678)] | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('outDate', () => { | ||||
|     it('converts a second date in unix timestamp', () => { | ||||
|       expect(outDate(0x57513668)).to.deep.equal(new Date('2016-06-03T07:48:56.000Z')); | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| import { inAddress, inData, inHex, inNumber16, inOptions } from '../../format/input'; | ||||
| import { outAccountInfo, outAddress, outHistogram, outNumber, outPeers, outTransaction } from '../../format/output'; | ||||
| import { outAccountInfo, outAddress, outChainStatus, outHistogram, outNumber, outPeers, outTransaction } from '../../format/output'; | ||||
| 
 | ||||
| export default class Parity { | ||||
|   constructor (transport) { | ||||
| @ -44,6 +44,12 @@ export default class Parity { | ||||
|       .execute('parity_addReservedPeer', encode); | ||||
|   } | ||||
| 
 | ||||
|   chainStatus () { | ||||
|     return this._transport | ||||
|       .execute('parity_chainStatus') | ||||
|       .then(outChainStatus); | ||||
|   } | ||||
| 
 | ||||
|   changePassword (account, password, newPassword) { | ||||
|     return this._transport | ||||
|       .execute('parity_changePassword', inAddress(account), password, newPassword); | ||||
|  | ||||
| @ -14,6 +14,7 @@ | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| import BigNumber from 'bignumber.js'; | ||||
| import { TEST_HTTP_URL, mockHttp } from '../../../../test/mockRpc'; | ||||
| import { isBigNumber } from '../../../../test/types'; | ||||
| 
 | ||||
| @ -45,6 +46,22 @@ describe('api/rpc/parity', () => { | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('chainStatus', () => { | ||||
|     it('retrieves the chain status', () => { | ||||
|       mockHttp([{ method: 'parity_chainStatus', reply: { | ||||
|         result: { | ||||
|           'blockGap': [0x123, 0x456] | ||||
|         } | ||||
|       } }]); | ||||
| 
 | ||||
|       return instance.chainStatus().then((result) => { | ||||
|         expect(result).to.deep.equal({ | ||||
|           'blockGap': [new BigNumber(0x123), new BigNumber(0x456)] | ||||
|         }); | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('gasFloorTarget', () => { | ||||
|     it('returns the gasfloor, formatted', () => { | ||||
|       mockHttp([{ method: 'parity_gasFloorTarget', reply: { result: '0x123456' } }]); | ||||
|  | ||||
| @ -22,7 +22,7 @@ import TransportError from '../error'; | ||||
| 
 | ||||
| /* global WebSocket */ | ||||
| export default class Ws extends JsonRpcBase { | ||||
|   constructor (url, token) { | ||||
|   constructor (url, token, connect = true) { | ||||
|     super(); | ||||
| 
 | ||||
|     this._url = url; | ||||
| @ -32,23 +32,34 @@ export default class Ws extends JsonRpcBase { | ||||
|     this._connecting = false; | ||||
|     this._connected = false; | ||||
|     this._lastError = null; | ||||
|     this._autoConnect = true; | ||||
|     this._autoConnect = false; | ||||
|     this._retries = 0; | ||||
|     this._reconnectTimeoutId = null; | ||||
| 
 | ||||
|     this._connect(); | ||||
|     this._connectPromise = null; | ||||
|     this._connectPromiseFunctions = {}; | ||||
| 
 | ||||
|     if (connect) { | ||||
|       this.connect(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   updateToken (token) { | ||||
|   updateToken (token, connect = true) { | ||||
|     this._token = token; | ||||
|     this._autoConnect = true; | ||||
|     // this._autoConnect = true;
 | ||||
| 
 | ||||
|     this._connect(); | ||||
|     if (connect) { | ||||
|       this.connect(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   connect () { | ||||
|     if (this._connected) { | ||||
|       return Promise.resolve(); | ||||
|     } | ||||
| 
 | ||||
|   _connect () { | ||||
|     if (this._connecting) { | ||||
|       return; | ||||
|       return this._connectPromise || Promise.resolve(); | ||||
|     } | ||||
| 
 | ||||
|     if (this._reconnectTimeoutId) { | ||||
| @ -104,10 +115,17 @@ export default class Ws extends JsonRpcBase { | ||||
| 
 | ||||
|       window._parityWS = this; | ||||
|     } | ||||
| 
 | ||||
|     this._connectPromise = new Promise((resolve, reject) => { | ||||
|       this._connectPromiseFunctions = { resolve, reject }; | ||||
|     }); | ||||
| 
 | ||||
|     return this._connectPromise; | ||||
|   } | ||||
| 
 | ||||
|   _onOpen = (event) => { | ||||
|     console.log('ws:onOpen', event); | ||||
|     console.log('ws:onOpen'); | ||||
| 
 | ||||
|     this._connected = true; | ||||
|     this._connecting = false; | ||||
|     this._autoConnect = true; | ||||
| @ -116,6 +134,11 @@ export default class Ws extends JsonRpcBase { | ||||
|     Object.keys(this._messages) | ||||
|       .filter((id) => this._messages[id].queued) | ||||
|       .forEach(this._send); | ||||
| 
 | ||||
|     this._connectPromiseFunctions.resolve(); | ||||
| 
 | ||||
|     this._connectPromise = null; | ||||
|     this._connectPromiseFunctions = {}; | ||||
|   } | ||||
| 
 | ||||
|   _onClose = (event) => { | ||||
| @ -135,13 +158,20 @@ export default class Ws extends JsonRpcBase { | ||||
|       console.log('ws:onClose', `trying again in ${time}...`); | ||||
| 
 | ||||
|       this._reconnectTimeoutId = setTimeout(() => { | ||||
|         this._connect(); | ||||
|         this.connect(); | ||||
|       }, timeout); | ||||
| 
 | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     console.log('ws:onClose', event); | ||||
|     if (this._connectPromise) { | ||||
|       this._connectPromiseFunctions.reject(event); | ||||
| 
 | ||||
|       this._connectPromise = null; | ||||
|       this._connectPromiseFunctions = {}; | ||||
|     } | ||||
| 
 | ||||
|     console.log('ws:onClose'); | ||||
|   } | ||||
| 
 | ||||
|   _onError = (event) => { | ||||
| @ -149,10 +179,17 @@ export default class Ws extends JsonRpcBase { | ||||
|     // ie. don't print if error == closed
 | ||||
|     window.setTimeout(() => { | ||||
|       if (this._connected) { | ||||
|         console.error('ws:onError', event); | ||||
|         console.error('ws:onError'); | ||||
| 
 | ||||
|         event.timestamp = Date.now(); | ||||
|         this._lastError = event; | ||||
| 
 | ||||
|         if (this._connectPromise) { | ||||
|           this._connectPromiseFunctions.reject(event); | ||||
| 
 | ||||
|           this._connectPromise = null; | ||||
|           this._connectPromiseFunctions = {}; | ||||
|         } | ||||
|       } | ||||
|     }, 50); | ||||
|   } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| /* Copyright 2015, 2016 Ethcore (UK) Ltd. | ||||
| /* Copyright 2015, 2016 Parity Technologies (UK) Ltd. | ||||
| /* This file is part of Parity. | ||||
| /* | ||||
| /* Parity is free software: you can redistribute it and/or modify | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user