Merge branch 'master' into auth-round

This commit is contained in:
keorn 2016-11-03 16:51:38 +00:00
commit 12125dcfee
68 changed files with 1135 additions and 361 deletions

View File

@ -136,7 +136,6 @@ linux-armv7:
stage: build stage: build
image: ethcore/rust-armv7:latest image: ethcore/rust-armv7:latest
only: only:
- master
- beta - beta
- tags - tags
- stable - stable
@ -176,7 +175,6 @@ linux-arm:
stage: build stage: build
image: ethcore/rust-arm:latest image: ethcore/rust-arm:latest
only: only:
- master
- beta - beta
- tags - tags
- stable - stable
@ -248,7 +246,6 @@ linux-aarch64:
stage: build stage: build
image: ethcore/rust-aarch64:latest image: ethcore/rust-aarch64:latest
only: only:
- master
- beta - beta
- tags - tags
- stable - stable
@ -287,7 +284,6 @@ linux-aarch64:
darwin: darwin:
stage: build stage: build
only: only:
- master
- beta - beta
- tags - tags
- stable - stable
@ -308,7 +304,6 @@ darwin:
windows: windows:
stage: build stage: build
only: only:
- master
- beta - beta
- tags - tags
- stable - stable
@ -322,6 +317,8 @@ windows:
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll - curl -sL --url "https://github.com/ethcore/win-build/raw/master/SimpleFC.dll" -o nsis\SimpleFC.dll
- curl -sL --url "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe - curl -sL --url "https://github.com/ethcore/win-build/raw/master/vc_redist.x64.exe" -o nsis\vc_redist.x64.exe
- signtool sign /f %keyfile% /p %certpass% target\release\parity.exe - signtool sign /f %keyfile% /p %certpass% target\release\parity.exe
- msbuild windows\ptray\ptray.vcxproj /p:Platform=x86 /p:Configuration=Release
- signtool sign /f %keyfile% /p %certpass% windows\ptray\release\ptray.exe
- cd nsis - cd nsis
- makensis.exe installer.nsi - makensis.exe installer.nsi
- copy installer.exe InstallParity.exe - copy installer.exe InstallParity.exe
@ -393,30 +390,14 @@ js-release:
- ./js/scripts/release.sh - ./js/scripts/release.sh
tags: tags:
- javascript - javascript
js-lint: js-tests:
stage: build stage: build
image: ethcore/javascript:latest image: ethcore/javascript:latest
before_script: before_script:
- ./js/scripts/install-deps.sh - ./js/scripts/install-deps.sh
script: script:
- ./js/scripts/lint.sh - ./js/scripts/lint.sh
tags:
- javascript-test
js-test:
stage: build
image: ethcore/javascript:latest
before_script:
- ./js/scripts/install-deps.sh
script:
- ./js/scripts/test.sh - ./js/scripts/test.sh
tags:
- javascript-test
js-pack:
stage: build
image: ethcore/javascript:latest
before_script:
- ./js/scripts/install-deps.sh
script:
- ./js/scripts/build.sh - ./js/scripts/build.sh
tags: tags:
- javascript-test - javascript-test

101
Cargo.lock generated
View File

@ -185,7 +185,7 @@ version = "1.1.1"
source = "git+https://github.com/ethcore/rust-ctrlc.git#f4927770f89eca80ec250911eea3adcbf579ac48" source = "git+https://github.com/ethcore/rust-ctrlc.git#f4927770f89eca80ec250911eea3adcbf579ac48"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -194,7 +194,7 @@ name = "daemonize"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -244,7 +244,7 @@ source = "git+https://github.com/ethcore/rust-secp256k1#a9a0b1be1f39560ca86e8fc8
dependencies = [ dependencies = [
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -352,6 +352,7 @@ dependencies = [
"serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.8.4 (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)", "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)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"zip 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
@ -370,7 +371,7 @@ version = "1.4.0"
dependencies = [ dependencies = [
"crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.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.0 (git+https://github.com/carllerche/mio)", "mio 0.6.1 (git+https://github.com/carllerche/mio)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -458,9 +459,9 @@ dependencies = [
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (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)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.0 (git+https://github.com/carllerche/mio)", "mio 0.6.1 (git+https://github.com/carllerche/mio)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0", "rlp 0.1.0",
@ -554,7 +555,7 @@ dependencies = [
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (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)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -618,7 +619,7 @@ dependencies = [
"ethkey 0.2.0", "ethkey 0.2.0",
"itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (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)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -663,7 +664,7 @@ dependencies = [
name = "fdlimit" name = "fdlimit"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -681,7 +682,7 @@ name = "flate2"
version = "0.2.14" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -802,7 +803,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -894,7 +895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.15" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -930,7 +931,7 @@ name = "memchr"
version = "0.1.11" version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -958,7 +959,7 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -967,7 +968,7 @@ version = "0.5.1"
source = "git+https://github.com/ethcore/mio?branch=v0.5.x#3842d3b250ffd7bd9b16f9586b875ddcbac2b0dd" source = "git+https://github.com/ethcore/mio?branch=v0.5.x#3842d3b250ffd7bd9b16f9586b875ddcbac2b0dd"
dependencies = [ dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (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)", "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)", "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)", "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
@ -983,7 +984,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (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)", "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)", "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)", "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
@ -999,7 +1000,7 @@ version = "0.6.0-dev"
source = "git+https://github.com/ethcore/mio?branch=timer-fix#31eccc40ece3d47abaefaf23bb2114033175b972" source = "git+https://github.com/ethcore/mio?branch=timer-fix#31eccc40ece3d47abaefaf23bb2114033175b972"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (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)", "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)", "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)", "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1010,16 +1011,16 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.6.0" version = "0.6.1"
source = "git+https://github.com/carllerche/mio#9f17b70d6fecbf912168267ea74cf536f2cba705" source = "git+https://github.com/carllerche/mio#56f8663510196fdca04bdf7c5f4d60b24297826f"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (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)", "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)", "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)", "net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.6.0 (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)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1050,7 +1051,7 @@ name = "nanomsg"
version = "0.5.1" version = "0.5.1"
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00" source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)", "nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
] ]
@ -1060,7 +1061,7 @@ version = "0.5.0"
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00" source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
dependencies = [ dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1070,7 +1071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1081,7 +1082,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1091,7 +1092,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (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.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (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.1.20 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1181,7 +1195,7 @@ name = "num_cpus"
version = "0.2.11" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1235,7 +1249,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-ui-precompiled" name = "parity-ui-precompiled"
version = "1.4.0" version = "1.4.0"
source = "git+https://github.com/ethcore/js-precompiled.git#10a57a7df153360b4abeddff99e5b8f34a85ff53" source = "git+https://github.com/ethcore/js-precompiled.git#f8bd7fa67e91daea3ac698ebcc447fae494802cb"
dependencies = [ dependencies = [
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1246,7 +1260,7 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1266,7 +1280,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1405,7 +1419,7 @@ name = "rand"
version = "0.3.14" version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1459,7 +1473,7 @@ name = "rocksdb"
version = "0.4.5" version = "0.4.5"
source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58" source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)", "rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
] ]
@ -1469,7 +1483,7 @@ version = "0.3.0"
source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58" source = "git+https://github.com/ethcore/rust-rocksdb#64c63ccbe1f62c2e2b39262486f9ba813793af58"
dependencies = [ dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1489,7 +1503,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1500,7 +1514,7 @@ version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1671,7 +1685,7 @@ name = "syntex_errors"
version = "0.42.0" version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.15 (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)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_pos 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1693,7 +1707,7 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (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)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1706,7 +1720,7 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (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)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_errors 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.42.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1747,7 +1761,7 @@ name = "termios"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1756,7 +1770,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1773,7 +1787,7 @@ version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2012,7 +2026,7 @@ dependencies = [
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b" "checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
"checksum libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "23e3757828fa702a20072c37ff47938e9dd331b92fac6e223d26d4b7a55f7ee2" "checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
"checksum linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bda158e0dabeb97ee8a401f4d17e479d6b891a14de0bba79d5cc2d4d325b5e48" "checksum linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bda158e0dabeb97ee8a401f4d17e479d6b891a14de0bba79d5cc2d4d325b5e48"
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" "checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
@ -2024,8 +2038,8 @@ dependencies = [
"checksum miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1f4d337a01c32e1f2122510fed46393d53ca35a7f429cb0450abaedfa3ed54" "checksum miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1f4d337a01c32e1f2122510fed46393d53ca35a7f429cb0450abaedfa3ed54"
"checksum mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)" = "<none>" "checksum mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)" = "<none>"
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e" "checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum mio 0.6.0 (git+https://github.com/carllerche/mio)" = "<none>"
"checksum mio 0.6.0-dev (git+https://github.com/ethcore/mio?branch=timer-fix)" = "<none>" "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/carllerche/mio)" = "<none>"
"checksum miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bfc6782530ac8ace97af10a540054a37126b63b0702ddaaa243b73b5745b9a" "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 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 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)" = "<none>"
@ -2033,6 +2047,7 @@ dependencies = [
"checksum net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a816012ca11cb47009693c1e0c6130e26d39e4d97ee2a13c50e868ec83e3204" "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.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" "checksum nix 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a7bb1da2be7da3cbffda73fc681d509ffd9e665af478d2bee1907cee0bc64b2"
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
"checksum nodrop 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4d9a22dbcebdeef7bf275cbf444d6521d4e7a2fee187b72d80dba0817120dd8f" "checksum nodrop 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4d9a22dbcebdeef7bf275cbf444d6521d4e7a2fee187b72d80dba0817120dd8f"
"checksum nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6caab12c5f97aa316cb249725aa32115118e1522b445e26c257dd77cad5ffd4e" "checksum nom 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6caab12c5f97aa316cb249725aa32115118e1522b445e26c257dd77cad5ffd4e"
"checksum num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c04bd954dbf96f76bab6e5bd6cef6f1ce1262d15268ce4f926d2b5b778fa7af2" "checksum num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "c04bd954dbf96f76bab6e5bd6cef6f1ce1262d15268ce4f926d2b5b778fa7af2"

View File

@ -38,6 +38,8 @@ after_test:
- cargo build --verbose --release - cargo build --verbose --release
- ps: if($env:cert) { Start-FileDownload $env:cert -FileName $env:keyfile } - ps: if($env:cert) { Start-FileDownload $env:cert -FileName $env:keyfile }
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass target\release\parity.exe } - ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass target\release\parity.exe }
- msbuild windows\ptray\ptray.vcxproj /p:Platform=x86 /p:Configuration=Release
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass windows\ptray\release\ptray.exe }
- makensis.exe nsis\installer.nsi - makensis.exe nsis\installer.nsi
- ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass nsis\installer.exe } - ps: if($env:cert) { signtool sign /f $env:keyfile /p $env:certpass nsis\installer.exe }

View File

@ -24,6 +24,7 @@ ethabi = "0.2.2"
linked-hash-map = "0.3" linked-hash-map = "0.3"
parity-dapps-glue = "1.4" parity-dapps-glue = "1.4"
mime = "0.2" mime = "0.2"
time = "0.1.35"
serde_macros = { version = "0.8", optional = true } serde_macros = { version = "0.8", optional = true }
zip = { version = "0.1", default-features = false } zip = { version = "0.1", default-features = false }
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }

View File

@ -32,14 +32,15 @@ use random_filename;
use SyncStatus; use SyncStatus;
use util::{Mutex, H256}; use util::{Mutex, H256};
use util::sha3::sha3; use util::sha3::sha3;
use page::LocalPageEndpoint; use page::{LocalPageEndpoint, PageCache};
use handlers::{ContentHandler, ContentFetcherHandler, ContentValidator}; use handlers::{ContentHandler, ContentFetcherHandler, ContentValidator};
use endpoint::{Endpoint, EndpointPath, Handler}; use endpoint::{Endpoint, EndpointPath, Handler};
use apps::cache::{ContentCache, ContentStatus}; use apps::cache::{ContentCache, ContentStatus};
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest};
use apps::urlhint::{URLHintContract, URLHint, URLHintResult}; use apps::urlhint::{URLHintContract, URLHint, URLHintResult};
const MAX_CACHED_DAPPS: usize = 10; /// Limit of cached dapps/content
const MAX_CACHED_DAPPS: usize = 20;
pub struct ContentFetcher<R: URLHint = URLHintContract> { pub struct ContentFetcher<R: URLHint = URLHintContract> {
dapps_path: PathBuf, dapps_path: PathBuf,
@ -71,12 +72,13 @@ impl<R: URLHint> ContentFetcher<R> {
} }
} }
fn still_syncing() -> Box<Handler> { fn still_syncing(port: Option<u16>) -> Box<Handler> {
Box::new(ContentHandler::error( Box::new(ContentHandler::error(
StatusCode::ServiceUnavailable, StatusCode::ServiceUnavailable,
"Sync In Progress", "Sync In Progress",
"Your node is still syncing. We cannot resolve any content before it's fully synced.", "Your node is still syncing. We cannot resolve any content before it's fully synced.",
Some("<a href=\"javascript:window.location.reload()\">Refresh</a>") Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"),
port,
)) ))
} }
@ -143,19 +145,19 @@ impl<R: URLHint> ContentFetcher<R> {
match content { match content {
// Don't serve dapps if we are still syncing (but serve content) // Don't serve dapps if we are still syncing (but serve content)
Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => { Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => {
(None, Self::still_syncing()) (None, Self::still_syncing(self.embeddable_at))
}, },
Some(URLHintResult::Dapp(dapp)) => { Some(URLHintResult::Dapp(dapp)) => {
let (handler, fetch_control) = ContentFetcherHandler::new( let (handler, fetch_control) = ContentFetcherHandler::new(
dapp.url(), dapp.url(),
control, control,
path.using_dapps_domains,
DappInstaller { DappInstaller {
id: content_id.clone(), id: content_id.clone(),
dapps_path: self.dapps_path.clone(), dapps_path: self.dapps_path.clone(),
on_done: Box::new(on_done), on_done: Box::new(on_done),
embeddable_at: self.embeddable_at, embeddable_at: self.embeddable_at,
} },
self.embeddable_at,
); );
(Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>) (Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>)
@ -164,19 +166,19 @@ impl<R: URLHint> ContentFetcher<R> {
let (handler, fetch_control) = ContentFetcherHandler::new( let (handler, fetch_control) = ContentFetcherHandler::new(
content.url, content.url,
control, control,
path.using_dapps_domains,
ContentInstaller { ContentInstaller {
id: content_id.clone(), id: content_id.clone(),
mime: content.mime, mime: content.mime,
content_path: self.dapps_path.clone(), content_path: self.dapps_path.clone(),
on_done: Box::new(on_done), on_done: Box::new(on_done),
} },
self.embeddable_at,
); );
(Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>) (Some(ContentStatus::Fetching(fetch_control)), Box::new(handler) as Box<Handler>)
}, },
None if self.sync.is_major_importing() => { None if self.sync.is_major_importing() => {
(None, Self::still_syncing()) (None, Self::still_syncing(self.embeddable_at))
}, },
None => { None => {
// This may happen when sync status changes in between // This may happen when sync status changes in between
@ -185,7 +187,8 @@ impl<R: URLHint> ContentFetcher<R> {
StatusCode::NotFound, StatusCode::NotFound,
"Resource Not Found", "Resource Not Found",
"Requested resource was not found.", "Requested resource was not found.",
None None,
self.embeddable_at,
)) as Box<Handler>) )) as Box<Handler>)
}, },
} }
@ -255,6 +258,17 @@ impl ContentValidator for ContentInstaller {
// Create dir // Create dir
try!(fs::create_dir_all(&self.content_path)); 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 // And prepare path for a file
let filename = path.file_name().expect("We always fetch a file."); let filename = path.file_name().expect("We always fetch a file.");
let mut content_path = self.content_path.clone(); let mut content_path = self.content_path.clone();
@ -266,7 +280,7 @@ impl ContentValidator for ContentInstaller {
try!(fs::copy(&path, &content_path)); try!(fs::copy(&path, &content_path));
Ok((self.id.clone(), LocalPageEndpoint::single_file(content_path, self.mime.clone()))) Ok((self.id.clone(), LocalPageEndpoint::single_file(content_path, self.mime.clone(), PageCache::Enabled)))
} }
fn done(&self, endpoint: Option<LocalPageEndpoint>) { fn done(&self, endpoint: Option<LocalPageEndpoint>) {
@ -372,7 +386,7 @@ impl ContentValidator for DappInstaller {
try!(manifest_file.write_all(manifest_str.as_bytes())); try!(manifest_file.write_all(manifest_str.as_bytes()));
// Create endpoint // Create endpoint
let app = LocalPageEndpoint::new(target, manifest.clone().into(), self.embeddable_at); let app = LocalPageEndpoint::new(target, manifest.clone().into(), PageCache::Enabled, self.embeddable_at);
// Return modified app manifest // Return modified app manifest
Ok((manifest.id.clone(), app)) Ok((manifest.id.clone(), app))
@ -412,7 +426,7 @@ mod tests {
version: "".into(), version: "".into(),
author: "".into(), author: "".into(),
icon_url: "".into(), icon_url: "".into(),
}, None); }, Default::default(), None);
// when // when
fetcher.set_status("test", ContentStatus::Ready(handler)); fetcher.set_status("test", ContentStatus::Ready(handler));

