├── .gitignore ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── examples ├── client.rs └── node.rs └── src ├── client.rs ├── codec.rs ├── config.rs ├── lib.rs ├── node.rs ├── server.rs ├── session.rs ├── sign.rs └── types.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | node*.toml 3 | client*.toml 4 | **/*.rs.bk 5 | .idea/ 6 | *.iml 7 | ex/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | dist: xenial 3 | sudo: required 4 | 5 | rust: 6 | - stable 7 | - beta 8 | - nightly 9 | 10 | env: 11 | global: 12 | - SODIUM_VERS=1.0.17 13 | - CARGO_INCREMENTAL=1 14 | - RUSTFLAGS="-D warnings" 15 | 16 | matrix: 17 | allow_failures: 18 | - rust: nightly 19 | 20 | addons: 21 | apt: 22 | packages: 23 | - gcc 24 | - g++ 25 | - libssl-dev 26 | - libcurl4-openssl-dev 27 | - libelf-dev 28 | - libdw-dev 29 | - binutils-dev 30 | 31 | cache: 32 | directories: 33 | - $HOME/.cargo 34 | - $HOME/.local 35 | - $TRAVIS_BUILD_DIR/target 36 | 37 | before_install: 38 | - | 39 | if [ ! -f "$HOME/.local/lib/libsodium.a" ]; then 40 | wget "https://github.com/jedisct1/libsodium/releases/download/$SODIUM_VERS/libsodium-$SODIUM_VERS.tar.gz" -t 5 -O "libsodium.tar.gz" 41 | tar xvf libsodium.tar.gz 42 | cd libsodium-$SODIUM_VERS 43 | ./configure --prefix=$HOME/.local 44 | make 45 | make install 46 | cd .. 47 | fi 48 | - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/.local/lib 49 | - export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$HOME/.local/lib/pkgconfig 50 | 51 | after_success: | 52 | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && 53 | tar xzf master.tar.gz && 54 | cd kcov-master && 55 | mkdir build && 56 | cd build && 57 | cmake .. && 58 | make && 59 | make install DESTDIR=../../kcov-build && 60 | cd ../.. && 61 | rm -rf kcov-master && 62 | for file in target/debug/*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib,_test.rs,tests/ --verify "target/cov/$(basename $file)" "$file"; done && 63 | bash <(curl -s https://codecov.io/bash) 64 | echo "Uploaded code coverage" 65 | 66 | 67 | script: 68 | - cargo build --all 69 | - cargo test --all 70 | 71 | git: 72 | depth: 5 -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "actix" 5 | version = "0.7.9" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "actix_derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 9 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 10 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 11 | "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 12 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 13 | "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 14 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 15 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 16 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 18 | "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 19 | "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 20 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 21 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", 27 | "trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 28 | "trust-dns-resolver 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", 29 | "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 30 | ] 31 | 32 | [[package]] 33 | name = "actix_derive" 34 | version = "0.3.2" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | dependencies = [ 37 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 38 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 39 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", 40 | ] 41 | 42 | [[package]] 43 | name = "adler32" 44 | version = "1.0.3" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | 47 | [[package]] 48 | name = "amq" 49 | version = "0.2.0" 50 | dependencies = [ 51 | "actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", 52 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 53 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 54 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 55 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 56 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 59 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 60 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 61 | "sodiumoxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 62 | "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 63 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 66 | "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 68 | ] 69 | 70 | [[package]] 71 | name = "arc-swap" 72 | version = "0.3.7" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | 75 | [[package]] 76 | name = "arrayvec" 77 | version = "0.4.10" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | dependencies = [ 80 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 81 | ] 82 | 83 | [[package]] 84 | name = "autocfg" 85 | version = "0.1.2" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | 88 | [[package]] 89 | name = "backtrace" 90 | version = "0.3.14" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | dependencies = [ 93 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 94 | "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 96 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 97 | "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 98 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 99 | ] 100 | 101 | [[package]] 102 | name = "backtrace-sys" 103 | version = "0.1.28" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | dependencies = [ 106 | "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 107 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 108 | ] 109 | 110 | [[package]] 111 | name = "base64" 112 | version = "0.10.1" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | dependencies = [ 115 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 116 | ] 117 | 118 | [[package]] 119 | name = "bitflags" 120 | version = "1.0.4" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | 123 | [[package]] 124 | name = "block-buffer" 125 | version = "0.7.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | dependencies = [ 128 | "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 129 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 130 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 131 | "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 132 | ] 133 | 134 | [[package]] 135 | name = "block-padding" 136 | version = "0.1.3" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | dependencies = [ 139 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 140 | ] 141 | 142 | [[package]] 143 | name = "byte-tools" 144 | version = "0.3.1" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | 147 | [[package]] 148 | name = "byteorder" 149 | version = "1.3.1" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | 152 | [[package]] 153 | name = "bytes" 154 | version = "0.4.12" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | dependencies = [ 157 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 158 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 159 | ] 160 | 161 | [[package]] 162 | name = "bzip2" 163 | version = "0.3.3" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | dependencies = [ 166 | "bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 167 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 168 | ] 169 | 170 | [[package]] 171 | name = "bzip2-sys" 172 | version = "0.1.7" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | dependencies = [ 175 | "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 176 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 177 | ] 178 | 179 | [[package]] 180 | name = "cc" 181 | version = "1.0.31" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | 184 | [[package]] 185 | name = "cfg-if" 186 | version = "0.1.7" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | 189 | [[package]] 190 | name = "cloudabi" 191 | version = "0.0.3" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | dependencies = [ 194 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 195 | ] 196 | 197 | [[package]] 198 | name = "crc32fast" 199 | version = "1.2.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | dependencies = [ 202 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 203 | ] 204 | 205 | [[package]] 206 | name = "crossbeam-channel" 207 | version = "0.3.8" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | dependencies = [ 210 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 211 | "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 212 | ] 213 | 214 | [[package]] 215 | name = "crossbeam-deque" 216 | version = "0.7.1" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | dependencies = [ 219 | "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 220 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 221 | ] 222 | 223 | [[package]] 224 | name = "crossbeam-epoch" 225 | version = "0.7.1" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | dependencies = [ 228 | "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 229 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 230 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 231 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 232 | "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 233 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 234 | ] 235 | 236 | [[package]] 237 | name = "crossbeam-queue" 238 | version = "0.1.2" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | dependencies = [ 241 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 242 | ] 243 | 244 | [[package]] 245 | name = "crossbeam-utils" 246 | version = "0.6.5" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | dependencies = [ 249 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 250 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 251 | ] 252 | 253 | [[package]] 254 | name = "digest" 255 | version = "0.8.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | dependencies = [ 258 | "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 259 | ] 260 | 261 | [[package]] 262 | name = "error-chain" 263 | version = "0.8.1" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | dependencies = [ 266 | "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 267 | ] 268 | 269 | [[package]] 270 | name = "failure" 271 | version = "0.1.5" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | dependencies = [ 274 | "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 275 | "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 276 | ] 277 | 278 | [[package]] 279 | name = "failure_derive" 280 | version = "0.1.5" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | dependencies = [ 283 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 284 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 285 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", 286 | "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 287 | ] 288 | 289 | [[package]] 290 | name = "fake-simd" 291 | version = "0.1.2" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | 294 | [[package]] 295 | name = "filetime" 296 | version = "0.2.4" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | dependencies = [ 299 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 300 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 301 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", 302 | ] 303 | 304 | [[package]] 305 | name = "fnv" 306 | version = "1.0.6" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | 309 | [[package]] 310 | name = "fuchsia-cprng" 311 | version = "0.1.1" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | 314 | [[package]] 315 | name = "fuchsia-zircon" 316 | version = "0.3.3" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | dependencies = [ 319 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 320 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 321 | ] 322 | 323 | [[package]] 324 | name = "fuchsia-zircon-sys" 325 | version = "0.3.3" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | 328 | [[package]] 329 | name = "futures" 330 | version = "0.1.25" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | 333 | [[package]] 334 | name = "generic-array" 335 | version = "0.12.0" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | dependencies = [ 338 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 339 | ] 340 | 341 | [[package]] 342 | name = "hex" 343 | version = "0.3.2" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | 346 | [[package]] 347 | name = "hostname" 348 | version = "0.1.5" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | dependencies = [ 351 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 352 | "winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 353 | ] 354 | 355 | [[package]] 356 | name = "http_req" 357 | version = "0.4.5" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | dependencies = [ 360 | "rustls 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 361 | "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", 362 | "webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", 363 | ] 364 | 365 | [[package]] 366 | name = "idna" 367 | version = "0.1.5" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | dependencies = [ 370 | "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 371 | "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 372 | "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 373 | ] 374 | 375 | [[package]] 376 | name = "iovec" 377 | version = "0.1.2" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | dependencies = [ 380 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 381 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 382 | ] 383 | 384 | [[package]] 385 | name = "ipconfig" 386 | version = "0.1.9" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | dependencies = [ 389 | "error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 390 | "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 391 | "widestring 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 392 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 393 | "winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 394 | ] 395 | 396 | [[package]] 397 | name = "itoa" 398 | version = "0.4.3" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | 401 | [[package]] 402 | name = "kernel32-sys" 403 | version = "0.2.2" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | dependencies = [ 406 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 407 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 408 | ] 409 | 410 | [[package]] 411 | name = "lazy_static" 412 | version = "1.3.0" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | 415 | [[package]] 416 | name = "lazycell" 417 | version = "1.2.1" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | 420 | [[package]] 421 | name = "libc" 422 | version = "0.2.50" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | 425 | [[package]] 426 | name = "libflate" 427 | version = "0.1.21" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | dependencies = [ 430 | "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 431 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 432 | "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 433 | ] 434 | 435 | [[package]] 436 | name = "libsodium-sys" 437 | version = "0.2.1" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | dependencies = [ 440 | "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 441 | "http_req 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 442 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 443 | "libflate 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", 444 | "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", 445 | "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 446 | "tar 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)", 447 | "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 448 | "zip 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 449 | ] 450 | 451 | [[package]] 452 | name = "linked-hash-map" 453 | version = "0.4.2" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | 456 | [[package]] 457 | name = "lock_api" 458 | version = "0.1.5" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | dependencies = [ 461 | "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 462 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 463 | ] 464 | 465 | [[package]] 466 | name = "log" 467 | version = "0.4.6" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | dependencies = [ 470 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 471 | ] 472 | 473 | [[package]] 474 | name = "lru-cache" 475 | version = "0.1.1" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | dependencies = [ 478 | "linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 479 | ] 480 | 481 | [[package]] 482 | name = "matches" 483 | version = "0.1.8" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | 486 | [[package]] 487 | name = "memoffset" 488 | version = "0.2.1" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | 491 | [[package]] 492 | name = "mio" 493 | version = "0.6.16" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | dependencies = [ 496 | "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 497 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 498 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 499 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 500 | "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 501 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 502 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 503 | "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 504 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 505 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 506 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 507 | ] 508 | 509 | [[package]] 510 | name = "mio-uds" 511 | version = "0.6.7" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | dependencies = [ 514 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 515 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 516 | "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", 517 | ] 518 | 519 | [[package]] 520 | name = "miow" 521 | version = "0.2.1" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | dependencies = [ 524 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 525 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 526 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 527 | "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 528 | ] 529 | 530 | [[package]] 531 | name = "net2" 532 | version = "0.2.33" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | dependencies = [ 535 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 536 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 537 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 538 | ] 539 | 540 | [[package]] 541 | name = "nodrop" 542 | version = "0.1.13" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | 545 | [[package]] 546 | name = "num_cpus" 547 | version = "1.10.0" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | dependencies = [ 550 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 551 | ] 552 | 553 | [[package]] 554 | name = "opaque-debug" 555 | version = "0.2.2" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | 558 | [[package]] 559 | name = "owning_ref" 560 | version = "0.4.0" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | dependencies = [ 563 | "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 564 | ] 565 | 566 | [[package]] 567 | name = "parking_lot" 568 | version = "0.7.1" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | dependencies = [ 571 | "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 572 | "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 573 | ] 574 | 575 | [[package]] 576 | name = "parking_lot_core" 577 | version = "0.4.0" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | dependencies = [ 580 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 581 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 582 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 583 | "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 584 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 585 | ] 586 | 587 | [[package]] 588 | name = "percent-encoding" 589 | version = "1.0.1" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | 592 | [[package]] 593 | name = "pkg-config" 594 | version = "0.3.14" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | 597 | [[package]] 598 | name = "podio" 599 | version = "0.1.6" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | 602 | [[package]] 603 | name = "proc-macro2" 604 | version = "0.4.27" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | dependencies = [ 607 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 608 | ] 609 | 610 | [[package]] 611 | name = "quick-error" 612 | version = "1.2.2" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | 615 | [[package]] 616 | name = "quote" 617 | version = "0.6.11" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | dependencies = [ 620 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 621 | ] 622 | 623 | [[package]] 624 | name = "rand" 625 | version = "0.5.6" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | dependencies = [ 628 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 629 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 630 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 631 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 632 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 633 | ] 634 | 635 | [[package]] 636 | name = "rand" 637 | version = "0.6.5" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | dependencies = [ 640 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 641 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 642 | "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 643 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 644 | "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 645 | "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 646 | "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 647 | "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 648 | "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 649 | "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 650 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 651 | ] 652 | 653 | [[package]] 654 | name = "rand_chacha" 655 | version = "0.1.1" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | dependencies = [ 658 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 659 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 660 | ] 661 | 662 | [[package]] 663 | name = "rand_core" 664 | version = "0.3.1" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | dependencies = [ 667 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 668 | ] 669 | 670 | [[package]] 671 | name = "rand_core" 672 | version = "0.4.0" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | 675 | [[package]] 676 | name = "rand_hc" 677 | version = "0.1.0" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | dependencies = [ 680 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 681 | ] 682 | 683 | [[package]] 684 | name = "rand_isaac" 685 | version = "0.1.1" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | dependencies = [ 688 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 689 | ] 690 | 691 | [[package]] 692 | name = "rand_jitter" 693 | version = "0.1.3" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | dependencies = [ 696 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 697 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 698 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 699 | ] 700 | 701 | [[package]] 702 | name = "rand_os" 703 | version = "0.1.3" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | dependencies = [ 706 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 707 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 708 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 709 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 710 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 711 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 712 | ] 713 | 714 | [[package]] 715 | name = "rand_pcg" 716 | version = "0.1.2" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | dependencies = [ 719 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 720 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 721 | ] 722 | 723 | [[package]] 724 | name = "rand_xorshift" 725 | version = "0.1.1" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | dependencies = [ 728 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 729 | ] 730 | 731 | [[package]] 732 | name = "rdrand" 733 | version = "0.4.0" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | dependencies = [ 736 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 737 | ] 738 | 739 | [[package]] 740 | name = "redox_syscall" 741 | version = "0.1.51" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | 744 | [[package]] 745 | name = "resolv-conf" 746 | version = "0.6.2" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | dependencies = [ 749 | "hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 750 | "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 751 | ] 752 | 753 | [[package]] 754 | name = "ring" 755 | version = "0.14.6" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | dependencies = [ 758 | "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", 759 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 760 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 761 | "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 762 | "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 763 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 764 | ] 765 | 766 | [[package]] 767 | name = "rustc-demangle" 768 | version = "0.1.13" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | 771 | [[package]] 772 | name = "rustc_version" 773 | version = "0.2.3" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | dependencies = [ 776 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 777 | ] 778 | 779 | [[package]] 780 | name = "rustls" 781 | version = "0.15.1" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | dependencies = [ 784 | "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 785 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 786 | "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", 787 | "sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 788 | "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 789 | "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", 790 | ] 791 | 792 | [[package]] 793 | name = "ryu" 794 | version = "0.2.7" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | 797 | [[package]] 798 | name = "scopeguard" 799 | version = "0.3.3" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | 802 | [[package]] 803 | name = "sct" 804 | version = "0.5.0" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | dependencies = [ 807 | "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", 808 | "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 809 | ] 810 | 811 | [[package]] 812 | name = "semver" 813 | version = "0.9.0" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | dependencies = [ 816 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 817 | ] 818 | 819 | [[package]] 820 | name = "semver-parser" 821 | version = "0.7.0" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | 824 | [[package]] 825 | name = "serde" 826 | version = "1.0.89" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | 829 | [[package]] 830 | name = "serde_derive" 831 | version = "1.0.89" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | dependencies = [ 834 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 835 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 836 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", 837 | ] 838 | 839 | [[package]] 840 | name = "serde_json" 841 | version = "1.0.39" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | dependencies = [ 844 | "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 845 | "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 846 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 847 | ] 848 | 849 | [[package]] 850 | name = "sha2" 851 | version = "0.8.0" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | dependencies = [ 854 | "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 855 | "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 856 | "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 857 | "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 858 | ] 859 | 860 | [[package]] 861 | name = "signal-hook" 862 | version = "0.1.8" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | dependencies = [ 865 | "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 866 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 867 | ] 868 | 869 | [[package]] 870 | name = "slab" 871 | version = "0.4.2" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | 874 | [[package]] 875 | name = "smallvec" 876 | version = "0.6.9" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | 879 | [[package]] 880 | name = "socket2" 881 | version = "0.3.8" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | dependencies = [ 884 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 885 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 886 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", 887 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 888 | ] 889 | 890 | [[package]] 891 | name = "sodiumoxide" 892 | version = "0.2.1" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | dependencies = [ 895 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 896 | "libsodium-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 897 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 898 | ] 899 | 900 | [[package]] 901 | name = "spin" 902 | version = "0.5.0" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | 905 | [[package]] 906 | name = "stable_deref_trait" 907 | version = "1.1.1" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | 910 | [[package]] 911 | name = "syn" 912 | version = "0.15.29" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | dependencies = [ 915 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 916 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 917 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 918 | ] 919 | 920 | [[package]] 921 | name = "synstructure" 922 | version = "0.10.1" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | dependencies = [ 925 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 926 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 927 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", 928 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 929 | ] 930 | 931 | [[package]] 932 | name = "tar" 933 | version = "0.4.21" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | dependencies = [ 936 | "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 937 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 938 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", 939 | "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 940 | ] 941 | 942 | [[package]] 943 | name = "time" 944 | version = "0.1.42" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | dependencies = [ 947 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 948 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", 949 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 950 | ] 951 | 952 | [[package]] 953 | name = "tokio" 954 | version = "0.1.16" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | dependencies = [ 957 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 958 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 959 | "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", 960 | "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 961 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 962 | "tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 963 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 964 | "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 965 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 966 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 967 | "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 968 | "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 969 | "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 970 | "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", 971 | "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 972 | "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 973 | ] 974 | 975 | [[package]] 976 | name = "tokio-codec" 977 | version = "0.1.1" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | dependencies = [ 980 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 981 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 982 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 983 | ] 984 | 985 | [[package]] 986 | name = "tokio-current-thread" 987 | version = "0.1.5" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | dependencies = [ 990 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 991 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 992 | ] 993 | 994 | [[package]] 995 | name = "tokio-executor" 996 | version = "0.1.6" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | dependencies = [ 999 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1000 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "tokio-fs" 1005 | version = "0.1.6" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | dependencies = [ 1008 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1009 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1010 | "tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1011 | ] 1012 | 1013 | [[package]] 1014 | name = "tokio-io" 1015 | version = "0.1.12" 1016 | source = "registry+https://github.com/rust-lang/crates.io-index" 1017 | dependencies = [ 1018 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1019 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1020 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1021 | ] 1022 | 1023 | [[package]] 1024 | name = "tokio-reactor" 1025 | version = "0.1.9" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | dependencies = [ 1028 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1029 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1030 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1031 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1032 | "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", 1033 | "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 1034 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1035 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1036 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1037 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1038 | "tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "tokio-signal" 1043 | version = "0.2.7" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | dependencies = [ 1046 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1047 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 1048 | "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", 1049 | "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", 1050 | "signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 1051 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1052 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1053 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1054 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "tokio-sync" 1059 | version = "0.1.3" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | dependencies = [ 1062 | "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1063 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1064 | ] 1065 | 1066 | [[package]] 1067 | name = "tokio-tcp" 1068 | version = "0.1.3" 1069 | source = "registry+https://github.com/rust-lang/crates.io-index" 1070 | dependencies = [ 1071 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1072 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1073 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1074 | "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", 1075 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1076 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1077 | ] 1078 | 1079 | [[package]] 1080 | name = "tokio-threadpool" 1081 | version = "0.1.12" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | dependencies = [ 1084 | "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1085 | "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1086 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1087 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1088 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1089 | "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 1090 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1091 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1092 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "tokio-timer" 1097 | version = "0.2.10" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | dependencies = [ 1100 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1101 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1102 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1103 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "tokio-udp" 1108 | version = "0.1.3" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | dependencies = [ 1111 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1112 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1113 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1114 | "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", 1115 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1116 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1117 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "tokio-uds" 1122 | version = "0.2.5" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | dependencies = [ 1125 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1126 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1127 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1128 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 1129 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1130 | "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", 1131 | "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", 1132 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1133 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1134 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1135 | ] 1136 | 1137 | [[package]] 1138 | name = "toml" 1139 | version = "0.4.10" 1140 | source = "registry+https://github.com/rust-lang/crates.io-index" 1141 | dependencies = [ 1142 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 1143 | ] 1144 | 1145 | [[package]] 1146 | name = "trust-dns-proto" 1147 | version = "0.5.0" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | dependencies = [ 1150 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1151 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1152 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1153 | "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1154 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1155 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1156 | "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", 1157 | "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 1158 | "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1159 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1160 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1161 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1162 | "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 1163 | "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", 1164 | "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 1165 | "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1166 | ] 1167 | 1168 | [[package]] 1169 | name = "trust-dns-proto" 1170 | version = "0.6.3" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | dependencies = [ 1173 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1174 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1175 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1176 | "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1177 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1178 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1179 | "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", 1180 | "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 1181 | "socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1182 | "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1183 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1184 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1185 | "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 1186 | "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", 1187 | "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 1188 | "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1189 | ] 1190 | 1191 | [[package]] 1192 | name = "trust-dns-resolver" 1193 | version = "0.10.3" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | dependencies = [ 1196 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 1197 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1198 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 1199 | "ipconfig 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1200 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1201 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1202 | "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1203 | "resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 1204 | "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 1205 | "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 1206 | "trust-dns-proto 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "typenum" 1211 | version = "1.10.0" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | 1214 | [[package]] 1215 | name = "unicode-bidi" 1216 | version = "0.3.4" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | dependencies = [ 1219 | "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "unicode-normalization" 1224 | version = "0.1.8" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | dependencies = [ 1227 | "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 1228 | ] 1229 | 1230 | [[package]] 1231 | name = "unicode-xid" 1232 | version = "0.1.0" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | 1235 | [[package]] 1236 | name = "untrusted" 1237 | version = "0.6.2" 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" 1239 | 1240 | [[package]] 1241 | name = "url" 1242 | version = "1.7.2" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | dependencies = [ 1245 | "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1246 | "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 1247 | "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "uuid" 1252 | version = "0.7.2" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | dependencies = [ 1255 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1256 | ] 1257 | 1258 | [[package]] 1259 | name = "vcpkg" 1260 | version = "0.2.6" 1261 | source = "registry+https://github.com/rust-lang/crates.io-index" 1262 | 1263 | [[package]] 1264 | name = "webpki" 1265 | version = "0.19.1" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | dependencies = [ 1268 | "ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)", 1269 | "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 1270 | ] 1271 | 1272 | [[package]] 1273 | name = "webpki-roots" 1274 | version = "0.16.0" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | dependencies = [ 1277 | "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 1278 | "webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", 1279 | ] 1280 | 1281 | [[package]] 1282 | name = "widestring" 1283 | version = "0.2.2" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | 1286 | [[package]] 1287 | name = "winapi" 1288 | version = "0.2.8" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | 1291 | [[package]] 1292 | name = "winapi" 1293 | version = "0.3.6" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | dependencies = [ 1296 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1297 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1298 | ] 1299 | 1300 | [[package]] 1301 | name = "winapi-build" 1302 | version = "0.1.1" 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" 1304 | 1305 | [[package]] 1306 | name = "winapi-i686-pc-windows-gnu" 1307 | version = "0.4.0" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | 1310 | [[package]] 1311 | name = "winapi-x86_64-pc-windows-gnu" 1312 | version = "0.4.0" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | 1315 | [[package]] 1316 | name = "winreg" 1317 | version = "0.5.1" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | dependencies = [ 1320 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "winutil" 1325 | version = "0.1.1" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | dependencies = [ 1328 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 1329 | ] 1330 | 1331 | [[package]] 1332 | name = "ws2_32-sys" 1333 | version = "0.2.1" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | dependencies = [ 1336 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 1337 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1338 | ] 1339 | 1340 | [[package]] 1341 | name = "xattr" 1342 | version = "0.2.2" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | dependencies = [ 1345 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 1346 | ] 1347 | 1348 | [[package]] 1349 | name = "zip" 1350 | version = "0.5.1" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | dependencies = [ 1353 | "bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 1354 | "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1355 | "libflate 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", 1356 | "podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1357 | "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 1358 | ] 1359 | 1360 | [metadata] 1361 | "checksum actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c616db5fa4b0c40702fb75201c2af7f8aa8f3a2e2c1dda3b0655772aa949666" 1362 | "checksum actix_derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4300e9431455322ae393d43a2ba1ef96b8080573c0fc23b196219efedfb6ba69" 1363 | "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" 1364 | "checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" 1365 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" 1366 | "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" 1367 | "checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" 1368 | "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" 1369 | "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 1370 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 1371 | "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" 1372 | "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" 1373 | "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 1374 | "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" 1375 | "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" 1376 | "checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" 1377 | "checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f" 1378 | "checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" 1379 | "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" 1380 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1381 | "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 1382 | "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" 1383 | "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" 1384 | "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" 1385 | "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" 1386 | "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" 1387 | "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" 1388 | "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" 1389 | "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" 1390 | "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" 1391 | "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 1392 | "checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" 1393 | "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" 1394 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 1395 | "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 1396 | "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1397 | "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" 1398 | "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" 1399 | "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 1400 | "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" 1401 | "checksum http_req 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2a8b4570d8b7238e043e3bfb24023cbd228083218cd18f93ccba005c64f87980" 1402 | "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 1403 | "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" 1404 | "checksum ipconfig 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "08f7eadeaf4b52700de180d147c4805f199854600b36faa963d91114827b2ffc" 1405 | "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 1406 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 1407 | "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" 1408 | "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" 1409 | "checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" 1410 | "checksum libflate 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "7346a83e8a2c3958d44d24225d905385dc31fc16e89dffb356c457b278914d20" 1411 | "checksum libsodium-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09ff79e60003db178b30f7a43a56edfb726889f247a2a3b5d7a777bc0f8349f5" 1412 | "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" 1413 | "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" 1414 | "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" 1415 | "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" 1416 | "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1417 | "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 1418 | "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" 1419 | "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" 1420 | "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 1421 | "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 1422 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 1423 | "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" 1424 | "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" 1425 | "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" 1426 | "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" 1427 | "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" 1428 | "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" 1429 | "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" 1430 | "checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" 1431 | "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" 1432 | "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1433 | "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 1434 | "checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" 1435 | "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1436 | "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1437 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 1438 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" 1439 | "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 1440 | "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 1441 | "checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" 1442 | "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 1443 | "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 1444 | "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 1445 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 1446 | "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" 1447 | "checksum resolv-conf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b263b4aa1b5de9ffc0054a2386f96992058bb6870aab516f8cdeb8a667d56dcb" 1448 | "checksum ring 0.14.6 (registry+https://github.com/rust-lang/crates.io-index)" = "426bc186e3e95cac1e4a4be125a4aca7e84c2d616ffc02244eef36e2a60a093c" 1449 | "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" 1450 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1451 | "checksum rustls 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "38af00e78b66109e7184a0ee16940f41583161b7ec0518af258e4bcaed15db25" 1452 | "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" 1453 | "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 1454 | "checksum sct 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f5adf8fbd58e1b1b52699dc8bed2630faecb6d8c7bee77d009d6bbe4af569b9" 1455 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1456 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1457 | "checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" 1458 | "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" 1459 | "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" 1460 | "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" 1461 | "checksum signal-hook 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "97a47ae722318beceb0294e6f3d601205a1e6abaa4437d9d33e3a212233e3021" 1462 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1463 | "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" 1464 | "checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" 1465 | "checksum sodiumoxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fc75b810875ade9581b15c68543367dbba8bf3d0ae1ba63989171803d357" 1466 | "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" 1467 | "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 1468 | "checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" 1469 | "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" 1470 | "checksum tar 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "904b43da53c99b929c4484fa281e5535f2eb86b3040de3e3e5b69708e2a8bd65" 1471 | "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 1472 | "checksum tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcaabb3cec70485d0df6e9454fe514393ad1c4070dee8915f11041e95630b230" 1473 | "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" 1474 | "checksum tokio-current-thread 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c756b04680eea21902a46fca4e9f410a2332c04995af590e07ff262e2193a9a3" 1475 | "checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" 1476 | "checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" 1477 | "checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" 1478 | "checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" 1479 | "checksum tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd6dc5276ea05ce379a16de90083ec80836440d5ef8a6a39545a3207373b8296" 1480 | "checksum tokio-sync 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bf2b9dac2a0509b5cfd1df5aa25eafacb616a42a491a13604d6bbeab4486363" 1481 | "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" 1482 | "checksum tokio-threadpool 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "742e511f6ce2298aeb86fc9ea0d8df81c2388c6ebae3dc8a7316e8c9df0df801" 1483 | "checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6" 1484 | "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" 1485 | "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" 1486 | "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" 1487 | "checksum trust-dns-proto 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0838272e89f1c693b4df38dc353412e389cf548ceed6f9fd1af5a8d6e0e7cf74" 1488 | "checksum trust-dns-proto 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09144f0992b0870fa8d2972cc069cbf1e3c0fda64d1f3d45c4d68d0e0b52ad4e" 1489 | "checksum trust-dns-resolver 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a9f877f7a1ad821ab350505e1f1b146a4960402991787191d6d8cab2ce2de2c" 1490 | "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 1491 | "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1492 | "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" 1493 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1494 | "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" 1495 | "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" 1496 | "checksum uuid 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0238db0c5b605dd1cf51de0f21766f97fba2645897024461d6a00c036819a768" 1497 | "checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" 1498 | "checksum webpki 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f7e1cd7900a3a6b65a3e8780c51a3e6b59c0e2c55c6dc69578c288d69f7d082" 1499 | "checksum webpki-roots 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c10fa4212003ba19a564f25cd8ab572c6791f99a03cc219c13ed35ccab00de0e" 1500 | "checksum widestring 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7157704c2e12e3d2189c507b7482c52820a16dfa4465ba91add92f266667cadb" 1501 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1502 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 1503 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1504 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1505 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1506 | "checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" 1507 | "checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e" 1508 | "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1509 | "checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" 1510 | "checksum zip 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1cbbddef6339155bc4fa8e2609040078ff18f3011117b55caa9f0516d544a357" 1511 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "amq" 3 | version = "0.2.0" 4 | edition = "2018" 5 | authors = ["Evgeny Ukhanov "] 6 | description = "Message Queue framework based on Acix for Rust" 7 | readme = "README.md" 8 | keywords = ["message", "queue", "network", "security", "actor", "futures", "actix", "async", "tokio"] 9 | repository = "https://github.com/irony-rust/amq.git" 10 | categories = ["message-queue", "security", "network-programming", "asynchronous"] 11 | license = "MIT" 12 | exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"] 13 | 14 | [badges] 15 | travis-ci = { repository = "irony-rust/amq", branch = "master" } 16 | codecov = { repository = "irony-rust/amq", branch = "master", service = "github" } 17 | 18 | [lib] 19 | name = "amq" 20 | path = "src/lib.rs" 21 | 22 | #[workspace] 23 | #members = ["examples/node"] 24 | 25 | #[[bin]] 26 | #name = "client" 27 | #path = "src/client.rs" 28 | 29 | #[[bin]] 30 | #name = "config" 31 | #path = "src/config.rs" 32 | 33 | [dependencies] 34 | actix = "0.7" 35 | tokio = "0.1" 36 | tokio-codec = "0.1" 37 | tokio-io = "0.1" 38 | tokio-tcp = "0.1" 39 | futures = "0.1" 40 | 41 | bytes = "0.4" 42 | byteorder = "1.1" 43 | 44 | serde = "1.0" 45 | serde_json = "1.0" 46 | serde_derive = "1.0" 47 | rand = "0.5" 48 | sodiumoxide = "0.2" 49 | hex = "0.3" 50 | toml = "0.4" 51 | 52 | uuid = { version = "0.7", features = ["v4"] } 53 | log = "0.4" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Irony Rust 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile 3 | # @author Evgeny Ukhanov 4 | # 5 | 6 | .PHONY: check, run, build, release, test 7 | default: check 8 | 9 | test: 10 | @echo Run tests... 11 | @cargo test -- --nocapture 12 | @echo Done. 13 | 14 | check: 15 | @cargo check 16 | 17 | check-examples: 18 | @cargo check --examples 19 | 20 | client1: 21 | @echo "Run Client 1" 22 | @cargo run --bin client client1.toml 23 | 24 | client2: 25 | @echo "Run Client 2" 26 | @cargo run --bin client client2.toml 27 | 28 | config: 29 | @echo "Run configurator" 30 | @cargo run --bin config node node.toml 31 | @cargo run --bin config client client.toml 32 | 33 | node: 34 | @echo "Run Server" 35 | @cargo run --bin node node.toml 36 | 37 | build: 38 | @echo Build debug version... 39 | @cargo build 40 | @echo Done. 41 | 42 | release: 43 | @echo Build release version... 44 | @cargo build --release 45 | @echo Done. 46 | 47 | fmt: 48 | @cargo fmt 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Actix MQ frameworkvir 2 | [![Build Status](https://travis-ci.org/irony-rust/amq.svg?branch=master)](https://travis-ci.org/irony-rust/amq) 3 | [![codecov](https://codecov.io/gh/irony-rust/amq/branch/master/graph/badge.svg)](https://codecov.io/gh/irony-rust/amq) 4 | 5 | Actix MQ is Rust framework developed for efficient and fast communication 6 | via MQ protocols with various security options. Based on Rust Actix library, and implement actor-based 7 | model abd Sodiuoxide library. 8 | 9 | The network communication implement 1-rank model client-server. 10 | 11 | Currently implemented protocols: 12 | * PUB/SUB 13 | * REQ/REP 14 | 15 | ## Features 16 | * Network MQ communication via TCP 17 | * PUB/SUB/UNSUB protocol 18 | * REQ/REP protocol 19 | * Message sign verification 20 | * Message Encoding/Decoding for security enforced messages 21 | * Configurations for Client, Node, Messages via toml configs 22 | * Configuration generator for Client and Node 23 | * Basis sample application for Client and Node 24 | 25 | 26 | ## Useful commands 27 | * `make` - run `cargo check` 28 | * `make build` - build all 29 | * `make release` - build release version 30 | * `make test` - run tests 31 | * `make fmt` - formatting code 32 | * `make node` - build & run sample Node 33 | * `make client1` - build & run sample Client1 34 | * `make client1` - build & run sample Client2 35 | 36 | 37 | #### License MIT 38 | -------------------------------------------------------------------------------- /examples/client.rs: -------------------------------------------------------------------------------- 1 | use amq::client::MqClient; 2 | use amq::types::ClientConfig; 3 | 4 | /// Check command arguments 5 | fn check_commands() { 6 | let args = std::env::args(); 7 | if args.len() != 2 { 8 | help_message(1); 9 | } 10 | } 11 | 12 | /// Print help message for CLI commands 13 | fn help_message(code: i32) { 14 | println!( 15 | r#" 16 | Actix MQ network Client 17 | 18 | Usage: client [CONFIG_FILE] 19 | "# 20 | ); 21 | std::process::exit(code); 22 | } 23 | 24 | /// Read config data form TOML file 25 | fn read_config() -> ClientConfig { 26 | let mut args = std::env::args(); 27 | let config_file = args.nth(1).unwrap(); 28 | 29 | let config_data = std::fs::read_to_string(config_file).expect("File not found"); 30 | toml::from_str(&config_data).expect("Failed to parse config file") 31 | } 32 | 33 | fn main() { 34 | check_commands(); 35 | let client_config = &read_config(); 36 | MqClient::new(&client_config).dial(); 37 | } 38 | -------------------------------------------------------------------------------- /examples/node.rs: -------------------------------------------------------------------------------- 1 | use amq::node::MqNode; 2 | use amq::types::NodeConfig; 3 | 4 | /// Check command arguments 5 | fn check_commands() { 6 | let args = std::env::args(); 7 | if args.len() != 2 { 8 | help_message(1); 9 | } 10 | } 11 | 12 | /// Print help message for CLI commands 13 | fn help_message(code: i32) { 14 | println!( 15 | r#" 16 | Actix MQ network Node 17 | 18 | Usage: node [CONFIG_FILE] 19 | "# 20 | ); 21 | std::process::exit(code); 22 | } 23 | 24 | /// Read config data form TOML file 25 | fn read_config() -> NodeConfig { 26 | let mut args = std::env::args(); 27 | let config_file = args.nth(1).unwrap(); 28 | 29 | let config_data = std::fs::read_to_string(config_file).expect("File not found"); 30 | toml::from_str(&config_data).expect("Failed to parse config file") 31 | } 32 | 33 | fn main() { 34 | check_commands(); 35 | let node_config = read_config(); 36 | MqNode::new(&node_config).serve(); 37 | } 38 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | use crate::codec::{ 2 | ClientMqCodec, MessageData, 3 | MessageProtocol::{Pub, ReqRep, Sub, UnSub}, 4 | MqRequest, MqResponse, 5 | }; 6 | use crate::server; 7 | use crate::sign; 8 | use crate::types::{ClientAppConfig, ClientConfig}; 9 | 10 | use actix::prelude::*; 11 | use futures::{stream::once, Future}; 12 | use log::info; 13 | use serde_derive::{Deserialize, Serialize}; 14 | use serde_json as json; 15 | use sodiumoxide::crypto::box_; 16 | use sodiumoxide::crypto::sign::ed25519::PublicKey; 17 | use std::str::FromStr; 18 | use std::time::Duration; 19 | use std::time::SystemTime; 20 | use std::{io, net, process, thread}; 21 | use tokio_codec::FramedRead; 22 | use tokio_io::io::WriteHalf; 23 | use tokio_io::AsyncRead; 24 | use tokio_tcp::TcpStream; 25 | use uuid::Uuid; 26 | 27 | const PING_TIME_SEC: u64 = 5; 28 | 29 | /// Basic type for MQ Client 30 | pub struct MqClient { 31 | pub config: ClientAppConfig, 32 | } 33 | 34 | /// Basic MQ client connection data 35 | struct MqClientConnection { 36 | framed: actix::io::FramedWrite, ClientMqCodec>, 37 | settings: ClientAppConfig, 38 | } 39 | 40 | /// Struct for client message 41 | #[derive(Debug, Deserialize, Serialize)] 42 | struct ClientMessageData { 43 | title: String, 44 | amount: i32, 45 | } 46 | 47 | #[derive(Message)] 48 | struct ClientCommand(String); 49 | 50 | #[derive(Message)] 51 | struct RegisterCommand(PublicKey); 52 | 53 | /// MQ ClientCommand actor 54 | impl Actor for MqClientConnection { 55 | type Context = Context; 56 | 57 | fn started(&mut self, ctx: &mut Context) { 58 | // start heartbeats otherwise server will disconnect after 10 seconds 59 | self.hb(ctx) 60 | } 61 | 62 | fn stopping(&mut self, _: &mut Context) -> Running { 63 | info!("Disconnected"); 64 | 65 | // Stop application on disconnect 66 | System::current().stop(); 67 | 68 | Running::Stop 69 | } 70 | } 71 | 72 | /// Basic MQ Client implementation 73 | impl MqClient { 74 | /// Init New node struct with config data 75 | pub fn new(cfg: &ClientConfig) -> Self { 76 | Self { 77 | config: ClientAppConfig::new(cfg), 78 | } 79 | } 80 | 81 | /// Dial Client connection to Node 82 | pub fn dial(&self) { 83 | let client_config = self.config.clone(); 84 | actix::System::run(move || { 85 | // Connect to server 86 | let addr = net::SocketAddr::from_str(&format!( 87 | "{}:{:?}", 88 | client_config.node.ip, client_config.node.port 89 | )) 90 | .unwrap(); 91 | 92 | Arbiter::spawn( 93 | TcpStream::connect(&addr) 94 | .and_then(move |stream| { 95 | let addr = MqClientConnection::create(move |ctx| { 96 | let (r, w) = stream.split(); 97 | ctx.add_stream(FramedRead::new(r, ClientMqCodec)); 98 | ctx.add_message_stream(once(Ok(RegisterCommand( 99 | client_config.public_key, 100 | )))); 101 | MqClientConnection { 102 | framed: actix::io::FramedWrite::new(w, ClientMqCodec, ctx), 103 | settings: client_config, 104 | } 105 | }); 106 | 107 | // Start console loop 108 | let addr_to_send = addr.clone(); 109 | thread::spawn(move || loop { 110 | let mut cmd = String::new(); 111 | if let Err(msg) = io::stdin().read_line(&mut cmd) { 112 | println!("Error: {:?}", msg); 113 | return; 114 | } 115 | 116 | addr_to_send.do_send(ClientCommand(cmd)); 117 | }); 118 | 119 | futures::future::ok(()) 120 | }) 121 | .map_err(|e| { 122 | println!("Can not connect to server: {:?}", e); 123 | process::exit(1) 124 | }), 125 | ); 126 | }); 127 | } 128 | } 129 | 130 | /// Basic Mq Client Connection implementations 131 | impl MqClientConnection { 132 | /// Heard beat flow for Ping connections 133 | fn hb(&self, ctx: &mut Context) { 134 | ctx.run_later(Duration::new(PING_TIME_SEC, 0), |act, ctx| { 135 | act.framed.write(MqRequest::Ping); 136 | act.hb(ctx); 137 | }); 138 | } 139 | } 140 | 141 | impl actix::io::WriteHandler for MqClientConnection {} 142 | 143 | /// Handle Register commands 144 | impl Handler for MqClientConnection { 145 | type Result = (); 146 | 147 | fn handle(&mut self, msg: RegisterCommand, _: &mut Context) { 148 | let pk = msg.0; 149 | println!("Handler: {}", sign::to_hex_pk(&pk)); 150 | self.framed.write(MqRequest::Register(pk)); 151 | } 152 | } 153 | 154 | /// Handle stdin commands 155 | impl Handler for MqClientConnection { 156 | type Result = (); 157 | 158 | fn handle(&mut self, msg: ClientCommand, _: &mut Context) { 159 | println!("Handler"); 160 | 161 | let m = msg.0.trim(); 162 | 163 | // we check for /command type of messages 164 | if m.starts_with('/') { 165 | let v: Vec<&str> = m.splitn(2, ' ').collect(); 166 | let client1_pk = sign::from_string_pk( 167 | &"f20bfbae14396d9d3da5b35f8d9c2800244f59ddb7492af045930b760c893185".to_string(), 168 | ); 169 | 170 | let client2_pk = sign::from_string_pk( 171 | &"5238e1c69a42280dc5d2d93ca18889a7ecbc6388872d4e64ac328eed7940b5b7".to_string(), 172 | ); 173 | 174 | match v[0] { 175 | "/reqrep" => { 176 | if v.len() < 2 { 177 | println!(">> Wrong /reqrep command. For help print: /help"); 178 | return; 179 | } 180 | match v[1] { 181 | "client1" => { 182 | let msg_data = json::to_string(&ClientMessageData { 183 | title: "message for client1".to_owned(), 184 | amount: 100, 185 | }) 186 | .expect("Message should be serialize to JSON"); 187 | 188 | let mut msg = MessageData { 189 | id: Uuid::new_v4().to_string(), 190 | to: Some(client1_pk), 191 | signature: None, 192 | event: None, 193 | protocol: ReqRep, 194 | time: SystemTime::now(), 195 | nonce: None, 196 | body: msg_data, 197 | }; 198 | 199 | if self.settings.message.encode { 200 | let nonce = box_::gen_nonce(); 201 | let encoded_msg = box_::seal( 202 | &msg.body.as_bytes(), 203 | &nonce, 204 | &self.settings.message.public_key, 205 | &self.settings.message.secret_key, 206 | ); 207 | 208 | msg.body = sign::to_hex(&encoded_msg); 209 | msg.nonce = Some(nonce); 210 | } 211 | 212 | let data = 213 | json::to_string(&msg).expect("Message should be serialize to JSON"); 214 | 215 | // Set message sign 216 | msg.signature = if self.settings.message.sign { 217 | Some(sign::sign(data.as_bytes(), &self.settings.secret_key)) 218 | } else { 219 | None 220 | }; 221 | 222 | self.framed.write(MqRequest::Message(msg)); 223 | } 224 | "client2" => { 225 | let msg_data = json::to_string(&ClientMessageData { 226 | title: "message for client2".to_owned(), 227 | amount: 200, 228 | }) 229 | .expect("Message should be serialize to JSON"); 230 | 231 | let mut msg = MessageData { 232 | id: Uuid::new_v4().to_string(), 233 | to: Some(client2_pk), 234 | signature: None, 235 | event: None, 236 | protocol: ReqRep, 237 | time: SystemTime::now(), 238 | nonce: None, 239 | body: msg_data, 240 | }; 241 | 242 | if self.settings.message.encode { 243 | let nonce = box_::gen_nonce(); 244 | let encoded_msg = box_::seal( 245 | &msg.body.as_bytes(), 246 | &nonce, 247 | &self.settings.message.public_key, 248 | &self.settings.message.secret_key, 249 | ); 250 | 251 | msg.body = sign::to_hex(&encoded_msg); 252 | msg.nonce = Some(nonce); 253 | } 254 | 255 | let data = 256 | json::to_string(&msg).expect("Message should be serialize to JSON"); 257 | 258 | // Set message sign 259 | msg.signature = if self.settings.message.sign { 260 | Some(sign::sign(data.as_bytes(), &self.settings.secret_key)) 261 | } else { 262 | None 263 | }; 264 | 265 | self.framed.write(MqRequest::Message(msg)); 266 | } 267 | _ => println!(">> Wrong /reqrep command. For help print: /help"), 268 | } 269 | } 270 | "/pub" => { 271 | if v.len() < 2 { 272 | println!(">> Wrong /pub command. For help print: /help"); 273 | return; 274 | } 275 | let event_name = Some(v[1].to_owned()); 276 | 277 | let msg_data = json::to_string(&ClientMessageData { 278 | title: format!( 279 | "Public message from: {}", 280 | sign::to_hex(&self.settings.public_key[..]) 281 | ) 282 | .to_owned(), 283 | amount: 100, 284 | }) 285 | .expect("Message should be serialize to JSON"); 286 | 287 | // Public message not encode message body 288 | let mut msg = MessageData { 289 | id: Uuid::new_v4().to_string(), 290 | to: None, 291 | signature: None, 292 | event: event_name, 293 | protocol: Pub, 294 | time: SystemTime::now(), 295 | nonce: None, 296 | body: msg_data, 297 | }; 298 | 299 | let data = json::to_string(&msg).expect("Message should be serialize to JSON"); 300 | 301 | // Set message sign 302 | msg.signature = if self.settings.message.sign { 303 | Some(sign::sign(data.as_bytes(), &self.settings.secret_key)) 304 | } else { 305 | None 306 | }; 307 | 308 | self.framed.write(MqRequest::Message(msg)); 309 | } 310 | "/sub" => { 311 | if v.len() < 2 { 312 | println!(">> Wrong /sub command. For help print: /help"); 313 | return; 314 | } 315 | let event_name = Some(v[1].to_owned()); 316 | 317 | let mut msg = MessageData { 318 | id: Uuid::new_v4().to_string(), 319 | to: None, 320 | signature: None, 321 | event: event_name, 322 | protocol: Sub, 323 | time: SystemTime::now(), 324 | nonce: None, 325 | body: String::from(""), 326 | }; 327 | 328 | let data = json::to_string(&msg).expect("Message should be serialize to JSON"); 329 | 330 | // Set message sign 331 | msg.signature = if self.settings.message.sign { 332 | Some(sign::sign(data.as_bytes(), &self.settings.secret_key)) 333 | } else { 334 | None 335 | }; 336 | 337 | self.framed.write(MqRequest::Message(msg)); 338 | } 339 | "/unsub" => { 340 | if v.len() < 2 { 341 | println!(">> Wrong /unsub command. For help print: /help"); 342 | return; 343 | } 344 | let event_name = Some(v[1].to_owned()); 345 | 346 | let mut msg = MessageData { 347 | id: Uuid::new_v4().to_string(), 348 | to: None, 349 | signature: None, 350 | event: event_name, 351 | protocol: UnSub, 352 | time: SystemTime::now(), 353 | nonce: None, 354 | body: String::from(""), 355 | }; 356 | 357 | let data = json::to_string(&msg).expect("Message should be serialize to JSON"); 358 | 359 | // Set message sign 360 | msg.signature = if self.settings.message.sign { 361 | Some(sign::sign(data.as_bytes(), &self.settings.secret_key)) 362 | } else { 363 | None 364 | }; 365 | 366 | self.framed.write(MqRequest::Message(msg)); 367 | } 368 | "/ping" => { 369 | if v.len() < 2 { 370 | println!(">> Wrong /ping command. For help print: /help"); 371 | return; 372 | } 373 | match v[1] { 374 | "client1" => { 375 | self.framed.write(MqRequest::PingClient(client1_pk)); 376 | } 377 | "client2" => { 378 | self.framed.write(MqRequest::PingClient(client2_pk)); 379 | } 380 | _ => { 381 | println!("Unknown client name. Print for help: /help"); 382 | return; 383 | } 384 | } 385 | } 386 | "/help" => { 387 | println!( 388 | r#"Commands HELP: 389 | /ping [CLIENT] ping connected clients 390 | client will ping by pub_key. 391 | Available clients name: client1, client2 392 | 393 | /help print this help 394 | [CLIENT] [MESSAGE] send message to specific client. 395 | Available clients name: client1, client2 396 | 397 | /reqrep [CLIENT] send REQ/REP message to specific client. 398 | Available clients name: client1, client2 399 | 400 | /pub [NAME] send PUB message for specific channel name. 401 | Example: /pub my.public.channel 402 | 403 | /sub [NAME] send SUB message to subscribe for specific channel name. 404 | Example: /sub my.public.channel 405 | 406 | /unsub [NAME] send UNSUB message to unsubscrive from specific channel name. 407 | Example: /unsub my.public.channel 408 | 409 | "# 410 | ); 411 | } 412 | _ => println!(">> unknown command. For help print: /help"), 413 | } 414 | } else { 415 | println!(">> Unknown command. For help print: /help"); 416 | } 417 | } 418 | } 419 | 420 | /// Server communication 421 | impl StreamHandler for MqClientConnection { 422 | fn handle(&mut self, msg: MqResponse, _: &mut Context) { 423 | match msg { 424 | MqResponse::Message(mut msg) => { 425 | let is_verified = msg.verify(); 426 | println!("message: {:#?}", msg); 427 | println!("is verified: {:#?}", is_verified); 428 | 429 | // Encode message 430 | if msg.protocol != Pub && self.settings.message.encode { 431 | let encoded_msg = box_::open( 432 | &sign::from_hex(&msg.body), 433 | &msg.nonce.unwrap(), 434 | &self.settings.message.public_key, 435 | &self.settings.message.secret_key, 436 | ) 437 | .expect("Message should be decoded."); 438 | 439 | let msg_data = std::str::from_utf8(&encoded_msg[..]) 440 | .expect("Message should be valid UTF8 string"); 441 | let client_msg: ClientMessageData = json::from_str(&msg_data).unwrap(); 442 | dbg!(client_msg); 443 | } else { 444 | let client_msg: ClientMessageData = json::from_str(&msg.body).unwrap(); 445 | dbg!(client_msg); 446 | } 447 | 448 | // Send message response data for ReqRep 449 | if msg.protocol == ReqRep { 450 | self.framed 451 | .write(MqRequest::MessageResponse(server::MqMessageResponse { 452 | from: msg.from, 453 | to: msg.to, 454 | status: server::MessageSendStatus::Received, 455 | })); 456 | } 457 | } 458 | MqResponse::Pong => {} 459 | MqResponse::PingClient(pk) => { 460 | println!("PingClient"); 461 | self.framed.write(MqRequest::PongClient(pk)); 462 | } 463 | MqResponse::PongClient(pk) => { 464 | println!("PongClient response: {:}", sign::to_hex_pk(&pk)); 465 | } 466 | MqResponse::MessageResponseStatus(status) => { 467 | println!("MessageResponseStatus: {:#?}", status); 468 | } 469 | } 470 | } 471 | } 472 | -------------------------------------------------------------------------------- /src/codec.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use actix::Message; 3 | use byteorder::{BigEndian, ByteOrder}; 4 | use bytes::{BufMut, BytesMut}; 5 | use serde_derive::{Deserialize, Serialize}; 6 | use serde_json as json; 7 | use sodiumoxide::crypto::box_ as cipher; 8 | use sodiumoxide::crypto::sign::ed25519::{PublicKey, Signature}; 9 | use std::io; 10 | use std::time::SystemTime; 11 | use tokio_io::codec::{Decoder, Encoder}; 12 | 13 | use crate::server; 14 | 15 | /// Client request 16 | #[derive(Serialize, Deserialize, Debug, Message)] 17 | #[serde(tag = "cmd", content = "data")] 18 | pub enum MqRequest { 19 | /// Ping request 20 | Ping, 21 | /// Ping client by pub_key 22 | PingClient(PublicKey), 23 | /// Pong from client by pub_key 24 | PongClient(PublicKey), 25 | /// Send message 26 | Message(MessageData), 27 | /// Register request 28 | Register(PublicKey), 29 | /// Message Response request 30 | MessageResponse(server::MqMessageResponse), 31 | } 32 | 33 | /// Basic MQ message target/type 34 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] 35 | #[serde(tag = "cmd", content = "data")] 36 | pub enum MessageProtocol { 37 | /// Publish for PUB/SUB protocol 38 | Pub, 39 | /// Subscribe for PUB/SUB protocol 40 | Sub, 41 | /// Unsubscribe for PUB/SUB protocol 42 | UnSub, 43 | /// Request / Response protocol 44 | ReqRep, 45 | } 46 | 47 | /// Basic MQ Message Data 48 | #[derive(Serialize, Deserialize, Debug, Clone)] 49 | pub struct MessageData { 50 | pub id: String, 51 | pub to: Option, 52 | pub signature: Option, 53 | pub event: Option, 54 | pub protocol: MessageProtocol, 55 | pub time: SystemTime, 56 | pub nonce: Option, 57 | pub body: String, 58 | } 59 | 60 | impl MessageData { 61 | /// Convert message to Server message 62 | pub fn to_message(&self, from: &PublicKey) -> server::MqMessage { 63 | server::MqMessage { 64 | id: self.id.clone(), 65 | from: *from, 66 | to: self.to, 67 | signature: self.signature, 68 | event: self.event.clone(), 69 | protocol: self.protocol.clone(), 70 | time: self.time, 71 | nonce: self.nonce, 72 | body: self.body.clone(), 73 | } 74 | } 75 | } 76 | 77 | /// Server response 78 | #[derive(Serialize, Deserialize, Debug, Message)] 79 | #[serde(tag = "cmd", content = "data")] 80 | pub enum MqResponse { 81 | /// Pong response 82 | Pong, 83 | /// Receive Message 84 | Message(server::MqMessage), 85 | /// Ping message for Client 86 | PingClient(PublicKey), 87 | /// Pong message for Client 88 | PongClient(PublicKey), 89 | /// Message response status 90 | MessageResponseStatus(server::MqMessageResponse), 91 | } 92 | 93 | /// Codec for Client -> Server transport 94 | pub struct MqCodec; 95 | 96 | impl Decoder for MqCodec { 97 | type Item = MqRequest; 98 | type Error = io::Error; 99 | 100 | fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { 101 | let size = { 102 | if src.len() < 2 { 103 | return Ok(None); 104 | } 105 | BigEndian::read_u16(src.as_ref()) as usize 106 | }; 107 | 108 | if src.len() >= size + 2 { 109 | src.split_to(2); 110 | let buf = src.split_to(size); 111 | Ok(Some(json::from_slice::(&buf)?)) 112 | } else { 113 | Ok(None) 114 | } 115 | } 116 | } 117 | 118 | impl Encoder for MqCodec { 119 | type Item = MqResponse; 120 | type Error = io::Error; 121 | 122 | fn encode(&mut self, msg: MqResponse, dst: &mut BytesMut) -> Result<(), Self::Error> { 123 | let msg = json::to_string(&msg).unwrap(); 124 | let msg_ref: &[u8] = msg.as_ref(); 125 | 126 | dst.reserve(msg_ref.len() + 2); 127 | dst.put_u16_be(msg_ref.len() as u16); 128 | dst.put(msg_ref); 129 | 130 | Ok(()) 131 | } 132 | } 133 | 134 | /// Codec for Server -> Client transport 135 | pub struct ClientMqCodec; 136 | 137 | impl Decoder for ClientMqCodec { 138 | type Item = MqResponse; 139 | type Error = io::Error; 140 | 141 | fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { 142 | let size = { 143 | if src.len() < 2 { 144 | return Ok(None); 145 | } 146 | BigEndian::read_u16(src.as_ref()) as usize 147 | }; 148 | 149 | if src.len() >= size + 2 { 150 | src.split_to(2); 151 | let buf = src.split_to(size); 152 | Ok(Some(json::from_slice::(&buf)?)) 153 | } else { 154 | Ok(None) 155 | } 156 | } 157 | } 158 | 159 | impl Encoder for ClientMqCodec { 160 | type Item = MqRequest; 161 | type Error = io::Error; 162 | 163 | fn encode(&mut self, msg: MqRequest, dst: &mut BytesMut) -> Result<(), Self::Error> { 164 | let msg = json::to_string(&msg).unwrap(); 165 | let msg_ref: &[u8] = msg.as_ref(); 166 | 167 | dst.reserve(msg_ref.len() + 2); 168 | dst.put_u16_be(msg_ref.len() as u16); 169 | dst.put(msg_ref); 170 | 171 | Ok(()) 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::types::{ClientConfig, ClientMessageConfig, ClientNodeConfig, NodeConfig}; 2 | use std::env; 3 | use std::fs; 4 | use toml; 5 | 6 | mod sign; 7 | mod types; 8 | 9 | /// Basic config types 10 | enum AppConfigType { 11 | Node, 12 | Client, 13 | } 14 | 15 | /// Generate config data by specific ty[e 16 | fn generate_config_date(config_type: AppConfigType) -> String { 17 | let (pk, sk) = sign::gen_keypair(); 18 | let (box_pk, box_sk) = sign::gen_box_keypair(); 19 | 20 | match config_type { 21 | AppConfigType::Client => { 22 | let cfg = ClientConfig { 23 | public_key: sign::to_hex_pk(&pk), 24 | secret_key: sign::to_hex_sk(&sk), 25 | node: ClientNodeConfig { 26 | ip: "0.0.0.0".to_string(), 27 | port: 3030, 28 | }, 29 | message: ClientMessageConfig { 30 | public_key: sign::to_hex(&box_pk[..]), 31 | secret_key: sign::to_hex(&box_sk[..]), 32 | sign: true, 33 | encode: false, 34 | }, 35 | }; 36 | toml::to_string_pretty(&cfg).unwrap() 37 | } 38 | AppConfigType::Node => { 39 | let cfg = NodeConfig { 40 | public_key: sign::to_hex_pk(&pk), 41 | secret_key: sign::to_hex_sk(&sk), 42 | port: 3030, 43 | }; 44 | toml::to_string_pretty(&cfg).unwrap() 45 | } 46 | } 47 | } 48 | 49 | /// Check command arguments 50 | fn check_commands() { 51 | let mut args = env::args(); 52 | if args.len() != 3 { 53 | help_message(1); 54 | } 55 | match args.nth(1).unwrap().as_ref() { 56 | "node" => return, 57 | "client" => return, 58 | "help" => { 59 | help_message(0); 60 | } 61 | _ => { 62 | help_message(1); 63 | } 64 | }; 65 | } 66 | 67 | /// Print help message for CLI commands 68 | fn help_message(code: i32) { 69 | println!( 70 | r#" 71 | Actix MQ network config generator 72 | 73 | Usage: config [COMMAND] [CONFIG_FILE] 74 | 75 | Available commands: 76 | node generate config for Server Node 77 | client generate config for Client that 78 | can connect to specific Server Node 79 | help print that help 80 | "# 81 | ); 82 | std::process::exit(code); 83 | } 84 | 85 | fn main() { 86 | sign::init(); 87 | 88 | check_commands(); 89 | let mut args = env::args(); 90 | 91 | // Fetch config generation parameters 92 | let (config_type, config_file) = { 93 | let config_type = match args.nth(1).unwrap().as_ref() { 94 | "node" => AppConfigType::Node, 95 | "client" => AppConfigType::Client, 96 | _ => { 97 | panic!("Failed to fetch arguments"); 98 | } 99 | }; 100 | (config_type, args.nth(0).unwrap()) 101 | }; 102 | 103 | // Generate config 104 | let cfg_toml = generate_config_date(config_type); 105 | 106 | // Save config to file 107 | if let Err(err) = fs::write(config_file, cfg_toml) { 108 | eprintln!("Failed to create config file: {}", err); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod client; 2 | pub mod codec; 3 | pub mod node; 4 | pub mod server; 5 | pub mod session; 6 | pub mod sign; 7 | pub mod types; 8 | -------------------------------------------------------------------------------- /src/node.rs: -------------------------------------------------------------------------------- 1 | use actix::io::FramedWrite; 2 | use actix::prelude::*; 3 | use futures::Stream; 4 | use log::info; 5 | use std::net; 6 | use std::str::FromStr; 7 | use tokio_codec::FramedRead; 8 | use tokio_io::AsyncRead; 9 | use tokio_tcp::{TcpListener, TcpStream}; 10 | 11 | use crate::codec::MqCodec; 12 | use crate::server::MqServer; 13 | use crate::session::MqSession; 14 | use crate::types::{NodeAppConfig, NodeConfig}; 15 | 16 | /// Define tcp server that will accept incoming tcp 17 | /// connection and create MQ actors. 18 | struct Server { 19 | server: Addr, 20 | } 21 | 22 | /// Make actor from `Server` 23 | impl Actor for Server { 24 | /// Every actor has to provide execution `Context` in which it can run. 25 | type Context = Context; 26 | } 27 | 28 | #[derive(Message)] 29 | struct TcpConnect(pub TcpStream, pub net::SocketAddr); 30 | 31 | // Handle stream of TcpStream's 32 | impl Handler for Server { 33 | /// this is response for message, which is defined by `ResponseType` trait 34 | /// in this case we just return unit. 35 | type Result = (); 36 | 37 | fn handle(&mut self, msg: TcpConnect, _: &mut Context) { 38 | println!("Handler"); 39 | // For each incoming connection we create `MqSession` actor 40 | // with out MQ server address. 41 | let server = self.server.clone(); 42 | MqSession::create(move |ctx| { 43 | let (r, w) = msg.0.split(); 44 | MqSession::add_stream(FramedRead::new(r, MqCodec), ctx); 45 | MqSession::new(server, FramedWrite::new(w, MqCodec, ctx)) 46 | }); 47 | } 48 | } 49 | 50 | /// Basic type for MQ Node 51 | pub struct MqNode { 52 | pub config: NodeAppConfig, 53 | } 54 | 55 | /// Basic Node implementation 56 | impl MqNode { 57 | /// Init New node struct with config data 58 | pub fn new(cfg: &NodeConfig) -> Self { 59 | Self { 60 | config: NodeAppConfig::new(cfg), 61 | } 62 | } 63 | 64 | /// Serve Node based on Config data 65 | pub fn serve(&self) { 66 | let config = self.config.clone(); 67 | actix::System::run(move || { 68 | // Start server actor 69 | let server = MqServer::new(config.clone()).start(); 70 | 71 | // Create server listener 72 | let addr = net::SocketAddr::from_str(&format!("0.0.0.0:{:?}", config.port)) 73 | .expect("Can't parse TCP Address"); 74 | let listener = TcpListener::bind(&addr).expect("Can't bind TCP address"); 75 | 76 | // Our MQ server `Server` is an actor, first we need to start it 77 | // and then add stream on incoming tcp connections to it. 78 | // TcpListener::incoming() returns stream of the (TcpStream, net::SocketAddr) 79 | // items So to be able to handle this events `Server` actor has to implement 80 | // stream handler `StreamHandler<(TcpStream, net::SocketAddr), io::Error>` 81 | Server::create(|ctx| { 82 | ctx.add_message_stream(listener.incoming().map_err(|_| ()).map(|stream| { 83 | let addr = stream.peer_addr().unwrap(); 84 | TcpConnect(stream, addr) 85 | })); 86 | Server { server } 87 | }); 88 | 89 | info!("Running MQ server..."); 90 | }); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/server.rs: -------------------------------------------------------------------------------- 1 | use crate::types::NodeAppConfig; 2 | use actix::prelude::*; 3 | use actix::Message; 4 | use serde_derive::{Deserialize, Serialize}; 5 | use serde_json as json; 6 | use sodiumoxide::crypto::box_ as cipher; 7 | use sodiumoxide::crypto::sign::ed25519::{PublicKey, Signature}; 8 | use std::collections::HashMap; 9 | use std::time::SystemTime; 10 | 11 | use crate::codec; 12 | use crate::codec::MessageProtocol::{Pub, Sub, UnSub}; 13 | use crate::session; 14 | use crate::sign; 15 | 16 | /// `MqServer` manages MQ network and 17 | /// responsible for network nodes 18 | /// coordinating. 19 | #[allow(dead_code)] 20 | pub struct MqServer { 21 | sessions: HashMap>, 22 | events: MessageEvents, 23 | settigns: NodeAppConfig, 24 | } 25 | 26 | #[allow(dead_code)] 27 | impl MqServer { 28 | pub fn new(cfg: NodeAppConfig) -> MqServer { 29 | MqServer { 30 | sessions: HashMap::new(), 31 | events: MessageEvents { 32 | subscribers: HashMap::new(), 33 | }, 34 | settigns: cfg, 35 | } 36 | } 37 | } 38 | 39 | /// Make actor from `MqServer` 40 | impl Actor for MqServer { 41 | /// We are going to use simple Context, we just need ability to communicate 42 | /// with other actors. 43 | type Context = Context; 44 | } 45 | 46 | /// Message for MQ server communications 47 | 48 | /// New MQ session is created 49 | pub struct Connect { 50 | pub addr: Addr, 51 | } 52 | 53 | /// Response type for Connect message 54 | /// 55 | /// MQ server returns unique session id 56 | impl actix::Message for Connect { 57 | type Result = PublicKey; 58 | } 59 | 60 | /// Session is disconnected 61 | #[derive(Message)] 62 | pub struct Disconnect(pub PublicKey); 63 | 64 | /// Basic MQ Message Data 65 | #[derive(Message, Debug, Deserialize, Serialize, Clone)] 66 | pub struct MqMessage { 67 | pub id: String, 68 | pub from: PublicKey, 69 | pub to: Option, 70 | pub signature: Option, 71 | pub event: Option, 72 | pub protocol: codec::MessageProtocol, 73 | pub time: SystemTime, 74 | pub nonce: Option, 75 | pub body: String, 76 | } 77 | 78 | #[allow(dead_code)] 79 | impl MqMessage { 80 | /// Convert message to Client message 81 | pub fn to_message(&self) -> codec::MessageData { 82 | codec::MessageData { 83 | id: self.id.clone(), 84 | to: self.to, 85 | signature: self.signature, 86 | event: self.event.clone(), 87 | protocol: self.protocol.clone(), 88 | time: self.time, 89 | nonce: self.nonce, 90 | body: self.body.clone(), 91 | } 92 | } 93 | 94 | /// Verify message signature 95 | pub fn verify(&mut self) -> bool { 96 | if self.signature.is_none() { 97 | return false; 98 | } 99 | let mut msg = self.to_message(); 100 | msg.signature = None; 101 | let data = json::to_string(&msg).expect("Message should be serialize to JSON"); 102 | sign::verify(&self.signature.unwrap(), data.as_bytes(), &self.from) 103 | } 104 | } 105 | 106 | /// Public Message Events subscribers 107 | pub type MessageEventsSubscribers = HashMap>; 108 | 109 | /// Message Events data 110 | #[derive(Debug, Clone)] 111 | pub struct MessageEvents { 112 | /// PUBSUB subscribers 113 | pub subscribers: MessageEventsSubscribers, 114 | } 115 | 116 | /// Sent Message response data 117 | #[derive(Message, Debug, Serialize, Deserialize)] 118 | pub struct MqMessageResponse { 119 | pub from: PublicKey, 120 | pub to: Option, 121 | pub status: MessageSendStatus, 122 | } 123 | 124 | /// Ping message for specific client 125 | #[derive(Message)] 126 | pub struct MqPingClient { 127 | pub from: PublicKey, 128 | pub to: PublicKey, 129 | } 130 | 131 | /// Pong message for specific client 132 | #[derive(Message)] 133 | pub struct MqPongClient { 134 | pub from: PublicKey, 135 | pub to: PublicKey, 136 | } 137 | 138 | /// Register client 139 | pub struct MqRegister { 140 | /// Old client identifier 141 | /// as temporary value that should 142 | /// be set to real client pub_key 143 | pub old_pub_key: PublicKey, 144 | /// Client identifier 145 | pub pub_key: PublicKey, 146 | } 147 | 148 | /// Message send statuses 149 | #[derive(Debug, Serialize, Deserialize)] 150 | pub enum MessageSendStatus { 151 | Sent, 152 | Received, 153 | PeerNotFound, 154 | Failed, 155 | } 156 | 157 | /// Response type for Register message 158 | /// It can be success or fail 159 | impl actix::Message for MqRegister { 160 | type Result = Option; 161 | } 162 | 163 | /// Handler for Connect message. 164 | /// 165 | /// Register new session and assign unique id to this session 166 | impl Handler for MqServer { 167 | type Result = MessageResult; 168 | 169 | fn handle(&mut self, msg: Connect, _: &mut Context) -> Self::Result { 170 | println!("Handler"); 171 | // Generate temporary pub_key for session identification 172 | let (pk, _) = sign::gen_keypair(); 173 | self.sessions.insert(pk, msg.addr); 174 | MessageResult(pk) 175 | } 176 | } 177 | 178 | /// Handler for Disconnect message. 179 | impl Handler for MqServer { 180 | type Result = (); 181 | 182 | fn handle(&mut self, msg: Disconnect, _: &mut Context) { 183 | let pub_key = msg.0; 184 | println!("Handler"); 185 | // Unregister session 186 | self.sessions.remove(&pub_key); 187 | } 188 | } 189 | 190 | /// Handler for Message message. 191 | impl Handler for MqServer { 192 | type Result = (); 193 | 194 | fn handle(&mut self, msg: MqMessage, _: &mut Context) { 195 | println!("Handler"); 196 | let msg_data = msg.clone(); 197 | // Send message and set message status response 198 | let status = if (msg.protocol == Pub || msg.protocol == Sub || msg.protocol == UnSub) 199 | && msg.event.is_some() 200 | { 201 | match msg.protocol { 202 | Pub => { 203 | let event_name = msg.event.clone().unwrap(); 204 | // Send message to subscribers 205 | if let Some(event) = self.events.subscribers.get(&event_name) { 206 | for subscriber in event { 207 | if let Some(addr) = self.sessions.get(subscriber) { 208 | addr.do_send(session::MqSessionMessage(msg.clone())); 209 | } 210 | } 211 | } 212 | } 213 | Sub => { 214 | let event_name = msg.event.unwrap(); 215 | // Add subscriber to specific Event 216 | if let Some(event) = self.events.subscribers.get_mut(&event_name) { 217 | event.push(msg.from); 218 | } else { 219 | self.events.subscribers.insert(event_name, vec![msg.from]); 220 | } 221 | } 222 | UnSub => { 223 | let event_name = msg.event.clone().unwrap(); 224 | // Remove subscriber from specific Event 225 | if let Some(event) = self.events.subscribers.get_mut(&event_name) { 226 | let from = msg.from; 227 | let element = event.iter().position(|x| *x == from); 228 | if element.is_some() { 229 | let _ = event.remove(element.unwrap()); 230 | } 231 | } 232 | } 233 | _ => {} 234 | } 235 | MessageSendStatus::Sent 236 | } else if msg.to.is_none() { 237 | // Check is set peer `to` 238 | MessageSendStatus::PeerNotFound 239 | } else if let Some(addr) = self.sessions.get(&msg.to.unwrap()) { 240 | // Send message to peer `to` 241 | addr.do_send(session::MqSessionMessage(msg)); 242 | MessageSendStatus::Sent 243 | } else if self.sessions.get(&msg.from).is_some() { 244 | // We found `from` peer but not found peer `to` 245 | MessageSendStatus::PeerNotFound 246 | } else { 247 | MessageSendStatus::Failed 248 | }; 249 | 250 | // Send message response to peer 251 | if let Some(addr) = self.sessions.get(&msg_data.from) { 252 | addr.do_send(MqMessageResponse { 253 | from: msg_data.from, 254 | to: msg_data.to, 255 | status, 256 | }); 257 | } 258 | } 259 | } 260 | 261 | /// Handler for Register message. 262 | impl Handler for MqServer { 263 | type Result = MessageResult; 264 | 265 | fn handle(&mut self, msg: MqRegister, _: &mut Context) -> Self::Result { 266 | println!("Handler"); 267 | 268 | // Check is Client already registered 269 | if self.sessions.get(&msg.pub_key).is_some() { 270 | eprintln!("Client already registered - close session"); 271 | return MessageResult(None); 272 | } 273 | 274 | if let Some(addr) = self.sessions.get(&msg.old_pub_key) { 275 | self.sessions.insert(msg.pub_key, addr.to_owned()); 276 | self.sessions.remove(&msg.old_pub_key); 277 | } else { 278 | eprintln!("Session address not found"); 279 | return MessageResult(None); 280 | } 281 | MessageResult(Some(msg.pub_key)) 282 | } 283 | } 284 | 285 | /// Handler for Ping Client message. 286 | impl Handler for MqServer { 287 | type Result = (); 288 | 289 | fn handle(&mut self, msg: MqPingClient, _: &mut Context) -> Self::Result { 290 | println!("Handler"); 291 | 292 | if let Some(addr) = self.sessions.get(&msg.to) { 293 | addr.do_send(session::MqSessionPingClient(msg.from)); 294 | } 295 | } 296 | } 297 | 298 | /// Handler for Pong Client message. 299 | impl Handler for MqServer { 300 | type Result = (); 301 | 302 | fn handle(&mut self, msg: MqPongClient, _: &mut Context) -> Self::Result { 303 | println!("Handler"); 304 | 305 | if let Some(addr) = self.sessions.get(&msg.to) { 306 | addr.do_send(session::MqSessionPongClient(msg.from)); 307 | } 308 | } 309 | } 310 | 311 | /// Handler for Response message. 312 | impl Handler for MqServer { 313 | type Result = (); 314 | 315 | fn handle(&mut self, msg: MqMessageResponse, _: &mut Context) { 316 | println!("Handler"); 317 | 318 | // Send response message to `from` peer 319 | if let Some(addr) = self.sessions.get(&msg.from) { 320 | addr.do_send(msg); 321 | } 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /src/session.rs: -------------------------------------------------------------------------------- 1 | use actix::io::{FramedWrite, WriteHandler}; 2 | use actix::prelude::*; 3 | use actix::Message; 4 | use sodiumoxide::crypto::sign::ed25519::PublicKey; 5 | use std::io; 6 | use std::time::{Duration, Instant}; 7 | use tokio_io::io::WriteHalf; 8 | use tokio_tcp::TcpStream; 9 | 10 | use crate::codec::{MqCodec, MqRequest, MqResponse}; 11 | use crate::server::{self, MqServer}; 12 | use crate::sign; 13 | 14 | const PING_TIME_SEC: u64 = 5; 15 | const PING_WAIT_SEC: u64 = 15; 16 | 17 | /// MQ server sends this messages to session 18 | #[derive(Message)] 19 | pub struct MqSessionMessage(pub server::MqMessage); 20 | 21 | /// MQ server sends this Disconnect for 22 | /// current session 23 | #[derive(Message)] 24 | pub struct MqSessionDisconnect; 25 | 26 | /// Ping message for Client 27 | #[derive(Message)] 28 | pub struct MqSessionPingClient(pub PublicKey); 29 | 30 | /// Pong message for Client 31 | #[derive(Message)] 32 | pub struct MqSessionPongClient(pub PublicKey); 33 | 34 | /// `MqSession` actor is responsible for tcp peer communications. 35 | pub struct MqSession { 36 | /// MQ session NodePublicKey 37 | pub_key: Option, 38 | /// this is address of MQ server 39 | addr: Addr, 40 | /// Client must send ping at least once per 10 seconds, otherwise we drop 41 | /// connection. 42 | hb: Instant, 43 | /// Framed wrapper 44 | framed: FramedWrite, MqCodec>, 45 | } 46 | 47 | impl Actor for MqSession { 48 | type Context = actix::Context; 49 | 50 | fn started(&mut self, ctx: &mut Self::Context) { 51 | // We'll start heartbeat process on session start. 52 | self.hb(ctx); 53 | println!("Session started"); 54 | 55 | // Register self in MQ server. `AsyncContext::wait` register 56 | // future within context, but context waits until this future resolves 57 | // before processing any other events. 58 | self.addr 59 | .send(server::Connect { 60 | addr: ctx.address(), 61 | }) 62 | .into_actor(self) 63 | .then(|res, act, ctx| { 64 | match res { 65 | Ok(pk) => { 66 | // Set session pub_key 67 | act.pub_key = Some(pk); 68 | } 69 | // something is wrong with MQ server 70 | _ => ctx.stop(), 71 | } 72 | actix::fut::ok(()) 73 | }) 74 | .wait(ctx); 75 | } 76 | 77 | fn stopping(&mut self, _: &mut Self::Context) -> Running { 78 | // notify MQ server 79 | self.addr.do_send(server::Disconnect(self.pub_key.unwrap())); 80 | Running::Stop 81 | } 82 | } 83 | 84 | impl WriteHandler for MqSession {} 85 | 86 | /// To use `Framed` with an actor, we have to implement `StreamHandler` trait 87 | impl StreamHandler for MqSession { 88 | /// This is main event loop for client requests 89 | fn handle(&mut self, msg: MqRequest, ctx: &mut Self::Context) { 90 | match msg { 91 | MqRequest::Message(message) => { 92 | if self.pub_key.is_none() { 93 | eprintln!("MqRequest::Message - pub_key not sets"); 94 | return; 95 | } 96 | // Send message to MQ server 97 | println!("Peer message: {:#?}", message); 98 | 99 | self.addr 100 | .do_send(message.to_message(&self.pub_key.unwrap())); 101 | } 102 | // we update heartbeat time on ping from peer 103 | MqRequest::Ping => self.hb = { Instant::now() }, 104 | MqRequest::PingClient(pk) => { 105 | println!("MqRequest::PingClient"); 106 | self.addr.do_send(server::MqPingClient { 107 | from: self.pub_key.unwrap(), 108 | to: pk, 109 | }); 110 | } 111 | MqRequest::PongClient(pk) => { 112 | println!("MqRequest::PongClient"); 113 | self.addr.do_send(server::MqPongClient { 114 | from: self.pub_key.unwrap(), 115 | to: pk, 116 | }); 117 | } 118 | MqRequest::Register(pk) => { 119 | if self.pub_key.is_none() { 120 | eprintln!("Register pub_key: session pub_key not set"); 121 | return; 122 | } 123 | 124 | let old_pub_key = self.pub_key.unwrap(); 125 | 126 | println!("Register pub_key: {}", sign::to_hex_pk(&pk)); 127 | 128 | self.addr 129 | .send(server::MqRegister { 130 | old_pub_key: old_pub_key, 131 | pub_key: pk, 132 | }) 133 | .into_actor(self) 134 | .then(|res, act, ctx| { 135 | match res { 136 | // Registration successful 137 | Ok(Some(pub_key)) => { 138 | // Change old pub_key 139 | act.pub_key = Some(pub_key.clone()); 140 | } 141 | // Registration failed 142 | // stopping current session 143 | _ => ctx.stop(), 144 | } 145 | actix::fut::ok(()) 146 | }) 147 | .wait(ctx); 148 | } 149 | MqRequest::MessageResponse(response) => { 150 | self.addr.do_send(server::MqMessageResponse { 151 | from: response.from, 152 | to: response.to, 153 | status: response.status, 154 | }); 155 | } 156 | } 157 | } 158 | } 159 | 160 | /// Handler for MqMessage, MqServer sends this message 161 | impl Handler for MqSession { 162 | type Result = (); 163 | 164 | fn handle(&mut self, msg: MqSessionMessage, _: &mut Self::Context) { 165 | // Send message to peer 166 | self.framed.write(MqResponse::Message(msg.0)); 167 | } 168 | } 169 | 170 | /// Handler for hard disconnect current session 171 | impl Handler for MqSession { 172 | type Result = (); 173 | 174 | fn handle(&mut self, _: MqSessionDisconnect, ctx: &mut Self::Context) { 175 | println!("Handler"); 176 | // Notify MQ server 177 | self.addr.do_send(server::Disconnect(self.pub_key.unwrap())); 178 | 179 | // Stop actor 180 | ctx.stop(); 181 | } 182 | } 183 | 184 | /// Handler for Clent Ping 185 | impl Handler for MqSession { 186 | type Result = (); 187 | 188 | fn handle(&mut self, msg: MqSessionPingClient, _: &mut Self::Context) { 189 | // Send Ping message to peer 190 | println!("Handler: {}", sign::to_hex_pk(&msg.0)); 191 | self.framed.write(MqResponse::PingClient(msg.0)); 192 | } 193 | } 194 | 195 | /// Handler for Clent Pong 196 | impl Handler for MqSession { 197 | type Result = (); 198 | 199 | fn handle(&mut self, msg: MqSessionPongClient, _: &mut Self::Context) { 200 | // Send Pong message to peer 201 | self.framed.write(MqResponse::PongClient(msg.0)); 202 | } 203 | } 204 | 205 | #[allow(dead_code)] 206 | impl MqSession { 207 | /// Basic Session initialisation 208 | pub fn new( 209 | addr: Addr, 210 | framed: FramedWrite, MqCodec>, 211 | ) -> MqSession { 212 | MqSession { 213 | pub_key: None, 214 | addr, 215 | framed, 216 | hb: Instant::now(), 217 | } 218 | } 219 | 220 | /// Helper method that sends ping to client every second. 221 | /// 222 | /// Also this method check heartbeats from client 223 | fn hb(&self, ctx: &mut actix::Context) { 224 | ctx.run_later(Duration::new(PING_TIME_SEC, 0), |act, ctx| { 225 | // Check client heartbeats 226 | if Instant::now().duration_since(act.hb) > Duration::new(PING_WAIT_SEC, 0) { 227 | // Heartbeat timed out 228 | println!("Client heartbeat failed, disconnecting!"); 229 | 230 | // Notify MQ server 231 | act.addr.do_send(server::Disconnect(act.pub_key.unwrap())); 232 | 233 | // Stop actor 234 | ctx.stop(); 235 | } 236 | 237 | act.framed.write(MqResponse::Pong); 238 | act.hb(ctx); 239 | }); 240 | } 241 | } 242 | 243 | /// Response handler to peer 244 | impl Handler for MqSession { 245 | type Result = (); 246 | 247 | fn handle(&mut self, msg: server::MqMessageResponse, _: &mut Context) { 248 | // Send response message to peer 249 | self.framed.write(MqResponse::MessageResponseStatus(msg)); 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/sign.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use hex; 3 | use sodiumoxide::crypto::{ 4 | box_, 5 | sign::ed25519, 6 | sign::ed25519::{PublicKey, SecretKey, Seed, Signature}, 7 | }; 8 | 9 | /// Initializes the sodium library and automatically selects faster versions 10 | /// of the primitives, if possible. 11 | pub fn init() { 12 | if sodiumoxide::init().is_err() { 13 | panic!("Cryptographic library hasn't initialized."); 14 | } 15 | } 16 | 17 | /// Signs a slice of bytes using the signer's secret key and returns the 18 | /// resulting `Signature`. 19 | pub fn sign(data: &[u8], secret_key: &SecretKey) -> Signature { 20 | ed25519::sign_detached(data, secret_key) 21 | } 22 | 23 | /// Computes a secret key and a corresponding public key from a `Seed`. 24 | pub fn gen_keypair_from_seed(seed: &Seed) -> (PublicKey, SecretKey) { 25 | ed25519::keypair_from_seed(seed) 26 | } 27 | 28 | /// Generates a secret key and a corresponding public key using a cryptographically secure 29 | /// pseudo-random number generator. 30 | pub fn gen_keypair() -> (PublicKey, SecretKey) { 31 | ed25519::gen_keypair() 32 | } 33 | 34 | /// Generate box_ keypair for message encoding/decoding 35 | pub fn gen_box_keypair() -> (box_::PublicKey, box_::SecretKey) { 36 | box_::gen_keypair() 37 | } 38 | 39 | /// Verifies that `data` is signed with a secret key corresponding to the 40 | /// given public key. 41 | pub fn verify(sig: &Signature, data: &[u8], pub_key: &PublicKey) -> bool { 42 | ed25519::verify_detached(sig, data, pub_key) 43 | } 44 | 45 | /// Returns a hex representation of binary data. 46 | pub fn to_hex_pk(pk: &PublicKey) -> String { 47 | hex::encode(&pk[..]) 48 | } 49 | 50 | /// Convert data to hex string 51 | pub fn to_hex(data: &[u8]) -> String { 52 | hex::encode(&data[..]) 53 | } 54 | 55 | /// Convert data from hex [u8] 56 | pub fn from_hex(data: &String) -> Vec { 57 | hex::decode(&data).unwrap() 58 | } 59 | 60 | /// Return PublicKey from hex string 61 | pub fn from_string_pk(hex: &String) -> PublicKey { 62 | let pk = hex::decode(hex).unwrap(); 63 | PublicKey::from_slice(&pk).unwrap() 64 | } 65 | 66 | /// Return Box PublicKey from hex string 67 | pub fn from_string_box_pk(hex: &String) -> box_::PublicKey { 68 | let pk = hex::decode(hex).unwrap(); 69 | box_::PublicKey::from_slice(&pk).unwrap() 70 | } 71 | 72 | /// Return Box SecretKey from hex string 73 | pub fn from_string_box_sk(hex: &String) -> box_::SecretKey { 74 | let pk = hex::decode(hex).unwrap(); 75 | box_::SecretKey::from_slice(&pk).unwrap() 76 | } 77 | 78 | /// Returns a hex representation of binary data. 79 | pub fn to_hex_sk(pk: &SecretKey) -> String { 80 | hex::encode(&pk[..]) 81 | } 82 | 83 | /// Return SecretKey from hex string 84 | pub fn from_string_sk(hex: &String) -> SecretKey { 85 | let sk = hex::decode(hex).unwrap(); 86 | SecretKey::from_slice(&sk).unwrap() 87 | } 88 | 89 | /* 90 | /// Calculates hash of a bytes slice. 91 | pub fn hash(data: &[u8]) -> Hash { 92 | sha256::hash(data) 93 | } 94 | 95 | pub fn hash(data: &[u8]) -> Hash { 96 | let dig = crypto_impl::hash(data); 97 | Hash(dig) 98 | } 99 | */ 100 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | use crate::sign; 2 | use serde_derive::{Deserialize, Serialize}; 3 | use sodiumoxide::crypto::box_; 4 | use sodiumoxide::crypto::sign::ed25519::{PublicKey, SecretKey}; 5 | 6 | /// Basic Node configuration 7 | #[derive(Serialize, Deserialize, Debug)] 8 | pub struct NodeConfig { 9 | pub public_key: String, 10 | pub secret_key: String, 11 | pub port: u32, 12 | } 13 | 14 | /// Basic client config 15 | #[derive(Serialize, Deserialize, Debug)] 16 | pub struct ClientConfig { 17 | pub public_key: String, 18 | pub secret_key: String, 19 | pub node: ClientNodeConfig, 20 | pub message: ClientMessageConfig, 21 | } 22 | 23 | /// Client config - node for connection 24 | #[derive(Serialize, Deserialize, Debug)] 25 | pub struct ClientNodeConfig { 26 | pub ip: String, 27 | pub port: u32, 28 | } 29 | 30 | #[derive(Serialize, Deserialize, Debug, Clone)] 31 | pub struct ClientMessageConfig { 32 | /// PubKey for encoding message 33 | pub public_key: String, 34 | /// SecretKey for encoding message 35 | pub secret_key: String, 36 | /// Should message be crypto sign 37 | pub sign: bool, 38 | /// Should message be encoded with crypto keys 39 | pub encode: bool, 40 | } 41 | 42 | #[derive(Serialize, Deserialize, Debug, Clone)] 43 | pub struct ClientAppMessageConfig { 44 | /// PubKey for encoding message 45 | pub public_key: box_::PublicKey, 46 | /// SecretKey for encoding message 47 | pub secret_key: box_::SecretKey, 48 | /// Should message be crypto sign 49 | pub sign: bool, 50 | /// Should message be encoded with crypto keys 51 | pub encode: bool, 52 | } 53 | 54 | /// Node app config struct 55 | #[derive(Serialize, Deserialize, Debug, Clone)] 56 | pub struct NodeAppConfig { 57 | pub public_key: PublicKey, 58 | pub secret_key: SecretKey, 59 | pub port: u32, 60 | } 61 | 62 | /// Client app config struct 63 | #[derive(Serialize, Deserialize, Debug, Clone)] 64 | pub struct ClientAppConfig { 65 | pub public_key: PublicKey, 66 | pub secret_key: SecretKey, 67 | pub node: ClientAppNodeConfig, 68 | pub message: ClientAppMessageConfig, 69 | } 70 | 71 | /// Client app config - node for connection 72 | #[derive(Serialize, Deserialize, Debug, Clone)] 73 | pub struct ClientAppNodeConfig { 74 | pub ip: String, 75 | pub port: u32, 76 | } 77 | 78 | /// Init Node app configuration 79 | #[allow(dead_code)] 80 | impl NodeAppConfig { 81 | pub fn new(cfg: &NodeConfig) -> Self { 82 | NodeAppConfig { 83 | public_key: sign::from_string_pk(&cfg.public_key), 84 | secret_key: sign::from_string_sk(&cfg.secret_key), 85 | port: cfg.port, 86 | } 87 | } 88 | } 89 | 90 | /// Init Client app configuration 91 | #[allow(dead_code)] 92 | impl ClientAppConfig { 93 | pub fn new(cfg: &ClientConfig) -> Self { 94 | ClientAppConfig { 95 | public_key: sign::from_string_pk(&cfg.public_key), 96 | secret_key: sign::from_string_sk(&cfg.secret_key), 97 | node: ClientAppNodeConfig { 98 | ip: cfg.node.ip.clone(), 99 | port: cfg.node.port, 100 | }, 101 | message: ClientAppMessageConfig { 102 | public_key: sign::from_string_box_pk(&cfg.message.public_key), 103 | secret_key: sign::from_string_box_sk(&cfg.message.secret_key), 104 | sign: cfg.message.sign, 105 | encode: cfg.message.encode, 106 | }, 107 | } 108 | } 109 | } 110 | --------------------------------------------------------------------------------