View File

@ -18,7 +18,7 @@ use std::io;
use std::io::Read; use std::io::Read;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use page::LocalPageEndpoint; use page::{LocalPageEndpoint, PageCache};
use endpoint::{Endpoints, EndpointInfo}; use endpoint::{Endpoints, EndpointInfo};
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest}; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest};
@ -102,7 +102,7 @@ pub fn local_endpoints(dapps_path: String, signer_port: Option<u16>) -> Endpoint
for dapp in local_dapps(dapps_path) { for dapp in local_dapps(dapps_path) {
pages.insert( pages.insert(
dapp.id, dapp.id,
Box::new(LocalPageEndpoint::new(dapp.path, dapp.info, signer_port)) Box::new(LocalPageEndpoint::new(dapp.path, dapp.info, PageCache::Disabled, signer_port))
); );
} }
pages pages

View File

@ -33,14 +33,6 @@ pub const RPC_PATH : &'static str = "rpc";
pub const API_PATH : &'static str = "api"; pub const API_PATH : &'static str = "api";
pub const UTILS_PATH : &'static str = "parity-utils"; pub const UTILS_PATH : &'static str = "parity-utils";
pub fn redirection_address(using_dapps_domains: bool, app_id: &str) -> String {
if using_dapps_domains {
format!("http://{}{}/", app_id, DAPPS_DOMAIN)
} else {
format!("/{}/", app_id)
}
}
pub fn utils() -> Box<Endpoint> { pub fn utils() -> Box<Endpoint> {
Box::new(PageEndpoint::with_prefix(parity_ui::App::default(), UTILS_PATH.to_owned())) Box::new(PageEndpoint::with_prefix(parity_ui::App::default(), UTILS_PATH.to_owned()))
} }

View File

@ -48,11 +48,7 @@ impl ContentHandler {
Self::new_embeddable(code, content, mime!(Text/Html), embeddable_at) Self::new_embeddable(code, content, mime!(Text/Html), embeddable_at)
} }
pub fn error(code: StatusCode, title: &str, message: &str, details: Option<&str>) -> Self { pub fn error(code: StatusCode, title: &str, message: &str, details: Option<&str>, embeddable_at: Option<u16>) -> Self {
Self::error_embeddable(code, title, message, details, None)
}
pub fn error_embeddable(code: StatusCode, title: &str, message: &str, details: Option<&str>, embeddable_at: Option<u16>) -> Self {
Self::html(code, format!( Self::html(code, format!(
include_str!("../error_tpl.html"), include_str!("../error_tpl.html"),
title=title, title=title,

View File

@ -22,14 +22,14 @@ use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Instant, Duration}; use std::time::{Instant, Duration};
use util::Mutex; use util::Mutex;
use url::Url;
use fetch::{Client, Fetch, FetchResult}; use fetch::{Client, Fetch, FetchResult};
use hyper::{server, Decoder, Encoder, Next, Method, Control}; use hyper::{server, Decoder, Encoder, Next, Method, Control};
use hyper::net::HttpStream; use hyper::net::HttpStream;
use hyper::status::StatusCode; use hyper::status::StatusCode;
use handlers::{ContentHandler, Redirection}; use handlers::{ContentHandler, Redirection, extract_url};
use apps::redirection_address;
use page::LocalPageEndpoint; use page::LocalPageEndpoint;
const FETCH_TIMEOUT: u64 = 30; const FETCH_TIMEOUT: u64 = 30;
@ -136,8 +136,9 @@ pub struct ContentFetcherHandler<H: ContentValidator> {
control: Option<Control>, control: Option<Control>,
status: FetchState, status: FetchState,
client: Option<Client>, client: Option<Client>,
using_dapps_domains: bool,
installer: H, installer: H,
request_url: Option<Url>,
embeddable_at: Option<u16>,
} }
impl<H: ContentValidator> Drop for ContentFetcherHandler<H> { impl<H: ContentValidator> Drop for ContentFetcherHandler<H> {
@ -155,8 +156,9 @@ impl<H: ContentValidator> ContentFetcherHandler<H> {
pub fn new( pub fn new(
url: String, url: String,
control: Control, control: Control,
using_dapps_domains: bool, handler: H,
handler: H) -> (Self, Arc<FetchControl>) { embeddable_at: Option<u16>,
) -> (Self, Arc<FetchControl>) {
let fetch_control = Arc::new(FetchControl::default()); let fetch_control = Arc::new(FetchControl::default());
let client = Client::default(); let client = Client::default();
@ -165,8 +167,9 @@ impl<H: ContentValidator> ContentFetcherHandler<H> {
control: Some(control), control: Some(control),
client: Some(client), client: Some(client),
status: FetchState::NotStarted(url), status: FetchState::NotStarted(url),
using_dapps_domains: using_dapps_domains,
installer: handler, installer: handler,
request_url: None,
embeddable_at: embeddable_at,
}; };
(handler, fetch_control) (handler, fetch_control)
@ -189,6 +192,7 @@ impl<H: ContentValidator> ContentFetcherHandler<H> {
impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<H> { impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<H> {
fn on_request(&mut self, request: server::Request<HttpStream>) -> Next { fn on_request(&mut self, request: server::Request<HttpStream>) -> Next {
self.request_url = extract_url(&request);
let status = if let FetchState::NotStarted(ref url) = self.status { let status = if let FetchState::NotStarted(ref url) = self.status {
Some(match *request.method() { Some(match *request.method() {
// Start fetching content // Start fetching content
@ -204,6 +208,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
"Unable To Start Dapp Download", "Unable To Start Dapp Download",
"Could not initialize download of the dapp. It might be a problem with the remote server.", "Could not initialize download of the dapp. It might be a problem with the remote server.",
Some(&format!("{}", e)), Some(&format!("{}", e)),
self.embeddable_at,
)), )),
} }
}, },
@ -213,6 +218,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
"Method Not Allowed", "Method Not Allowed",
"Only <code>GET</code> requests are allowed.", "Only <code>GET</code> requests are allowed.",
None, None,
self.embeddable_at,
)), )),
}) })
} else { None }; } else { None };
@ -234,7 +240,8 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
StatusCode::GatewayTimeout, StatusCode::GatewayTimeout,
"Download Timeout", "Download Timeout",
&format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT), &format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT),
None None,
self.embeddable_at,
); );
Self::close_client(&mut self.client); Self::close_client(&mut self.client);
(Some(FetchState::Error(timeout)), Next::write()) (Some(FetchState::Error(timeout)), Next::write())
@ -255,12 +262,15 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
StatusCode::BadGateway, StatusCode::BadGateway,
"Invalid Dapp", "Invalid Dapp",
"Downloaded bundle does not contain a valid content.", "Downloaded bundle does not contain a valid content.",
Some(&format!("{:?}", e)) Some(&format!("{:?}", e)),
self.embeddable_at,
)) ))
}, },
Ok((id, result)) => { Ok((id, result)) => {
let address = redirection_address(self.using_dapps_domains, &id); let url: String = self.request_url.take()
FetchState::Done(id, result, Redirection::new(&address)) .map(|url| url.raw.into_string())
.expect("Request URL always read in on_request; qed");
FetchState::Done(id, result, Redirection::new(&url))
}, },
}; };
// Remove temporary zip file // Remove temporary zip file
@ -274,6 +284,7 @@ impl<H: ContentValidator> server::Handler<HttpStream> for ContentFetcherHandler<
"Download Error", "Download Error",
"There was an error when fetching the content.", "There was an error when fetching the content.",
Some(&format!("{:?}", e)), Some(&format!("{:?}", e)),
self.embeddable_at,
); );
(Some(FetchState::Error(error)), Next::write()) (Some(FetchState::Error(error)), Next::write())
}, },

View File

@ -44,6 +44,7 @@
#![cfg_attr(feature="nightly", plugin(clippy))] #![cfg_attr(feature="nightly", plugin(clippy))]
extern crate hyper; extern crate hyper;
extern crate time;
extern crate url as url_lib; extern crate url as url_lib;
extern crate unicase; extern crate unicase;
extern crate serde; extern crate serde;

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use page::handler; use page::{handler, PageCache};
use std::sync::Arc; use std::sync::Arc;
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
use parity_dapps::{WebApp, File, Info}; use parity_dapps::{WebApp, File, Info};
@ -80,6 +80,7 @@ impl<T: WebApp> Endpoint for PageEndpoint<T> {
prefix: self.prefix.clone(), prefix: self.prefix.clone(),
path: path, path: path,
file: handler::ServedFile::new(self.safe_to_embed_at_port.clone()), file: handler::ServedFile::new(self.safe_to_embed_at_port.clone()),
cache: PageCache::Disabled,
safe_to_embed_at_port: self.safe_to_embed_at_port.clone(), safe_to_embed_at_port: self.safe_to_embed_at_port.clone(),
}) })
} }

View File

@ -15,6 +15,8 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::io::Write; use std::io::Write;
use time::{self, Duration};
use hyper::header; use hyper::header;
use hyper::server; use hyper::server;
use hyper::uri::RequestUri; use hyper::uri::RequestUri;
@ -59,7 +61,7 @@ pub enum ServedFile<T: Dapp> {
impl<T: Dapp> ServedFile<T> { impl<T: Dapp> ServedFile<T> {
pub fn new(embeddable_at: Option<u16>) -> Self { pub fn new(embeddable_at: Option<u16>) -> Self {
ServedFile::Error(ContentHandler::error_embeddable( ServedFile::Error(ContentHandler::error(
StatusCode::NotFound, StatusCode::NotFound,
"404 Not Found", "404 Not Found",
"Requested dapp resource was not found.", "Requested dapp resource was not found.",
@ -69,6 +71,19 @@ impl<T: Dapp> ServedFile<T> {
} }
} }
/// Defines what cache headers should be appended to returned resources.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PageCache {
Enabled,
Disabled,
}
impl Default for PageCache {
fn default() -> Self {
PageCache::Disabled
}
}
/// A handler for a single webapp. /// A handler for a single webapp.
/// Resolves correct paths and serves as a plumbing code between /// Resolves correct paths and serves as a plumbing code between
/// hyper server and dapp. /// hyper server and dapp.
@ -83,6 +98,8 @@ pub struct PageHandler<T: Dapp> {
pub path: EndpointPath, pub path: EndpointPath,
/// Flag indicating if the file can be safely embeded (put in iframe). /// Flag indicating if the file can be safely embeded (put in iframe).
pub safe_to_embed_at_port: Option<u16>, pub safe_to_embed_at_port: Option<u16>,
/// Cache settings for this page.
pub cache: PageCache,
} }
impl<T: Dapp> PageHandler<T> { impl<T: Dapp> PageHandler<T> {
@ -129,9 +146,19 @@ impl<T: Dapp> server::Handler<HttpStream> for PageHandler<T> {
ServedFile::File(ref f) => { ServedFile::File(ref f) => {
res.set_status(StatusCode::Ok); res.set_status(StatusCode::Ok);
if let PageCache::Enabled = self.cache {
let mut headers = res.headers_mut();
let validity = Duration::days(365);
headers.set(header::CacheControl(vec![
header::CacheDirective::Public,
header::CacheDirective::MaxAge(validity.num_seconds() as u32),
]));
headers.set(header::Expires(header::HttpDate(time::now() + validity)));
}
match f.content_type().parse() { match f.content_type().parse() {
Ok(mime) => res.headers_mut().set(header::ContentType(mime)), Ok(mime) => res.headers_mut().set(header::ContentType(mime)),
Err(()) => debug!(target: "page_handler", "invalid MIME type: {}", f.content_type()), Err(()) => debug!(target: "dapps", "invalid MIME type: {}", f.content_type()),
} }
// Security headers: // Security headers:
@ -218,6 +245,7 @@ fn should_extract_path_with_appid() {
using_dapps_domains: true, using_dapps_domains: true,
}, },
file: ServedFile::new(None), file: ServedFile::new(None),
cache: Default::default(),
safe_to_embed_at_port: None, safe_to_embed_at_port: None,
}; };

View File

@ -18,7 +18,7 @@ use mime_guess;
use std::io::{Seek, Read, SeekFrom}; use std::io::{Seek, Read, SeekFrom};
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use page::handler; use page::handler::{self, PageCache};
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Handler};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -26,24 +26,27 @@ pub struct LocalPageEndpoint {
path: PathBuf, path: PathBuf,
mime: Option<String>, mime: Option<String>,
info: Option<EndpointInfo>, info: Option<EndpointInfo>,
cache: PageCache,
embeddable_at: Option<u16>, embeddable_at: Option<u16>,
} }
impl LocalPageEndpoint { impl LocalPageEndpoint {
pub fn new(path: PathBuf, info: EndpointInfo, embeddable_at: Option<u16>) -> Self { pub fn new(path: PathBuf, info: EndpointInfo, cache: PageCache, embeddable_at: Option<u16>) -> Self {
LocalPageEndpoint { LocalPageEndpoint {
path: path, path: path,
mime: None, mime: None,
info: Some(info), info: Some(info),
cache: cache,
embeddable_at: embeddable_at, embeddable_at: embeddable_at,
} }
} }
pub fn single_file(path: PathBuf, mime: String) -> Self { pub fn single_file(path: PathBuf, mime: String, cache: PageCache) -> Self {
LocalPageEndpoint { LocalPageEndpoint {
path: path, path: path,
mime: Some(mime), mime: Some(mime),
info: None, info: None,
cache: cache,
embeddable_at: None, embeddable_at: None,
} }
} }
@ -66,6 +69,7 @@ impl Endpoint for LocalPageEndpoint {
path: path, path: path,
file: handler::ServedFile::new(None), file: handler::ServedFile::new(None),
safe_to_embed_at_port: self.embeddable_at, safe_to_embed_at_port: self.embeddable_at,
cache: self.cache,
}) })
} else { } else {
Box::new(handler::PageHandler { Box::new(handler::PageHandler {
@ -74,6 +78,7 @@ impl Endpoint for LocalPageEndpoint {
path: path, path: path,
file: handler::ServedFile::new(None), file: handler::ServedFile::new(None),
safe_to_embed_at_port: self.embeddable_at, safe_to_embed_at_port: self.embeddable_at,
cache: self.cache,
}) })
} }
} }

View File

@ -21,4 +21,5 @@ mod handler;
pub use self::local::LocalPageEndpoint; pub use self::local::LocalPageEndpoint;
pub use self::builtin::PageEndpoint; pub use self::builtin::PageEndpoint;
pub use self::handler::PageCache;

View File

@ -59,7 +59,8 @@ impl Authorization for HttpBasicAuth {
status::StatusCode::Unauthorized, status::StatusCode::Unauthorized,
"Unauthorized", "Unauthorized",
"You need to provide valid credentials to access this page.", "You need to provide valid credentials to access this page.",
None None,
None,
))) )))
}, },
Access::AuthRequired => { Access::AuthRequired => {

View File

@ -41,6 +41,7 @@ pub fn host_invalid_response() -> Box<server::Handler<HttpStream> + Send> {
Box::new(ContentHandler::error(StatusCode::Forbidden, Box::new(ContentHandler::error(StatusCode::Forbidden,
"Current Host Is Disallowed", "Current Host Is Disallowed",
"You are trying to access your node using incorrect address.", "You are trying to access your node using incorrect address.",
Some("Use allowed URL or specify different <code>hosts</code> CLI options.") Some("Use allowed URL or specify different <code>hosts</code> CLI options."),
None,
)) ))
} }

View File

@ -117,6 +117,7 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
"404 Not Found", "404 Not Found",
"Requested content was not found.", "Requested content was not found.",
None, None,
self.signer_port,
)) ))
}, },
// Redirect any other GET request to signer. // Redirect any other GET request to signer.
@ -131,6 +132,7 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
"404 Not Found", "404 Not Found",
"Your homepage is not available when Trusted Signer is disabled.", "Your homepage is not available when Trusted Signer is disabled.",
Some("You can still access dapps by writing a correct address, though. Re-enabled Signer to get your homepage back."), Some("You can still access dapps by writing a correct address, though. Re-enabled Signer to get your homepage back."),
self.signer_port,
)) ))
} }
}, },

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use tests::helpers::{serve_with_registrar, serve_with_registrar_and_sync, request, assert_security_headers}; use tests::helpers::{serve_with_registrar, serve_with_registrar_and_sync, request, assert_security_headers_for_embed};
#[test] #[test]
fn should_resolve_dapp() { fn should_resolve_dapp() {
@ -34,7 +34,7 @@ fn should_resolve_dapp() {
// then // then
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned()); assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
assert_eq!(registrar.calls.lock().len(), 2); assert_eq!(registrar.calls.lock().len(), 2);
assert_security_headers(&response.headers); assert_security_headers_for_embed(&response.headers);
} }
#[test] #[test]
@ -63,5 +63,5 @@ fn should_return_503_when_syncing_but_should_make_the_calls() {
// then // then
assert_eq!(response.status, "HTTP/1.1 503 Service Unavailable".to_owned()); assert_eq!(response.status, "HTTP/1.1 503 Service Unavailable".to_owned());
assert_eq!(registrar.calls.lock().len(), 4); assert_eq!(registrar.calls.lock().len(), 4);
assert_security_headers(&response.headers); assert_security_headers_for_embed(&response.headers);
} }

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use tests::helpers::{serve, request, assert_security_headers}; use tests::helpers::{serve, request, assert_security_headers, assert_security_headers_for_embed};
#[test] #[test]
fn should_redirect_to_home() { fn should_redirect_to_home() {
@ -93,7 +93,7 @@ fn should_display_404_on_invalid_dapp() {
// then // then
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned()); assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
assert_security_headers(&response.headers); assert_security_headers_for_embed(&response.headers);
} }
#[test] #[test]
@ -113,7 +113,7 @@ fn should_display_404_on_invalid_dapp_with_domain() {
// then // then
assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned()); assert_eq!(response.status, "HTTP/1.1 404 Not Found".to_owned());
assert_security_headers(&response.headers); assert_security_headers_for_embed(&response.headers);
} }
#[test] #[test]

View File

@ -1,6 +1,6 @@
{ {
"name": "parity.js", "name": "parity.js",
"version": "0.1.37", "version": "0.1.47",
"main": "release/index.js", "main": "release/index.js",
"jsnext:main": "src/index.js", "jsnext:main": "src/index.js",
"author": "Parity Team <admin@parity.io>", "author": "Parity Team <admin@parity.io>",

View File

@ -58,6 +58,11 @@ export default class Ethcore {
.execute('ethcore_dropNonReservedPeers'); .execute('ethcore_dropNonReservedPeers');
} }
enode () {
return this._transport
.execute('ethcore_enode');
}
extraData () { extraData () {
return this._transport return this._transport
.execute('ethcore_extraData'); .execute('ethcore_extraData');

View File

@ -80,7 +80,9 @@ export default class RegisterAction extends Component {
modal={ sending || complete } modal={ sending || complete }
className={ styles.dialog } className={ styles.dialog }
onRequestClose={ this.onClose } onRequestClose={ this.onClose }
actions={ this.renderActions() } > actions={ this.renderActions() }
autoScrollBodyContent
>
{ this.renderContent() } { this.renderContent() }
</Dialog> </Dialog>
); );

View File

@ -85,6 +85,15 @@ export default {
} }
}, },
enode: {
desc: 'Returns the node enode URI',
params: [],
returns: {
type: String,
desc: 'Enode URI'
}
},
extraData: { extraData: {
desc: 'Returns currently set extra data', desc: 'Returns currently set extra data',
params: [], params: [],

View File

@ -136,6 +136,7 @@ export default class AddAddress extends Component {
api.personal.setAccountName(address, name), api.personal.setAccountName(address, name),
api.personal.setAccountMeta(address, { api.personal.setAccountMeta(address, {
description, description,
timestamp: Date.now(),
deleted: false deleted: false
}) })
]).catch((error) => { ]).catch((error) => {

View File

@ -145,6 +145,7 @@ export default class AddContract extends Component {
api.personal.setAccountMeta(address, { api.personal.setAccountMeta(address, {
contract: true, contract: true,
deleted: false, deleted: false,
timestamp: Date.now(),
abi: abiParsed, abi: abiParsed,
description description
}) })

View File

@ -214,7 +214,10 @@ export default class CreateAccount extends Component {
this.setState({ address }); this.setState({ address });
return api.personal return api.personal
.setAccountName(address, this.state.name) .setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint })); .then(() => api.personal.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));
}) })
.then(() => { .then(() => {
this.onNext(); this.onNext();
@ -236,7 +239,10 @@ export default class CreateAccount extends Component {
this.setState({ address }); this.setState({ address });
return api.personal return api.personal
.setAccountName(address, this.state.name) .setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint })); .then(() => api.personal.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));
}) })
.then(() => { .then(() => {
this.onNext(); this.onNext();
@ -285,7 +291,10 @@ export default class CreateAccount extends Component {
return api.personal return api.personal
.setAccountName(address, this.state.name) .setAccountName(address, this.state.name)
.then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint })); .then(() => api.personal.setAccountMeta(address, {
timestamp: Date.now(),
passwordHint: this.state.passwordHint
}));
}) })
.then(() => { .then(() => {
this.onNext(); this.onNext();

View File

@ -216,6 +216,7 @@ export default class DeployContract extends Component {
api.personal.setAccountMeta(address, { api.personal.setAccountMeta(address, {
abi: abiParsed, abi: abiParsed,
contract: true, contract: true,
timestamp: Date.now(),
deleted: false, deleted: false,
description description
}) })

View File

@ -19,7 +19,7 @@ import ActionDoneAll from 'material-ui/svg-icons/action/done-all';
import ContentClear from 'material-ui/svg-icons/content/clear'; import ContentClear from 'material-ui/svg-icons/content/clear';
import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '../../ui'; import { BusyStep, CompletedStep, Button, IdentityIcon, Modal, TxHash } from '../../ui';
import { validateAddress } from '../../util/validation'; import { validateAddress, validateUint } from '../../util/validation';
import DetailsStep from './DetailsStep'; import DetailsStep from './DetailsStep';
@ -41,6 +41,7 @@ export default class ExecuteContract extends Component {
state = { state = {
amount: '0', amount: '0',
amountError: null, amountError: null,
fromAddressError: null,
func: null, func: null,
funcError: null, funcError: null,
values: [], values: [],
@ -77,7 +78,8 @@ export default class ExecuteContract extends Component {
renderDialogActions () { renderDialogActions () {
const { onClose, fromAddress } = this.props; const { onClose, fromAddress } = this.props;
const { sending, step } = this.state; const { sending, step, fromAddressError, valuesError } = this.state;
const hasError = fromAddressError || valuesError.find((error) => error);
const cancelBtn = ( const cancelBtn = (
<Button <Button
key='cancel' key='cancel'
@ -92,7 +94,7 @@ export default class ExecuteContract extends Component {
<Button <Button
key='postTransaction' key='postTransaction'
label='post transaction' label='post transaction'
disabled={ sending } disabled={ sending || hasError }
icon={ <IdentityIcon address={ fromAddress } button /> } icon={ <IdentityIcon address={ fromAddress } button /> }
onClick={ this.postTransaction } /> onClick={ this.postTransaction } />
]; ];
@ -177,12 +179,16 @@ export default class ExecuteContract extends Component {
let valueError = null; let valueError = null;
switch (input.kind.type) { switch (input.kind.type) {
case 'address':
valueError = validateAddress(_value).addressError;
break;
case 'bool': case 'bool':
value = _value === 'true'; value = _value === 'true';
break; break;
case 'address': case 'uint':
valueError = validateAddress(_value).addressError; valueError = validateUint(_value).valueError;
break; break;
} }
@ -190,8 +196,8 @@ export default class ExecuteContract extends Component {
valuesError[index] = valueError; valuesError[index] = valueError;
this.setState({ this.setState({
values, values: [].concat(values),
valuesError valuesError: [].concat(valuesError)
}); });
} }

View File

@ -29,6 +29,20 @@ export default class Status {
this._pollPing(); this._pollPing();
this._pollStatus(); this._pollStatus();
this._pollLogs(); this._pollLogs();
this._fetchEnode();
}
_fetchEnode () {
this._api
.ethcore.enode()
.then((enode) => {
this._store.dispatch(statusCollection({ enode }));
})
.catch(() => {
window.setTimeout(() => {
this._fetchEnode();
}, 1000);
});
} }
_subscribeBlockNumber () { _subscribeBlockNumber () {
@ -68,11 +82,17 @@ export default class Status {
_pollStatus = () => { _pollStatus = () => {
const { secureToken, isConnected, isConnecting, needsToken } = this._api; const { secureToken, isConnected, isConnecting, needsToken } = this._api;
const nextTimeout = (timeout = 1000) => { const nextTimeout = (timeout = 1000) => {
setTimeout(this._pollStatus, timeout); setTimeout(this._pollStatus, timeout);
}; };
if (isConnected !== this._store.getState().nodeStatus.isConnected) {
this._fetchEnode();
}
this._store.dispatch(statusCollection({ isConnected, isConnecting, needsToken, secureToken })); this._store.dispatch(statusCollection({ isConnected, isConnecting, needsToken, secureToken }));
if (!isConnected) { if (!isConnected) {
nextTimeout(250); nextTimeout(250);
return; return;

View File

@ -25,6 +25,7 @@ const initialState = {
clientVersion: '', clientVersion: '',
coinbase: '', coinbase: '',
defaultExtraData: '', defaultExtraData: '',
enode: '',
extraData: '', extraData: '',
gasFloorTarget: new BigNumber(0), gasFloorTarget: new BigNumber(0),
hashrate: new BigNumber(0), hashrate: new BigNumber(0),

View File

@ -27,14 +27,23 @@ import styles from './sort.css';
export default class ActionbarSort extends Component { export default class ActionbarSort extends Component {
static propTypes = { static propTypes = {
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
order: PropTypes.string order: PropTypes.string,
showDefault: PropTypes.bool,
metas: PropTypes.array
}; };
static defaultProps = {
metas: [],
showDefault: true
}
state = { state = {
menuOpen: false menuOpen: false
} }
render () { render () {
const { showDefault } = this.props;
return ( return (
<IconMenu <IconMenu
iconButtonElement={ iconButtonElement={
@ -50,14 +59,56 @@ export default class ActionbarSort extends Component {
onItemTouchTap={ this.handleSortChange } onItemTouchTap={ this.handleSortChange }
targetOrigin={ { horizontal: 'right', vertical: 'top' } } targetOrigin={ { horizontal: 'right', vertical: 'top' } }
anchorOrigin={ { horizontal: 'right', vertical: 'top' } } anchorOrigin={ { horizontal: 'right', vertical: 'top' } }
touchTapCloseDelay={ 0 }
> >
<MenuItem value='' primaryText='Default' /> {
<MenuItem value='tags' primaryText='Sort by tags' /> showDefault
<MenuItem value='name' primaryText='Sort by name' /> ? this.renderMenuItem('', 'Default')
: null
}
{ this.renderMenuItem('tags', 'Sort by tags') }
{ this.renderMenuItem('name', 'Sort by name') }
{ this.renderMenuItem('eth', 'Sort by ETH') }
{ this.renderSortByMetas() }
</IconMenu> </IconMenu>
); );
} }
renderSortByMetas () {
const { metas } = this.props;
return metas
.map((meta, index) => {
return this
.renderMenuItem(meta.key, `Sort by ${meta.label}`, index);
});
}
renderMenuItem (value, label, key = null) {
const { order } = this.props;
const props = {};
if (key !== null) {
props.key = key;
}
const checked = order === value;
return (
<MenuItem
checked={ checked }
value={ value }
primaryText={ label }
innerDivStyle={ {
paddingLeft: checked ? 50 : 16
} }
{ ...props }
/>
);
}
handleSortChange = (event, child) => { handleSortChange = (event, child) => {
const order = child.props.value; const order = child.props.value;
this.props.onChange(order); this.props.onChange(order);

View File

@ -18,6 +18,7 @@
flex: 1; flex: 1;
padding: 0em; padding: 0em;
background: rgba(0, 0, 0, 0.8); background: rgba(0, 0, 0, 0.8);
height: 100%;
} }
.compact, .compact,

View File

@ -16,6 +16,7 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { MenuItem } from 'material-ui'; import { MenuItem } from 'material-ui';
import { isEqual } from 'lodash';
import AutoComplete from '../AutoComplete'; import AutoComplete from '../AutoComplete';
import IdentityIcon from '../../IdentityIcon'; import IdentityIcon from '../../IdentityIcon';
@ -24,57 +25,82 @@ import IdentityName from '../../IdentityName';
import styles from './addressSelect.css'; import styles from './addressSelect.css';
export default class AddressSelect extends Component { export default class AddressSelect extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = { static propTypes = {
disabled: PropTypes.bool, disabled: PropTypes.bool,
accounts: PropTypes.object, accounts: PropTypes.object,
contacts: PropTypes.object, contacts: PropTypes.object,
contracts: PropTypes.object,
label: PropTypes.string, label: PropTypes.string,
hint: PropTypes.string, hint: PropTypes.string,
error: PropTypes.string, error: PropTypes.string,
value: PropTypes.string, value: PropTypes.string,
tokens: PropTypes.object, tokens: PropTypes.object,
onChange: PropTypes.func.isRequired onChange: PropTypes.func.isRequired,
allowInput: PropTypes.bool
} }
state = { state = {
entries: {}, entries: {},
addresses: [],
value: '' value: ''
} }
entriesFromProps (props = this.props) {
const { accounts, contacts, contracts } = props;
const entries = Object.assign({}, accounts || {}, contacts || {}, contracts || {});
return entries;
}
componentWillMount () { componentWillMount () {
const { accounts, contacts, value } = this.props; const { value } = this.props;
const entries = Object.assign({}, accounts || {}, contacts || {}); const entries = this.entriesFromProps();
this.setState({ entries, value }); const addresses = Object.keys(entries).sort();
this.setState({ entries, addresses, value });
} }
componentWillReceiveProps (newProps) { componentWillReceiveProps (newProps) {
const { accounts, contacts } = newProps; const entries = this.entriesFromProps();
const entries = Object.assign({}, accounts || {}, contacts || {}); const addresses = Object.keys(entries).sort();
this.setState({ entries });
if (!isEqual(addresses, this.state.addresses)) {
this.setState({ entries, addresses });
}
if (newProps.value !== this.props.value) {
this.setState({ value: newProps.value });
}
} }
render () { render () {
const { disabled, error, hint, label } = this.props; const { allowInput, disabled, error, hint, label } = this.props;
const { entries } = this.state; const { entries, value } = this.state;
const value = this.getSearchText();
const searchText = this.getSearchText();
const icon = this.renderIdentityIcon(value);
return ( return (
<div className={ styles.container }> <div className={ styles.container }>
<AutoComplete <AutoComplete
className={ (error || !value) ? '' : styles.paddedInput } className={ !icon ? '' : styles.paddedInput }
disabled={ disabled } disabled={ disabled }
label={ label } label={ label }
hint={ hint ? `search for ${hint}` : 'search for an address' } hint={ hint ? `search for ${hint}` : 'search for an address' }
error={ error } error={ error }
onChange={ this.onChange } onChange={ this.onChange }
value={ value } onBlur={ this.onBlur }
onUpdateInput={ allowInput && this.onUpdateInput }
value={ searchText }
filter={ this.handleFilter } filter={ this.handleFilter }
entries={ entries } entries={ entries }
entry={ this.getEntry() || {} } entry={ this.getEntry() || {} }
renderItem={ this.renderItem } renderItem={ this.renderItem }
/> />
{ icon }
{ this.renderIdentityIcon(value) }
</div> </div>
); );
} }
@ -82,7 +108,7 @@ export default class AddressSelect extends Component {
renderIdentityIcon (inputValue) { renderIdentityIcon (inputValue) {
const { error, value } = this.props; const { error, value } = this.props;
if (error || !inputValue) { if (error || !inputValue || value.length !== 42) {
return null; return null;
} }
@ -96,8 +122,9 @@ export default class AddressSelect extends Component {
renderItem = (entry) => { renderItem = (entry) => {
return { return {
text: entry.address, text: entry.name && entry.name.toUpperCase() || entry.address,
value: this.renderSelectEntry(entry) value: this.renderSelectEntry(entry),
address: entry.address
}; };
} }
@ -127,20 +154,20 @@ export default class AddressSelect extends Component {
getSearchText () { getSearchText () {
const entry = this.getEntry(); const entry = this.getEntry();
if (!entry) return ''; const { value } = this.state;
return entry.name ? entry.name.toUpperCase() : ''; return entry && entry.name
? entry.name.toUpperCase()
: value;
} }
getEntry () { getEntry () {
const { value } = this.props; const { entries, value } = this.state;
if (!value) return ''; return value ? entries[value] : null;
const { entries } = this.state;
return entries[value];
} }
handleFilter = (searchText, address) => { handleFilter = (searchText, name, item) => {
const { address } = item;
const entry = this.state.entries[address]; const entry = this.state.entries[address];
const lowCaseSearch = searchText.toLowerCase(); const lowCaseSearch = searchText.toLowerCase();
@ -149,10 +176,26 @@ export default class AddressSelect extends Component {
} }
onChange = (entry, empty) => { onChange = (entry, empty) => {
const { allowInput } = this.props;
const { value } = this.state;
const address = entry && entry.address const address = entry && entry.address
? entry.address ? entry.address
: (empty ? '' : this.state.value); : ((empty && !allowInput) ? '' : value);
this.props.onChange(null, address); this.props.onChange(null, address);
} }
onUpdateInput = (query, choices) => {
const { api } = this.context;
const address = query.trim();
if (!/^0x/.test(address) && api.util.isAddressValid(`0x${address}`)) {
const checksumed = api.util.toChecksumAddress(`0x${address}`);
return this.props.onChange(null, checksumed);
}
this.props.onChange(null, address);
};
} }

View File

@ -21,6 +21,7 @@ import { PopoverAnimationVertical } from 'material-ui/Popover';
export default class AutoComplete extends Component { export default class AutoComplete extends Component {
static propTypes = { static propTypes = {
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
onUpdateInput: PropTypes.func,
disabled: PropTypes.bool, disabled: PropTypes.bool,
label: PropTypes.string, label: PropTypes.string,
hint: PropTypes.string, hint: PropTypes.string,
@ -43,7 +44,7 @@ export default class AutoComplete extends Component {
} }
render () { render () {
const { disabled, error, hint, label, value, className, filter } = this.props; const { disabled, error, hint, label, value, className, filter, onUpdateInput } = this.props;
const { open } = this.state; const { open } = this.state;
return ( return (
@ -54,11 +55,11 @@ export default class AutoComplete extends Component {
hintText={ hint } hintText={ hint }
errorText={ error } errorText={ error }
onNewRequest={ this.onChange } onNewRequest={ this.onChange }
onUpdateInput={ onUpdateInput }
searchText={ value } searchText={ value }
onFocus={ this.onFocus } onFocus={ this.onFocus }
onBlur={ this.onBlur } onBlur={ this.onBlur }
animation={ PopoverAnimationVertical } animation={ PopoverAnimationVertical }
filter={ filter } filter={ filter }
popoverProps={ { open } } popoverProps={ { open } }
openOnFocus openOnFocus
@ -108,12 +109,18 @@ export default class AutoComplete extends Component {
} }
onBlur = () => { onBlur = () => {
const { onUpdateInput } = this.props;
// TODO: Handle blur gracefully where we use onUpdateInput (currently replaces input
// input where text is allowed with the last selected value from the dropdown)
if (!onUpdateInput) {
window.setTimeout(() => { window.setTimeout(() => {
const { entry } = this.state; const { entry } = this.state;
this.handleOnChange(entry); this.handleOnChange(entry);
}, 100); }, 100);
} }
}
onFocus = () => { onFocus = () => {
const { entry } = this.props; const { entry } = this.props;
@ -131,5 +138,4 @@ export default class AutoComplete extends Component {
this.props.onChange(value, empty); this.props.onChange(value, empty);
} }
} }
} }

View File

@ -26,8 +26,16 @@
padding-left: 0 !important; padding-left: 0 !important;
} }
.icon { .icon,
.iconDisabled {
position: absolute; position: absolute;
top: 35px; top: 35px;
}
.icon {
left: 0;
}
.iconDisabled {
left: 24px; left: 24px;
} }

View File

@ -69,14 +69,14 @@ class InputAddress extends Component {
} }
renderIcon () { renderIcon () {
const { value } = this.props; const { value, disabled } = this.props;
if (!value || !value.length || !util.isAddressValid(value)) { if (!value || !value.length || !util.isAddressValid(value)) {
return null; return null;
} }
return ( return (
<div className={ styles.icon }> <div className={ disabled ? styles.iconDisabled : styles.icon }>
<IdentityIcon <IdentityIcon
inline center inline center
address={ value } /> address={ value } />

View File

@ -1,31 +0,0 @@
/* Copyright 2015, 2016 Ethcore (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/>.
*/
.inputselect {
position: relative;
}
.inputselect svg {
padding-right: 84px;
}
.toggle {
position: absolute !important;
top: 38px;
right: 0;
display: inline-block !important;
width: auto !important;
}

View File

@ -17,103 +17,46 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { Toggle } from 'material-ui';
import AddressSelect from '../AddressSelect'; import AddressSelect from '../AddressSelect';
import InputAddress from '../InputAddress';
import styles from './inputAddressSelect.css';
class InputAddressSelect extends Component { class InputAddressSelect extends Component {
static propTypes = { static propTypes = {
accounts: PropTypes.object, accounts: PropTypes.object.isRequired,
contacts: PropTypes.object, contacts: PropTypes.object.isRequired,
disabled: PropTypes.bool, contracts: PropTypes.object.isRequired,
editing: PropTypes.bool,
error: PropTypes.string, error: PropTypes.string,
label: PropTypes.string, label: PropTypes.string,
hint: PropTypes.string, hint: PropTypes.string,
value: PropTypes.string, value: PropTypes.string,
tokens: PropTypes.object,
onChange: PropTypes.func onChange: PropTypes.func
}; };
state = {
editing: this.props.editing || false,
entries: []
}
render () { render () {
const { editing } = this.state; const { accounts, contacts, contracts, label, hint, error, value, onChange } = this.props;
return (
<div className={ styles.inputselect }>
{ editing ? this.renderInput() : this.renderSelect() }
<Toggle
className={ styles.toggle }
label='Edit'
labelPosition='right'
toggled={ editing }
onToggle={ this.onToggle } />
</div>
);
}
renderInput () {
const { disabled, error, hint, label, value, tokens } = this.props;
return (
<InputAddress
disabled={ disabled }
error={ error }
hint={ hint }
label={ label }
value={ value }
tokens={ tokens }
onChange={ this.onChangeInput } />
);
}
renderSelect () {
const { accounts, contacts, disabled, error, hint, label, value, tokens } = this.props;
return ( return (
<AddressSelect <AddressSelect
allowInput
accounts={ accounts } accounts={ accounts }
contacts={ contacts } contacts={ contacts }
disabled={ disabled } contracts={ contracts }
error={ error }
label={ label } label={ label }
hint={ hint } hint={ hint }
error={ error }
value={ value } value={ value }
tokens={ tokens } onChange={ onChange } />
onChange={ this.onChangeSelect } />
); );
} }
onToggle = () => {
const { editing } = this.state;
this.setState({
editing: !editing
});
}
onChangeInput = (event, value) => {
this.props.onChange(event, value);
}
onChangeSelect = (event, value) => {
this.props.onChange(event, value);
}
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { accounts, contacts } = state.personal; const { accounts, contacts, contracts } = state.personal;
return { return {
accounts, accounts,
contacts contacts,
contracts
}; };
} }

View File

@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import util from '../api/util'; import util from '../api/util';
export const ERRORS = { export const ERRORS = {
@ -22,7 +24,10 @@ export const ERRORS = {
invalidChecksum: 'address has failed the checksum formatting', invalidChecksum: 'address has failed the checksum formatting',
invalidName: 'name should not be blank and longer than 2', invalidName: 'name should not be blank and longer than 2',
invalidAbi: 'abi should be a valid JSON array', invalidAbi: 'abi should be a valid JSON array',
invalidCode: 'code should be the compiled hex string' invalidCode: 'code should be the compiled hex string',
invalidNumber: 'invalid number format',
negativeNumber: 'input number should be positive',
decimalNumber: 'input number should not contain decimals'
}; };
export function validateAbi (abi, api) { export function validateAbi (abi, api) {
@ -88,3 +93,23 @@ export function validateName (name) {
nameError nameError
}; };
} }
export function validateUint (value) {
let valueError = null;
try {
const bn = new BigNumber(value);
if (bn.lt(0)) {
valueError = ERRORS.negativeNumber;
} else if (bn.toString().indexOf('.') !== -1) {
valueError = ERRORS.decimalNumber;
}
} catch (e) {
valueError = ERRORS.invalidNumber;
}
return {
value,
valueError
};
}

View File

@ -29,6 +29,7 @@ export default class List extends Component {
search: PropTypes.array, search: PropTypes.array,
empty: PropTypes.bool, empty: PropTypes.bool,
order: PropTypes.string, order: PropTypes.string,
orderFallback: PropTypes.string,
handleAddSearchToken: PropTypes.func handleAddSearchToken: PropTypes.func
}; };
@ -79,9 +80,9 @@ export default class List extends Component {
} }
sortAddresses (addresses) { sortAddresses (addresses) {
const { order } = this.props; const { order, orderFallback } = this.props;
if (!order || ['tags', 'name'].indexOf(order) === -1) { if (!order) {
return addresses; return addresses;
} }
@ -91,24 +92,75 @@ export default class List extends Component {
const accountA = accounts[addressA]; const accountA = accounts[addressA];
const accountB = accounts[addressB]; const accountB = accounts[addressB];
if (order === 'name') { const sort = this.compareAccounts(accountA, accountB, order);
if (sort === 0 && orderFallback) {
return this.compareAccounts(accountA, accountB, orderFallback);
}
return sort;
});
}
compareAccounts (accountA, accountB, key) {
if (key === 'name') {
return accountA.name.localeCompare(accountB.name); return accountA.name.localeCompare(accountB.name);
} }
if (order === 'tags') { if (key === 'eth') {
const { balances } = this.props;
const balanceA = balances[accountA.address];
const balanceB = balances[accountB.address];
if (!balanceA && !balanceB) return 0;
if (balanceA && !balanceB) return -1;
if (!balanceA && balanceB) return 1;
const ethA = balanceA.tokens
.find(token => token.token.tag.toLowerCase() === 'eth')
.value;
const ethB = balanceB.tokens
.find(token => token.token.tag.toLowerCase() === 'eth')
.value;
return -1 * ethA.comparedTo(ethB);
}
if (key === 'tags') {
const tagsA = [].concat(accountA.meta.tags) const tagsA = [].concat(accountA.meta.tags)
.filter(t => t) .filter(t => t)
.sort(); .sort()
.join('');
const tagsB = [].concat(accountB.meta.tags) const tagsB = [].concat(accountB.meta.tags)
.filter(t => t) .filter(t => t)
.sort(); .sort()
.join('');
if (tagsA.length === 0) return 1; if (!tagsA && !tagsB) return 0;
if (tagsB.length === 0) return -1; if (tagsA && !tagsB) return -1;
if (!tagsA && tagsB) return 1;
return tagsA.join('').localeCompare(tagsB.join('')); return tagsA.localeCompare(tagsB);
} }
});
const metaA = accountA.meta[key];
const metaB = accountB.meta[key];
if (!metaA && !metaB) {
return 0;
}
if ((metaA && !metaB) || (metaA < metaB)) {
return -1;
}
if ((!metaA && metaB) || (metaA > metaB)) {
return 1;
}
return 0;
} }
getFilteredAddresses () { getFilteredAddresses () {

View File

@ -15,16 +15,24 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>. /* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/ */
.status { .status {
clear: both;
padding: 1.5em; padding: 1.5em;
text-align: right; text-align: right;
color: #ddd; color: #ddd;
display: flex;
flex-direction: column;
align-items: flex-end;
} }
.title { .title {
margin: 0 0.5em 0 2em; margin: 0 0.5em 0 2em;
} }
.enode {
width: 45em;
word-wrap: break-word;
margin: 0.5em 0 0.25em;
}
.block { .block {
} }

View File

@ -26,6 +26,7 @@ class Status extends Component {
static propTypes = { static propTypes = {
blockNumber: PropTypes.object.isRequired, blockNumber: PropTypes.object.isRequired,
clientVersion: PropTypes.string, clientVersion: PropTypes.string,
enode: PropTypes.string,
netPeers: PropTypes.object, netPeers: PropTypes.object,
netChain: PropTypes.string, netChain: PropTypes.string,
isTest: PropTypes.bool isTest: PropTypes.bool
@ -44,6 +45,7 @@ class Status extends Component {
<div className={ styles.version }> <div className={ styles.version }>
{ clientVersion } { clientVersion }
</div> </div>
{ this.renderEnode() }
<div className={ styles.netinfo }> <div className={ styles.netinfo }>
<div> <div>
<BlockStatus /> <BlockStatus />
@ -58,14 +60,29 @@ class Status extends Component {
</div> </div>
); );
} }
renderEnode () {
const { enode } = this.props;
if (!enode) {
return null;
}
return (
<div className={ styles.enode }>
{ enode }
</div>
);
}
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { blockNumber, clientVersion, netPeers, netChain, isTest } = state.nodeStatus; const { blockNumber, clientVersion, enode, netPeers, netChain, isTest } = state.nodeStatus;
return { return {
blockNumber, blockNumber,
clientVersion, clientVersion,
enode,
netPeers, netPeers,
netChain, netChain,
isTest isTest

View File

@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
import LinearProgress from 'material-ui/LinearProgress'; import LinearProgress from 'material-ui/LinearProgress';
import { Card, CardActions, CardTitle, CardText } from 'material-ui/Card'; import { Card, CardActions, CardTitle, CardText } from 'material-ui/Card';
import { Button, Input } from '../../../ui'; import { Button, Input, InputAddressSelect } from '../../../ui';
import styles from './queries.css'; import styles from './queries.css';
@ -124,8 +124,8 @@ export default class InputQuery extends Component {
const { name, type } = input; const { name, type } = input;
const label = `${name ? `${name}: ` : ''}${type}`; const label = `${name ? `${name}: ` : ''}${type}`;
const onChange = (event) => { const onChange = (event, input) => {
const value = event.target.value; const value = event && event.target.value || input;
const { values } = this.state; const { values } = this.state;
this.setState({ this.setState({
@ -136,6 +136,19 @@ export default class InputQuery extends Component {
}); });
}; };
if (type === 'address') {
return (
<div key={ name }>
<InputAddressSelect
hint={ type }
label={ label }
required
onChange={ onChange }
/>
</div>
);
}
return ( return (
<div key={ name }> <div key={ name }>
<Input <Input

View File

@ -39,6 +39,7 @@
.txhash { .txhash {
text-overflow: ellipsis; text-overflow: ellipsis;
width: 20%;
} }
.key { .key {
@ -82,6 +83,7 @@
.eventAddress { .eventAddress {
display: inline-block; display: inline-block;
position: relative; position: relative;
white-space: nowrap;
} }
.eventIdentityicon { .eventIdentityicon {

View File

@ -312,7 +312,7 @@ class Contract extends Component {
const contract = api.newContract(account.meta.abi, params.address); const contract = api.newContract(account.meta.abi, params.address);
contract contract
.subscribe(null, { limit: 50, fromBlock: 0, toBlock: 'pending' }, this._receiveEvents) .subscribe(null, { limit: 25, fromBlock: 0, toBlock: 'pending' }, this._receiveEvents)
.then((subscriptionId) => { .then((subscriptionId) => {
this.setState({ subscriptionId }); this.setState({ subscriptionId });
}); });

View File

@ -42,7 +42,7 @@ class Contracts extends Component {
state = { state = {
addContract: false, addContract: false,
deployContract: false, deployContract: false,
sortOrder: '', sortOrder: 'timestamp',
searchValues: [], searchValues: [],
searchTokens: [] searchTokens: []
} }
@ -65,6 +65,7 @@ class Contracts extends Component {
balances={ balances } balances={ balances }
empty={ !hasContracts } empty={ !hasContracts }
order={ sortOrder } order={ sortOrder }
orderFallback='name'
handleAddSearchToken={ this.onAddSearchToken } /> handleAddSearchToken={ this.onAddSearchToken } />
</Page> </Page>
</div> </div>
@ -80,6 +81,10 @@ class Contracts extends Component {
<ActionbarSort <ActionbarSort
key='sortAccounts' key='sortAccounts'
order={ this.state.sortOrder } order={ this.state.sortOrder }
metas={ [
{ key: 'timestamp', label: 'date' }
] }
showDefault={ false }
onChange={ onChange } /> onChange={ onChange } />
); );
} }

View File

@ -36,7 +36,7 @@ use regex::Regex;
use util::RotatingLogger; use util::RotatingLogger;
use util::log::Colour; use util::log::Colour;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub struct Config { pub struct Config {
pub mode: Option<String>, pub mode: Option<String>,
pub color: bool, pub color: bool,

View File

@ -1,3 +1,9 @@
!include WinMessages.nsh
!define WND_CLASS "Parity"
!define WND_TITLE "Parity"
!define WAIT_MS 5000
!define SYNC_TERM 0x00100001
!define APPNAME "Parity" !define APPNAME "Parity"
!define COMPANYNAME "Ethcore" !define COMPANYNAME "Ethcore"
@ -5,6 +11,7 @@
!define VERSIONMAJOR 1 !define VERSIONMAJOR 1
!define VERSIONMINOR 4 !define VERSIONMINOR 4
!define VERSIONBUILD 0 !define VERSIONBUILD 0
!define ARGS "--warp --mode=passive"
!addplugindir .\ !addplugindir .\
@ -13,6 +20,10 @@
!define ABOUTURL "https://github.com/ethcore/parity" # "Publisher" link !define ABOUTURL "https://github.com/ethcore/parity" # "Publisher" link
!define INSTALLSIZE 26120 !define INSTALLSIZE 26120
!define termMsg "Installer cannot stop running ${WND_TITLE}.$\nDo you want to terminate process?"
!define stopMsg "Stopping ${WND_TITLE} Application"
RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on) RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on)
InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}" InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}"
@ -26,7 +37,7 @@ outFile "installer.exe"
page license page license
page directory page directory
Page instfiles page instfiles
!macro VerifyUserIsAdmin !macro VerifyUserIsAdmin
UserInfo::GetAccountType UserInfo::GetAccountType
@ -38,6 +49,31 @@ ${If} $0 != "admin" ;Require admin rights on NT4+
${EndIf} ${EndIf}
!macroend !macroend
!macro TerminateApp
Push $0 ; window handle
Push $1
Push $2 ; process handle
DetailPrint "$(stopMsg)"
FindWindow $0 '${WND_CLASS}' ''
IntCmp $0 0 done
System::Call 'user32.dll::GetWindowThreadProcessId(i r0, *i .r1) i .r2'
System::Call 'kernel32.dll::OpenProcess(i ${SYNC_TERM}, i 0, i r1) i .r2'
SendMessage $0 ${WM_CLOSE} 0 0 /TIMEOUT=${TO_MS}
System::Call 'kernel32.dll::WaitForSingleObject(i r2, i ${WAIT_MS}) i .r1'
IntCmp $1 0 close
MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION "$(termMsg)" /SD IDYES IDYES terminate IDNO close
System::Call 'kernel32.dll::CloseHandle(i r2) i .r1'
Quit
terminate:
System::Call 'kernel32.dll::TerminateProcess(i r2, i 0) i .r1'
close:
System::Call 'kernel32.dll::CloseHandle(i r2) i .r1'
done:
Pop $2
Pop $1
Pop $0
!macroend
function .onInit function .onInit
setShellVarContext all setShellVarContext all
!insertmacro VerifyUserIsAdmin !insertmacro VerifyUserIsAdmin
@ -48,10 +84,13 @@ section "install"
setOutPath $INSTDIR setOutPath $INSTDIR
# Files added here should be removed by the uninstaller (see section "uninstall") # Files added here should be removed by the uninstaller (see section "uninstall")
file /oname=parity.exe ..\target\release\parity.exe file /oname=parity.exe ..\target\release\parity.exe
file /oname=ptray.exe ..\windows\ptray\Release\ptray.exe
file "logo.ico" file "logo.ico"
file vc_redist.x64.exe file vc_redist.x64.exe
ExecWait '"$INSTDIR\vc_redist.x64.exe" /passive /norestart' ExecWait '"$INSTDIR\vc_redist.x64.exe" /passive /norestart'
delete $INSTDIR\vc_redist.x64.exe
# Add any other files for the install directory (license files, app data, etc) here # Add any other files for the install directory (license files, app data, etc) here
# Uninstaller - See function un.onInit and section "uninstall" for configuration # Uninstaller - See function un.onInit and section "uninstall" for configuration
@ -79,11 +118,11 @@ section "install"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "InstallLocation" "$\"$INSTDIR$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "InstallLocation" "$\"$INSTDIR$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\logo.ico$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\logo.ico$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "$\"${COMPANYNAME}$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "${COMPANYNAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "HelpLink" "$\"${HELPURL}$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "HelpLink" "$\"${HELPURL}$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLUpdateInfo" "$\"${UPDATEURL}$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLUpdateInfo" "$\"${UPDATEURL}$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" "$\"${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR} WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR}
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR} WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR}
# There is no option for modifying or repairing the install # There is no option for modifying or repairing the install
@ -91,6 +130,9 @@ section "install"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoRepair" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoRepair" 1
# Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size # Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "EstimatedSize" ${INSTALLSIZE} WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "EstimatedSize" ${INSTALLSIZE}
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Run" ${APPNAME} "$INSTDIR\ptray.exe ${ARGS}"
ExecShell "" "$INSTDIR\ptray.exe" "${ARGS}"
sectionEnd sectionEnd
# Uninstaller # Uninstaller
@ -107,7 +149,7 @@ function un.onInit
functionEnd functionEnd
section "uninstall" section "uninstall"
!insertmacro TerminateApp
# Remove Start Menu launcher # Remove Start Menu launcher
delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk"
# Try to remove the Start Menu folder - this will only happen if it is empty # Try to remove the Start Menu folder - this will only happen if it is empty
@ -115,6 +157,7 @@ section "uninstall"
# Remove files # Remove files
delete $INSTDIR\parity.exe delete $INSTDIR\parity.exe
delete $INSTDIR\ptray.exe
delete $INSTDIR\logo.ico delete $INSTDIR\logo.ico
# Always delete uninstaller as the last action # Always delete uninstaller as the last action
@ -131,5 +174,6 @@ section "uninstall"
# Remove uninstaller information from the registry # Remove uninstaller information from the registry
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}"
DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPNAME}"
sectionEnd sectionEnd

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -21,7 +21,6 @@ use std::time::{Instant, Duration};
use std::thread::sleep; use std::thread::sleep;
use std::sync::Arc; use std::sync::Arc;
use rustc_serialize::hex::FromHex; use rustc_serialize::hex::FromHex;
use ethcore_logger::{setup_log, Config as LogConfig};
use io::{PanicHandler, ForwardPanic}; use io::{PanicHandler, ForwardPanic};
use util::{ToPretty, Uint}; use util::{ToPretty, Uint};
use rlp::PayloadInfo; use rlp::PayloadInfo;
@ -71,7 +70,6 @@ pub enum BlockchainCmd {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct ImportBlockchain { pub struct ImportBlockchain {
pub spec: SpecType, pub spec: SpecType,
pub logger_config: LogConfig,
pub cache_config: CacheConfig, pub cache_config: CacheConfig,
pub dirs: Directories, pub dirs: Directories,
pub file_path: Option<String>, pub file_path: Option<String>,
@ -85,12 +83,12 @@ pub struct ImportBlockchain {
pub fat_db: Switch, pub fat_db: Switch,
pub vm_type: VMType, pub vm_type: VMType,
pub check_seal: bool, pub check_seal: bool,
pub with_color: bool,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct ExportBlockchain { pub struct ExportBlockchain {
pub spec: SpecType, pub spec: SpecType,
pub logger_config: LogConfig,
pub cache_config: CacheConfig, pub cache_config: CacheConfig,
pub dirs: Directories, pub dirs: Directories,
pub file_path: Option<String>, pub file_path: Option<String>,
@ -120,9 +118,6 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
// Setup panic handler // Setup panic handler
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();
// Setup logging
let _logger = setup_log(&cmd.logger_config);
// create dirs used by parity // create dirs used by parity
try!(cmd.dirs.create_dirs()); try!(cmd.dirs.create_dirs());
@ -196,7 +191,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<String, String> {
} }
}; };
let informant = Informant::new(client.clone(), None, None, None, cmd.logger_config.color); let informant = Informant::new(client.clone(), None, None, None, cmd.with_color);
try!(service.register_io_handler(Arc::new(ImportIoHandler { try!(service.register_io_handler(Arc::new(ImportIoHandler {
info: Arc::new(informant), info: Arc::new(informant),
@ -269,9 +264,6 @@ fn execute_export(cmd: ExportBlockchain) -> Result<String, String> {
// Setup panic handler // Setup panic handler
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();
// Setup logging
let _logger = setup_log(&cmd.logger_config);
// create dirs used by parity // create dirs used by parity
try!(cmd.dirs.create_dirs()); try!(cmd.dirs.create_dirs());

View File

@ -35,7 +35,7 @@ use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras};
use ethcore_logger::Config as LogConfig; use ethcore_logger::Config as LogConfig;
use dir::Directories; use dir::Directories;
use dapps::Configuration as DappsConfiguration; use dapps::Configuration as DappsConfiguration;
use signer::Configuration as SignerConfiguration; use signer::{Configuration as SignerConfiguration, SignerCommand};
use run::RunCmd; use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat}; use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
use presale::ImportWallet; use presale::ImportWallet;
@ -49,11 +49,16 @@ pub enum Cmd {
Account(AccountCmd), Account(AccountCmd),
ImportPresaleWallet(ImportWallet), ImportPresaleWallet(ImportWallet),
Blockchain(BlockchainCmd), Blockchain(BlockchainCmd),
SignerToken(String), SignerToken(SignerCommand),
Snapshot(SnapshotCommand), Snapshot(SnapshotCommand),
Hash(Option<String>), Hash(Option<String>),
} }
pub struct Execute {
pub logger: LogConfig,
pub cmd: Cmd,
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Configuration { pub struct Configuration {
pub args: Args, pub args: Args,
@ -70,7 +75,7 @@ impl Configuration {
Ok(config) Ok(config)
} }
pub fn into_command(self) -> Result<Cmd, String> { pub fn into_command(self) -> Result<Execute, String> {
let dirs = self.directories(); let dirs = self.directories();
let pruning = try!(self.args.flag_pruning.parse()); let pruning = try!(self.args.flag_pruning.parse());
let pruning_history = self.args.flag_pruning_history; let pruning_history = self.args.flag_pruning_history;
@ -99,7 +104,9 @@ impl Configuration {
let cmd = if self.args.flag_version { let cmd = if self.args.flag_version {
Cmd::Version Cmd::Version
} else if self.args.cmd_signer && self.args.cmd_new_token { } else if self.args.cmd_signer && self.args.cmd_new_token {
Cmd::SignerToken(dirs.signer) Cmd::SignerToken(SignerCommand {
path: dirs.signer
})
} else if self.args.cmd_tools && self.args.cmd_hash { } else if self.args.cmd_tools && self.args.cmd_hash {
Cmd::Hash(self.args.arg_file) Cmd::Hash(self.args.arg_file)
} else if self.args.cmd_account { } else if self.args.cmd_account {
@ -141,7 +148,6 @@ impl Configuration {
} else if self.args.cmd_import { } else if self.args.cmd_import {
let import_cmd = ImportBlockchain { let import_cmd = ImportBlockchain {
spec: spec, spec: spec,
logger_config: logger_config,
cache_config: cache_config, cache_config: cache_config,
dirs: dirs, dirs: dirs,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_file.clone(),
@ -155,12 +161,12 @@ impl Configuration {
fat_db: fat_db, fat_db: fat_db,
vm_type: vm_type, vm_type: vm_type,
check_seal: !self.args.flag_no_seal_check, check_seal: !self.args.flag_no_seal_check,
with_color: logger_config.color,
}; };
Cmd::Blockchain(BlockchainCmd::Import(import_cmd)) Cmd::Blockchain(BlockchainCmd::Import(import_cmd))
} else if self.args.cmd_export { } else if self.args.cmd_export {
let export_cmd = ExportBlockchain { let export_cmd = ExportBlockchain {
spec: spec, spec: spec,
logger_config: logger_config,
cache_config: cache_config, cache_config: cache_config,
dirs: dirs, dirs: dirs,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_file.clone(),
@ -184,7 +190,6 @@ impl Configuration {
spec: spec, spec: spec,
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
logger_config: logger_config,
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db, fat_db: fat_db,
@ -202,7 +207,6 @@ impl Configuration {
spec: spec, spec: spec,
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
logger_config: logger_config,
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db, fat_db: fat_db,
@ -227,7 +231,7 @@ impl Configuration {
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
daemon: daemon, daemon: daemon,
logger_config: logger_config, logger_config: logger_config.clone(),
miner_options: miner_options, miner_options: miner_options,
http_conf: http_conf, http_conf: http_conf,
ipc_conf: ipc_conf, ipc_conf: ipc_conf,
@ -258,7 +262,10 @@ impl Configuration {
Cmd::Run(run_cmd) Cmd::Run(run_cmd)
}; };
Ok(cmd) Ok(Execute {
logger: logger_config,
cmd: cmd,
})
} }
fn enable_network(&self, mode: &Mode) -> bool { fn enable_network(&self, mode: &Mode) -> bool {
@ -684,7 +691,7 @@ mod tests {
use ethcore::miner::{MinerOptions, PrioritizationStrategy}; use ethcore::miner::{MinerOptions, PrioritizationStrategy};
use helpers::{replace_home, default_network_config}; use helpers::{replace_home, default_network_config};
use run::RunCmd; use run::RunCmd;
use signer::Configuration as SignerConfiguration; use signer::{Configuration as SignerConfiguration, SignerCommand};
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat}; use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat};
use presale::ImportWallet; use presale::ImportWallet;
use account::{AccountCmd, NewAccount, ImportAccounts}; use account::{AccountCmd, NewAccount, ImportAccounts};
@ -705,14 +712,14 @@ mod tests {
fn test_command_version() { fn test_command_version() {
let args = vec!["parity", "--version"]; let args = vec!["parity", "--version"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Version); assert_eq!(conf.into_command().unwrap().cmd, Cmd::Version);
} }
#[test] #[test]
fn test_command_account_new() { fn test_command_account_new() {
let args = vec!["parity", "account", "new"]; let args = vec!["parity", "account", "new"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Account(AccountCmd::New(NewAccount { assert_eq!(conf.into_command().unwrap().cmd, Cmd::Account(AccountCmd::New(NewAccount {
iterations: 10240, iterations: 10240,
path: replace_home("$HOME/.parity/keys"), path: replace_home("$HOME/.parity/keys"),
password_file: None, password_file: None,
@ -723,16 +730,16 @@ mod tests {
fn test_command_account_list() { fn test_command_account_list() {
let args = vec!["parity", "account", "list"]; let args = vec!["parity", "account", "list"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Account( assert_eq!(conf.into_command().unwrap().cmd, Cmd::Account(
AccountCmd::List(replace_home("$HOME/.parity/keys"))) AccountCmd::List(replace_home("$HOME/.parity/keys")),
); ));
} }
#[test] #[test]
fn test_command_account_import() { fn test_command_account_import() {
let args = vec!["parity", "account", "import", "my_dir", "another_dir"]; let args = vec!["parity", "account", "import", "my_dir", "another_dir"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Account(AccountCmd::Import(ImportAccounts { assert_eq!(conf.into_command().unwrap().cmd, Cmd::Account(AccountCmd::Import(ImportAccounts {
from: vec!["my_dir".into(), "another_dir".into()], from: vec!["my_dir".into(), "another_dir".into()],
to: replace_home("$HOME/.parity/keys"), to: replace_home("$HOME/.parity/keys"),
}))); })));
@ -742,7 +749,7 @@ mod tests {
fn test_command_wallet_import() { fn test_command_wallet_import() {
let args = vec!["parity", "wallet", "import", "my_wallet.json", "--password", "pwd"]; let args = vec!["parity", "wallet", "import", "my_wallet.json", "--password", "pwd"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::ImportPresaleWallet(ImportWallet { assert_eq!(conf.into_command().unwrap().cmd, Cmd::ImportPresaleWallet(ImportWallet {
iterations: 10240, iterations: 10240,
path: replace_home("$HOME/.parity/keys"), path: replace_home("$HOME/.parity/keys"),
wallet_path: "my_wallet.json".into(), wallet_path: "my_wallet.json".into(),
@ -754,9 +761,8 @@ mod tests {
fn test_command_blockchain_import() { fn test_command_blockchain_import() {
let args = vec!["parity", "import", "blockchain.json"]; let args = vec!["parity", "import", "blockchain.json"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Blockchain(BlockchainCmd::Import(ImportBlockchain { assert_eq!(conf.into_command().unwrap().cmd, Cmd::Blockchain(BlockchainCmd::Import(ImportBlockchain {
spec: Default::default(), spec: Default::default(),
logger_config: Default::default(),
cache_config: Default::default(), cache_config: Default::default(),
dirs: Default::default(), dirs: Default::default(),
file_path: Some("blockchain.json".into()), file_path: Some("blockchain.json".into()),
@ -770,6 +776,7 @@ mod tests {
fat_db: Default::default(), fat_db: Default::default(),
vm_type: VMType::Interpreter, vm_type: VMType::Interpreter,
check_seal: true, check_seal: true,
with_color: !cfg!(windows),
}))); })));
} }
@ -777,9 +784,8 @@ mod tests {
fn test_command_blockchain_export() { fn test_command_blockchain_export() {
let args = vec!["parity", "export", "blockchain.json"]; let args = vec!["parity", "export", "blockchain.json"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Blockchain(BlockchainCmd::Export(ExportBlockchain { assert_eq!(conf.into_command().unwrap().cmd, Cmd::Blockchain(BlockchainCmd::Export(ExportBlockchain {
spec: Default::default(), spec: Default::default(),
logger_config: Default::default(),
cache_config: Default::default(), cache_config: Default::default(),
dirs: Default::default(), dirs: Default::default(),
file_path: Some("blockchain.json".into()), file_path: Some("blockchain.json".into()),
@ -801,9 +807,8 @@ mod tests {
fn test_command_blockchain_export_with_custom_format() { fn test_command_blockchain_export_with_custom_format() {
let args = vec!["parity", "export", "--format", "hex", "blockchain.json"]; let args = vec!["parity", "export", "--format", "hex", "blockchain.json"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Blockchain(BlockchainCmd::Export(ExportBlockchain { assert_eq!(conf.into_command().unwrap().cmd, Cmd::Blockchain(BlockchainCmd::Export(ExportBlockchain {
spec: Default::default(), spec: Default::default(),
logger_config: Default::default(),
cache_config: Default::default(), cache_config: Default::default(),
dirs: Default::default(), dirs: Default::default(),
file_path: Some("blockchain.json".into()), file_path: Some("blockchain.json".into()),
@ -826,14 +831,16 @@ mod tests {
let args = vec!["parity", "signer", "new-token"]; let args = vec!["parity", "signer", "new-token"];
let conf = parse(&args); let conf = parse(&args);
let expected = replace_home("$HOME/.parity/signer"); let expected = replace_home("$HOME/.parity/signer");
assert_eq!(conf.into_command().unwrap(), Cmd::SignerToken(expected)); assert_eq!(conf.into_command().unwrap().cmd, Cmd::SignerToken(SignerCommand {
path: expected,
}));
} }
#[test] #[test]
fn test_run_cmd() { fn test_run_cmd() {
let args = vec!["parity"]; let args = vec!["parity"];
let conf = parse(&args); let conf = parse(&args);
assert_eq!(conf.into_command().unwrap(), Cmd::Run(RunCmd { assert_eq!(conf.into_command().unwrap().cmd, Cmd::Run(RunCmd {
cache_config: Default::default(), cache_config: Default::default(),
dirs: Default::default(), dirs: Default::default(),
spec: Default::default(), spec: Default::default(),

View File

@ -114,12 +114,13 @@ mod user_defaults;
mod stratum; mod stratum;
use std::{process, env}; use std::{process, env};
use std::io::BufReader; use std::io::{self as stdio, BufReader, Write};
use std::fs::File; use std::fs::File;
use util::sha3::sha3; use util::sha3::sha3;
use cli::Args; use cli::Args;
use configuration::{Cmd, Configuration}; use configuration::{Cmd, Execute, Configuration};
use deprecated::find_deprecated; use deprecated::find_deprecated;
use ethcore_logger::setup_log;
fn print_hash_of(maybe_file: Option<String>) -> Result<String, String> { fn print_hash_of(maybe_file: Option<String>) -> Result<String, String> {
if let Some(file) = maybe_file { if let Some(file) = maybe_file {
@ -131,10 +132,12 @@ fn print_hash_of(maybe_file: Option<String>) -> Result<String, String> {
} }
} }
fn execute(command: Cmd) -> Result<String, String> { fn execute(command: Execute) -> Result<String, String> {
match command { let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed");
match command.cmd {
Cmd::Run(run_cmd) => { Cmd::Run(run_cmd) => {
try!(run::execute(run_cmd)); try!(run::execute(run_cmd, logger));
Ok("".into()) Ok("".into())
}, },
Cmd::Version => Ok(Args::print_version()), Cmd::Version => Ok(Args::print_version()),
@ -142,7 +145,7 @@ fn execute(command: Cmd) -> Result<String, String> {
Cmd::Account(account_cmd) => account::execute(account_cmd), Cmd::Account(account_cmd) => account::execute(account_cmd),
Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd), Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd),
Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd), Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd),
Cmd::SignerToken(path) => signer::new_token(path), Cmd::SignerToken(signer_cmd) => signer::execute(signer_cmd),
Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd), Cmd::Snapshot(snapshot_cmd) => snapshot::execute(snapshot_cmd),
} }
} }
@ -210,7 +213,7 @@ fn main() {
info!("{}", result); info!("{}", result);
}, },
Err(err) => { Err(err) => {
info!("{}", err); writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed");
process::exit(1); process::exit(1);
} }
} }

View File

@ -15,13 +15,14 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::{Arc, Mutex, Condvar}; use std::sync::{Arc, Mutex, Condvar};
use std::net::{TcpListener};
use ctrlc::CtrlC; use ctrlc::CtrlC;
use fdlimit::raise_fd_limit; use fdlimit::raise_fd_limit;
use ethcore_logger::{Config as LogConfig, setup_log};
use ethcore_rpc::{NetworkSettings, is_major_importing}; use ethcore_rpc::{NetworkSettings, is_major_importing};
use ethsync::NetworkConfiguration; use ethsync::NetworkConfiguration;
use util::{Colour, version, U256}; use util::{Colour, version, U256, RotatingLogger};
use io::{MayPanic, ForwardPanic, PanicHandler}; use io::{MayPanic, ForwardPanic, PanicHandler};
use ethcore_logger::{Config as LogConfig};
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify, BlockChainClient}; use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify, BlockChainClient};
use ethcore::service::ClientService; use ethcore::service::ClientService;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
@ -93,13 +94,19 @@ pub struct RunCmd {
pub check_seal: bool, pub check_seal: bool,
} }
pub fn execute(cmd: RunCmd) -> Result<(), String> { pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
if cmd.ui && cmd.dapps_conf.enabled {
// Check if Parity is already running
let addr = format!("{}:{}", cmd.dapps_conf.interface, cmd.dapps_conf.port);
if !TcpListener::bind(&addr as &str).is_ok() {
url::open(&format!("http://{}:{}/", cmd.dapps_conf.interface, cmd.dapps_conf.port));
return Ok(());
}
}
// set up panic handler // set up panic handler
let panic_handler = PanicHandler::new_in_arc(); let panic_handler = PanicHandler::new_in_arc();
// set up logger
let logger = try!(setup_log(&cmd.logger_config));
// increase max number of open files // increase max number of open files
raise_fd_limit(); raise_fd_limit();

View File

@ -68,8 +68,13 @@ fn codes_path(path: String) -> PathBuf {
p p
} }
pub fn new_token(path: String) -> Result<String, String> { #[derive(Debug, PartialEq)]
generate_new_token(path) pub struct SignerCommand {
pub path: String,
}
pub fn execute(cmd: SignerCommand) -> Result<String, String> {
generate_new_token(cmd.path)
.map(|code| format!("This key code will authorise your System Signer UI: {}", Colour::White.bold().paint(code))) .map(|code| format!("This key code will authorise your System Signer UI: {}", Colour::White.bold().paint(code)))
.map_err(|err| format!("Error generating token: {:?}", err)) .map_err(|err| format!("Error generating token: {:?}", err))
} }

View File

@ -20,7 +20,6 @@ use std::time::Duration;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use ethcore_logger::{setup_log, Config as LogConfig};
use ethcore::snapshot::{Progress, RestorationStatus, SnapshotService as SS}; use ethcore::snapshot::{Progress, RestorationStatus, SnapshotService as SS};
use ethcore::snapshot::io::{SnapshotReader, PackedReader, PackedWriter}; use ethcore::snapshot::io::{SnapshotReader, PackedReader, PackedWriter};
use ethcore::snapshot::service::Service as SnapshotService; use ethcore::snapshot::service::Service as SnapshotService;
@ -55,7 +54,6 @@ pub struct SnapshotCommand {
pub spec: SpecType, pub spec: SpecType,
pub pruning: Pruning, pub pruning: Pruning,
pub pruning_history: u64, pub pruning_history: u64,
pub logger_config: LogConfig,
pub mode: Mode, pub mode: Mode,
pub tracing: Switch, pub tracing: Switch,
pub fat_db: Switch, pub fat_db: Switch,
@ -141,9 +139,6 @@ impl SnapshotCommand {
// load user defaults // load user defaults
let user_defaults = try!(UserDefaults::load(&user_defaults_path)); let user_defaults = try!(UserDefaults::load(&user_defaults_path));
// Setup logging
let _logger = setup_log(&self.logger_config);
fdlimit::raise_fd_limit(); fdlimit::raise_fd_limit();
// select pruning algorithm // select pruning algorithm

View File

@ -41,6 +41,7 @@ mod codes {
pub const ACCOUNT_ERROR: i64 = -32023; pub const ACCOUNT_ERROR: i64 = -32023;
pub const SIGNER_DISABLED: i64 = -32030; pub const SIGNER_DISABLED: i64 = -32030;
pub const DAPPS_DISABLED: i64 = -32031; pub const DAPPS_DISABLED: i64 = -32031;
pub const NETWORK_DISABLED: i64 = -32035;
pub const REQUEST_REJECTED: i64 = -32040; pub const REQUEST_REJECTED: i64 = -32040;
pub const REQUEST_REJECTED_LIMIT: i64 = -32041; pub const REQUEST_REJECTED_LIMIT: i64 = -32041;
pub const REQUEST_NOT_FOUND: i64 = -32042; pub const REQUEST_NOT_FOUND: i64 = -32042;
@ -185,6 +186,14 @@ pub fn dapps_disabled() -> Error {
} }
} }
pub fn network_disabled() -> Error {
Error {
code: ErrorCode::ServerError(codes::NETWORK_DISABLED),
message: "Network is disabled or not yet up.".into(),
data: None
}
}
pub fn encryption_error<T: fmt::Debug>(error: T) -> Error { pub fn encryption_error<T: fmt::Debug>(error: T) -> Error {
Error { Error {
code: ErrorCode::ServerError(codes::ENCRYPTION_ERROR), code: ErrorCode::ServerError(codes::ENCRYPTION_ERROR),

View File

@ -353,4 +353,8 @@ impl<C, M, S: ?Sized, F> Ethcore for EthcoreClient<C, M, S, F> where
Mode::Active => "active", Mode::Active => "active",
}.into()) }.into())
} }
fn enode(&self) -> Result<String, Error> {
take_weak!(self.sync).enode().ok_or_else(errors::network_disabled)
}
} }

View File

@ -93,5 +93,9 @@ impl SyncProvider for TestSyncProvider {
} }
] ]
} }
fn enode(&self) -> Option<String> {
None
}
} }

View File

@ -133,5 +133,9 @@ build_rpc_trait! {
/// Get the mode. Results one of: "active", "passive", "dark", "off". /// Get the mode. Results one of: "active", "passive", "dark", "off".
#[rpc(name = "ethcore_mode")] #[rpc(name = "ethcore_mode")]
fn mode(&self) -> Result<String, Error>; fn mode(&self) -> Result<String, Error>;
/// Get the enode of this node.
#[rpc(name = "ethcore_enode")]
fn enode(&self) -> Result<String, Error>;
} }
} }

View File

@ -73,6 +73,9 @@ pub trait SyncProvider: Send + Sync {
/// Get peers information /// Get peers information
fn peers(&self) -> Vec<PeerInfo>; fn peers(&self) -> Vec<PeerInfo>;
/// Get the enode if available.
fn enode(&self) -> Option<String>;
} }
/// Peer connection information /// Peer connection information
@ -143,6 +146,10 @@ impl SyncProvider for EthSync {
self.handler.sync.write().peers(&sync_io) self.handler.sync.write().peers(&sync_io)
}).unwrap_or(Vec::new()) }).unwrap_or(Vec::new())
} }
fn enode(&self) -> Option<String> {
self.network.external_url()
}
} }
struct SyncProtocolHandler { struct SyncProtocolHandler {

View File

@ -32,7 +32,8 @@ use node_table::NodeId;
use stats::NetworkStats; use stats::NetworkStats;
use time; use time;
const PING_TIMEOUT_SEC: u64 = 65; // Timeout must be less than (interval - 1).
const PING_TIMEOUT_SEC: u64 = 15;
const PING_INTERVAL_SEC: u64 = 30; const PING_INTERVAL_SEC: u64 = 30;
/// Peer session over encrypted connection. /// Peer session over encrypted connection.

View File

@ -30,7 +30,7 @@ pub struct Histogram {
impl Histogram { impl Histogram {
/// Histogram if a sorted corpus is at least fills the buckets. /// Histogram if a sorted corpus is at least fills the buckets.
pub fn new(corpus: &[U256], bucket_number: usize) -> Option<Histogram> { pub fn new(corpus: &[U256], bucket_number: usize) -> Option<Histogram> {
if corpus.len() < bucket_number { return None; } if corpus.len() <= bucket_number { return None; }
let corpus_end = corpus.last().expect("there are at least bucket_number elements; qed").clone(); let corpus_end = corpus.last().expect("there are at least bucket_number elements; qed").clone();
// If there are extremely few transactions, go from zero. // If there are extremely few transactions, go from zero.
let corpus_start = corpus.first().expect("there are at least bucket_number elements; qed").clone(); let corpus_start = corpus.first().expect("there are at least bucket_number elements; qed").clone();
@ -67,4 +67,9 @@ mod tests {
assert!(Histogram::new(&vec_into![1, 2], 5).is_none()); assert!(Histogram::new(&vec_into![1, 2], 5).is_none());
} }
#[test]
fn should_not_panic_when_asking_for_bucket_too_big() {
assert!(Histogram::new(&vec_into![1, 2], 2).is_none());
}
} }

274
windows/ptray/ptray.cpp Normal file
View File

@ -0,0 +1,274 @@
// Copyright 2015, 2016 Ethcore (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/>.
#define WIN32_LEAN_AND_MEAN
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <Windows.h>
#include <Shellapi.h>
#include <Shlwapi.h>
#include <tlhelp32.h>
#include <SDKDDKVer.h>
#include "resource.h"
#pragma comment(lib, "shlwapi.lib")
#define MAX_LOADSTRING 100
#define IDM_EXIT 100
#define IDM_OPEN 101
#define WM_USER_SHELLICON WM_USER + 1
HANDLE parityHandle = INVALID_HANDLE_VALUE;
DWORD parityProcId = 0;
NOTIFYICONDATA nidApp;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];
LPCWSTR cParityExe = _T("parity.exe");
ATOM MyRegisterClass(HINSTANCE hInstance);
bool InitInstance(HINSTANCE, int, LPWSTR cmdLine);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void KillParity();
void OpenUI();
bool ParityIsRunning();
bool GetParityExePath(TCHAR* dest, size_t destSize)
{
if (!dest || MAX_PATH > destSize)
return false;
GetModuleFileName(NULL, dest, destSize);
if (!PathRemoveFileSpec(dest))
return false;
return PathAppend(dest, _T("parity.exe")) == TRUE;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
CreateMutex(0, FALSE, _T("Local\\ParityTray"));
if (GetLastError() == ERROR_ALREADY_EXISTS)
return -1;
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_PTRAY, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
if (!InitInstance(hInstance, nCmdShow, lpCmdLine))
return FALSE;
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PTRAY));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTRAY));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PTRAY);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
bool InitInstance(HINSTANCE hInstance, int nCmdShow, LPWSTR cmdLine)
{
// Check if already running
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (lstrcmp(entry.szExeFile, cParityExe) == 0)
{
parityHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
parityProcId = entry.th32ProcessID;
break;
}
}
}
CloseHandle(snapshot);
if (parityHandle == INVALID_HANDLE_VALUE)
{
// Launch parity
TCHAR path[MAX_PATH] = { 0 };
if (!GetParityExePath(path, MAX_PATH))
return false;
PROCESS_INFORMATION procInfo = { 0 };
STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
LPWSTR cmd = new WCHAR[lstrlen(cmdLine) + lstrlen(path) + 2];
lstrcpy(cmd, path);
lstrcat(cmd, _T(" "));
lstrcat(cmd, cmdLine);
if (!CreateProcess(nullptr, cmd, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo))
return false;
delete[] cmd;
parityHandle = procInfo.hProcess;
parityProcId = procInfo.dwProcessId;
}
HWND hWnd = CreateWindowW(szWindowClass, szTitle, 0,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
return false;
HICON hMainIcon = LoadIcon(hInstance, (LPCTSTR)MAKEINTRESOURCE(IDI_PTRAY));
nidApp.cbSize = sizeof(NOTIFYICONDATA); // sizeof the struct in bytes
nidApp.hWnd = (HWND)hWnd; //handle of the window which will process this app. messages
nidApp.uID = IDI_PTRAY; //ID of the icon that willl appear in the system tray
nidApp.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; //ORing of all the flags
nidApp.hIcon = hMainIcon; // handle of the Icon to be displayed, obtained from LoadIcon
nidApp.uCallbackMessage = WM_USER_SHELLICON;
LoadString(hInstance, IDS_CONTROL_PARITY, nidApp.szTip, MAX_LOADSTRING);
Shell_NotifyIcon(NIM_ADD, &nidApp);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_USER_SHELLICON:
// systray msg callback
POINT lpClickPoint;
switch (LOWORD(lParam))
{
case WM_LBUTTONDOWN:
OpenUI();
break;
case WM_RBUTTONDOWN:
UINT uFlag = MF_BYPOSITION | MF_STRING;
GetCursorPos(&lpClickPoint);
HMENU hPopMenu = CreatePopupMenu();
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_EXIT, _T("Open"));
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_SEPARATOR | MF_BYPOSITION, 0, nullptr);
InsertMenu(hPopMenu, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, IDM_EXIT, _T("Exit"));
SetForegroundWindow(hWnd);
TrackPopupMenu(hPopMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_BOTTOMALIGN, lpClickPoint.x, lpClickPoint.y, 0, hWnd, NULL);
return TRUE;
}
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_OPEN:
OpenUI();
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &nidApp);
KillParity();
PostQuitMessage(0);
break;
case WM_TIMER:
if (!ParityIsRunning())
DestroyWindow(hWnd);
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
void KillParity()
{
DWORD procId = parityProcId;
//This does not require the console window to be visible.
if (AttachConsole(procId))
{
// Disable Ctrl-C handling for our program
SetConsoleCtrlHandler(nullptr, true);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
FreeConsole();
//Re-enable Ctrl-C handling or any subsequently started
//programs will inherit the disabled state.
SetConsoleCtrlHandler(nullptr, false);
}
WaitForSingleObject(parityHandle, INFINITE);
}
bool ParityIsRunning()
{
return WaitForSingleObject(parityHandle, 0) == WAIT_TIMEOUT;
}
void OpenUI()
{
// Launch parity
TCHAR path[MAX_PATH] = { 0 };
if (!GetParityExePath(path, MAX_PATH))
return;
PROCESS_INFORMATION procInfo = { 0 };
STARTUPINFO startupInfo = { sizeof(STARTUPINFO) };
LPWSTR cmd = _T("parity.exe ui");
CreateProcess(path, cmd, nullptr, nullptr, false, CREATE_NO_WINDOW, nullptr, nullptr, &startupInfo, &procInfo);
}

BIN
windows/ptray/ptray.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
windows/ptray/ptray.rc Normal file

Binary file not shown.

155
windows/ptray/ptray.vcxproj Normal file
View File

@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{37C89E90-8C9E-4FFC-AAE7-B3695D5EB6F4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ptray</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ptray.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ptray.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="ptray.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

BIN
windows/ptray/resource.h Normal file

Binary file not shown.

View File

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>