diff options
31 files changed, 2824 insertions, 741 deletions
@@ -1,10 +1,10 @@ # Generated by Cargo # will have compiled files and executables /target/ -/plugin_derive/target/ +/frippy_derive/target/ # The top level Cargo.lock should handle everything -/plugin_derive/Cargo.lock +/frippy_derive/Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk diff --git a/.travis.yml b/.travis.yml index cae9543..afb7296 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,12 @@ matrix: allow_failures: - rust: nightly +script: + - cargo test --verbose + - cargo test --verbose --features mysql + +cache: cargo + notifications: email: false irc: @@ -4,34 +4,28 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "advapi32-sys" -version = "0.2.0" +name = "aho-corasick" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "aho-corasick" -version = "0.6.3" +name = "antidote" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "backtrace" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -39,27 +33,27 @@ name = "backtrace-sys" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "base64" -version = "0.6.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bitflags" -version = "0.7.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.9.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -74,16 +68,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -91,14 +85,14 @@ name = "cargo_metadata" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -111,36 +105,38 @@ name = "chrono" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clippy" -version = "0.0.166" +version = "0.0.186" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.166 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clippy_lints" -version = "0.0.166" +version = "0.0.186" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -149,7 +145,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -157,39 +153,91 @@ name = "core-foundation-sys" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crc" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crc-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crc-core" -version = "0.1.0" +name = "derive-error-chain" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "crypt32-sys" -version = "0.2.0" +name = "derive-error-chain" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "dbghelp-sys" -version = "0.2.0" +name = "diesel" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel_derives 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "mysqlclient-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "diesel_derives" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "diesel_infer_schema" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "infer_schema_macros 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "diesel_migrations" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "migrations_internals 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "migrations_macros 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dotenv" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "derive-error-chain 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dotenv" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "derive-error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -199,7 +247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "either" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -260,71 +308,132 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "encoding_rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "error-chain" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "error-chain" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "foreign-types" -version = "0.2.0" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "frippy" version = "0.3.1" dependencies = [ - "clippy 0.0.166 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel_infer_schema 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "diesel_migrations 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "frippy_derive 0.1.0", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "irc 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin_derive 0.1.0", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "irc 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2-diesel 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rlua 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "unicode_names 0.1.7 (git+https://github.com/Jokler/unicode_names?branch=update-to-latest-unicode)", ] [[package]] +name = "frippy_derive" +version = "0.1.0" +dependencies = [ + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "fuchsia-zircon" -version = "0.2.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-zircon-sys" -version = "0.2.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "futures" -version = "0.1.16" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-cpupool" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] +name = "gcc" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "getopts" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -333,31 +442,45 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "httparse" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "humantime" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "hyper" -version = "0.11.6" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -365,13 +488,13 @@ name = "hyper-tls" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.19 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -385,34 +508,58 @@ dependencies = [ ] [[package]] +name = "if_chain" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "infer_schema_internals" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "diesel 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "infer_schema_macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dotenv 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "infer_schema_internals 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "iovec" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "irc" -version = "0.12.5" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-mockstream 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -421,7 +568,7 @@ name = "itertools" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -445,33 +592,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "0.2.9" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazycell" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.32" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libflate" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "matches" @@ -480,10 +643,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memchr" -version = "1.0.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "migrations_internals" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "diesel 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "migrations_macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "migrations_internals 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -491,12 +672,12 @@ name = "mime" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "mime_guess" -version = "2.0.0-alpha.2" +version = "2.0.0-alpha.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -507,16 +688,16 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -535,15 +716,26 @@ dependencies = [ ] [[package]] +name = "mysqlclient-sys" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "native-tls" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "openssl 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -553,77 +745,85 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.34" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.40" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl" -version = "0.9.20" +version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.26 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.9.20" +version = "0.9.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "percent-encoding" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -649,7 +849,7 @@ version = "0.7.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -667,11 +867,11 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "plugin_derive" -version = "0.1.0" +name = "proc-macro2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -680,10 +880,15 @@ version = "0.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] +name = "quick-error" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "quine-mc_cluskey" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -694,79 +899,129 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "quote" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "r2d2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "r2d2-diesel" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "diesel 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "rand" -version = "0.3.17" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.31" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" -version = "0.2.2" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "relay" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "remove_dir_all" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "reqwest" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.19 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libflate 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libflate 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mime_guess 2.0.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rustc-demangle" -version = "0.1.5" +name = "rlua" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "rustc_version" -version = "0.1.7" +name = "rustc-demangle" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "safemem" @@ -775,40 +1030,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "schannel" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "scoped-tls" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "secur32-sys" +name = "scheduled-thread-pool" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] +name = "scoped-tls" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "security-framework" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -818,16 +1067,11 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "semver" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "semver" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -841,22 +1085,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.16" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.16" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.16.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -865,13 +1109,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -881,8 +1125,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -916,6 +1160,16 @@ dependencies = [ ] [[package]] +name = "syn" +version = "0.12.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "synom" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -924,61 +1178,70 @@ dependencies = [ ] [[package]] +name = "synstructure" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "take" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "tempdir" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" -version = "0.1.38" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-core" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -986,8 +1249,8 @@ name = "tokio-mockstream" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -995,15 +1258,15 @@ name = "tokio-proto" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1012,7 +1275,7 @@ name = "tokio-service" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1020,19 +1283,19 @@ name = "tokio-timer" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-tls" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1040,7 +1303,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1053,10 +1316,10 @@ dependencies = [ [[package]] name = "unicase" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1078,9 +1341,14 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "unicode_names" version = "0.1.7" -source = "git+https://github.com/Jokler/unicode_names?branch=update-to-latest-unicode#6f3ad8f563cbd9a29c2857a451f1bf8cc0e105ee" +source = "git+https://github.com/Jokler/unicode_names?branch=update-to-latest-unicode#d97b80c3c35b9f1d04085409087ef113c94cde17" [[package]] name = "unreachable" @@ -1092,12 +1360,12 @@ dependencies = [ [[package]] name = "url" -version = "1.5.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1110,7 +1378,7 @@ name = "uuid" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1134,11 +1402,30 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "winapi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1149,31 +1436,36 @@ dependencies = [ [metadata] "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" -"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" -"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" +"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" +"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" +"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" +"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" -"checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" +"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" +"checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" -"checksum cc 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4019bdb99c0c1ddd56c12c2f507c174d729c6915eca6bd9d27c42f3d93b0f4" +"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" -"checksum clippy 0.0.166 (registry+https://github.com/rust-lang/crates.io-index)" = "86c1e9a7fd08987104fcca0ce1ab0a627006ed955ce14a87ffa32754c947fccb" -"checksum clippy_lints 0.0.166 (registry+https://github.com/rust-lang/crates.io-index)" = "cbde64e1942d299a8ebe242d54567654db22aa06bdaae7aa3eb392db275172e0" +"checksum clippy 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7b79c57f831e752f3667ae6115d02ed2d9e97a986ff76e5f04d613a8c0842a" +"checksum clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)" = "a3864104a4e6092e644b985dd7543e5f24e99aa7262f5ee400bcb17cfeec1bf5" "checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" "checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" -"checksum crc 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fba69ea0e15e720f7e1cfe1cf3bc55007fbd41e32b8ae11cfa343e7e5961e79a" -"checksum crc-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "003d1170779d405378223470f5864b41b79a91969be1260e4de7b4ec069af69c" -"checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" -"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" +"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" +"checksum derive-error-chain 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9ca9ade651388daad7c993f005d0d20c4f6fe78c1cdc93e95f161c6f5ede4a" +"checksum derive-error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92183014af72c63aea490e66526c712bf1066ac50f66c9f34824f02483ec1d98" +"checksum diesel 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925325c57038f2f14c0413bdf6a92ca72acff644959d0a1a9ebf8d19be7e9c01" +"checksum diesel_derives 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28e2b2605ac6a3b9a586383f5f8b2b5f1108f07a421ade965b266289d2805e79" +"checksum diesel_infer_schema 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd41decf55679a8486a3ea5e5de20e8f2a48c76d57177cd05f37f4d166f48647" +"checksum diesel_migrations 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0928a7d6f27c849954185416bd59439837de55fbc89e2985b0e46e756ae4e3da" +"checksum dotenv 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d6f0e2bb24d163428d8031d3ebd2d2bd903ad933205a97d0f18c7c1aade380f3" +"checksum dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a70de3c590ce18df70743cace1cf12565637a0b26fd8b04ef10c7d33fdc66cdc" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" -"checksum either 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e311a7479512fbdf858fb54d91ec59f3b9f85bc0113659f46bba12b199d273ce" +"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" "checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" "checksum encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" "checksum encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" @@ -1181,106 +1473,135 @@ dependencies = [ "checksum encoding-index-singlebyte 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" "checksum encoding-index-tradchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" "checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" +"checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d" "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" -"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" -"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" -"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" -"checksum futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "05a23db7bd162d4e8265968602930c476f688f0c180b44bdaf55e0cb2c687558" -"checksum futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e86f49cc0d92fe1b97a5980ec32d56208272cbb00f15044ea9e2799dde766fdf" -"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" +"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" +"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" +"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0bab5b5e94f5c31fc764ba5dd9ad16568aae5d4825538c01d6bca680c9bf94a7" +"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" +"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" +"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b45eac8b696d59491b079bd04fcb0f3488c0f6ed62dcb36bcfea8a543e9cdc3" +"checksum htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" +"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" +"checksum humantime 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5369e01a05e3404c421b5d6dcfea6ecf7d5e65eba8a275948151358cd8282042" +"checksum hyper 0.11.19 (registry+https://github.com/rust-lang/crates.io-index)" = "47659bb1cb7ef3cd7b4f9bd2a11349b8d92097d34f9597a3c09e9bcefaf92b61" "checksum hyper-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c81fa95203e2a6087242c38691a0210f23e9f3f8f944350bd676522132e2985" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" -"checksum iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6e8b9c2247fcf6c6a1151f1156932be5606c9fd6f55a2d7f9fc1cb29386b2f7" -"checksum irc 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)" = "484fea2147dd042cdb3dd9e707af9cc9d8f46a4adc04e553ff985203a955ed6e" +"checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" +"checksum infer_schema_internals 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8269258ae59744e7d5bdc44144c4b2319a355ff2ba34a3f629ae8888508a67c7" +"checksum infer_schema_macros 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fcc56d0b579656088758b435c63ad286be3ec5de53f18b2bbe161e85fb3fd0b" +"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +"checksum irc 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)" = "de55365493063dcc2f8193ff63b2c2852684275469be8c1524848a6ceda96044" "checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5" -"checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" -"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" -"checksum libflate 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ae46bcdafa496981e996e57c5be82c0a7f130a071323764c6faa4803619f1e67" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" +"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" +"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" +"checksum libflate 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1a429b86418868c7ea91ee50e9170683f47fd9d94f5375438ec86ec3adb74e8e" +"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum migrations_internals 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd916de6df9ac7e811e7e1ac28e0abfebe5205f3b29a7bda9ec8a41ee980a4eb" +"checksum migrations_macros 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a550cfd76f6cfdf15a7b541893d7c79b68277b0b309f12179211a373a56e617" "checksum mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e00e17be181010a91dbfefb01660b17311059dc8c7f48b9017677721e732bd" -"checksum mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27a5e6679a0614e25adc14c6434ba84e41632b765a6d9cb2031a0cca682699ae" -"checksum mio 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0e8411968194c7b139e9105bc4ae7db0bae232af087147e72f0616ebf5fdb9cb" +"checksum mime_guess 2.0.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130ea3c9c1b65dba905ab5a4d9ac59234a9585c24d135f264e187fe7336febbd" +"checksum mio 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "7da01a5e23070d92d99b1ecd1cd0af36447c6fd44b0fe283c2db199fa136724f" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum native-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04b781c9134a954c84f0594b9ab3f5606abc516030388e8511887ef4c204a1e5" +"checksum mysqlclient-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "879ce08e38739c54d87b7f8332a476004fe2a095f40a142a36f889779d9942b7" +"checksum native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" -"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" -"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" -"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" -"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" -"checksum openssl 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)" = "8bf434ff6117485dc16478d77a4f5c84eccc9c3645c4da8323b287ad6a15a638" -"checksum openssl-sys 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)" = "0ad395f1cee51b64a8d07cc8063498dc7554db62d5f3ca87a67f4eed2791d0c8" -"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" +"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" +"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10" +"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" +"checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" +"checksum openssl-sys 0.9.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5a41ce2f5f2d939c80decde8fcfcf5837c203ca6c06a553510a2fcb84fa3ef1" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc" "checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f" "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" "checksum pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "378e941dbd392c101f2cb88097fa4d7167bc421d4b88de3ff7dbee503bc3233b" +"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "61efcbcd9fa8d8fbb07c84e34a8af18a1ff177b449689ad38a6e9457ecc7b2ae" -"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" -"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" -"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5" -"checksum reqwest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "194fe0d39dea7f89738707bf70e9f3ed47e8aca47d4b2eeaad6ac7831d2d390b" -"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" -"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" +"checksum r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f9078ca6a8a5568ed142083bb2f7dc9295b69d16f867ddcc9849e51b17d8db46" +"checksum r2d2-diesel 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9c29bad92da76d02bc2c020452ebc3a3fe6fa74cfab91e711c43116e4fb1a3" +"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" +"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" +"checksum regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5be5347bde0c48cfd8c3fdc0766cdfe9d8a755ef84d620d6794c778c91de8b2b" +"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" +"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" +"checksum remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d2f806b0fcdabd98acd380dc8daef485e22bcb7cddc811d1337967f2528cf5" +"checksum reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "241faa9a8ca28a03cbbb9815a5d085f271d4c0168a19181f106aa93240c22ddb" +"checksum rlua 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4d6a9d2d1da31dd5cb4878789b924e46a600bdca4895b30f2efd6370d0dfc80e" +"checksum rustc-demangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f312457f8a4fa31d3581a6f423a70d6c33a10b95291985df55f1ff670ec10ce8" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum schannel 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7554288337c1110e34d7a2433518d889374c1de1a45f856b7bcddb03702131fc" +"checksum schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "acece75e0f987c48863a6c792ec8b7d6c4177d4a027f8ccc72f849794f437016" +"checksum scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2ff3fc5223829be817806c6441279c676e454cc7da608faf03b0ccc09d3889" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" -"checksum secur32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f412dfa83308d893101dd59c10d6fda8283465976c28c287c5c855bf8d216bc" "checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" "checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" -"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "e11a631f964d4e6572712ea12075fb1d65eeef42b0058884195b430ac1e26809" -"checksum serde_derive 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1a51d54c805fbc8e12b603d1ba51eaed3195862976be468888ab0e4995d0000e" -"checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58" -"checksum serde_json 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ee28c1d94a7745259b767ca9e5b95d55bafbd3205ca3acb978cad84a6ed6bc62" +"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526" +"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0" +"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5" +"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb" "checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +"checksum syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)" = "517f6da31bc53bf080b9a77b29fbd0ff8da2f5a2ebd24c73c2238274a94ac7cb" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" -"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" -"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" -"checksum tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c843a027f7c1df5f81e7734a0df3f67bf329411781ebf36393ce67beef6071e3" -"checksum tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ab83e7adb5677e42e405fa4ceff75659d93c4d7d7dd22f52fcec59ee9f02af" +"checksum tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f73eebdb68c14bcb24aef74ea96079830e7fa7b31a6106e42ea7ee887c1e134e" +"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" +"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" +"checksum tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "52b4e32d8edbf29501aabb3570f027c6ceb00ccef6538f4bddba0200503e74e8" +"checksum tokio-io 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b9532748772222bf70297ec0e2ad0f17213b4a7dd0e6afb68e0a0768f69f4e4f" "checksum tokio-mockstream 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41bfc436ef8b7f60c19adf3df086330ae9992385e4d8c53b17a323cad288e155" "checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" -"checksum tokio-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d88e411cac1c87e405e4090be004493c5d8072a370661033b1a64ea205ec2e13" +"checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -"checksum unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e01da42520092d0cd2d6ac3ae69eb21a22ad43ff195676b86f8c37f487d6b80" +"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode_names 0.1.7 (git+https://github.com/Jokler/unicode_names?branch=update-to-latest-unicode)" = "<none>" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27" +"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" @@ -9,29 +9,70 @@ keywords = ["irc", "bot"] categories = ["network-programming"] description = "An IRC Bot" -[lib] -name = "frippy" -path = "src/lib.rs" - [[bin]] name = "frippy" -path = "bin/main.rs" doc = false +[features] +mysql = [ + "diesel", + "diesel_infer_schema", + "diesel_migrations", + "dotenv", + "r2d2", + "r2d2-diesel" +] + [dependencies] -irc = "0.12.5" -tokio-core = "0.1.10" -futures = "0.1.16" -log = "0.3.8" -time = "0.1" -reqwest = "0.8.0" -regex = "0.2.2" -lazy_static = "0.2.9" -serde = "1.0.15" -serde_json = "1.0.3" -glob = "0.2" - -plugin_derive = { path = "plugin_derive" } -unicode_names = { git = 'https://github.com/Jokler/unicode_names', branch = 'update-to-latest-unicode' } - -clippy = {version = "*", optional = true} +irc = "0.13.4" +log = "0.4.1" +time = "0.1.39" +humantime = "1.1.0" +rlua = "0.12.2" +reqwest = "0.8.5" +regex = "0.2.6" +lazy_static = "1.0.0" +serde = "1.0.27" +serde_json = "1.0.9" +chrono = "0.4.0" +glob = "0.2.11" +failure = "0.1.1" + +frippy_derive = { path = "frippy_derive" } +htmlescape = "0.3.1" + +[dependencies.unicode_names] +git = 'https://github.com/Jokler/unicode_names' +branch = 'update-to-latest-unicode' + + +[dependencies.diesel] +version = "1.1.1" +optional = true +features = ["mysql", "chrono"] + +[dependencies.diesel_infer_schema] +version = "1.1.0" +optional = true +features = ["mysql"] + +[dependencies.diesel_migrations] +version = "1.1.0" +optional = true +features = ["mysql"] + +[dependencies.r2d2] +version = "0.8.2" +optional = true + +[dependencies.r2d2-diesel] +version = "1.0.0" +optional = true + +[dependencies.dotenv] +version = "0.11.0" +optional = true + +[dependencies.clippy] +version = "*" +optional = true @@ -1,2 +1,6 @@ -# frippy -IRC Bot +# frippy [](https://travis-ci.org/Mavulp/frippy) +Frippy is an IRC bot which sends emojis used to the channel they were received from, +lets you convert from one currency to another and checks the title of html pages +linked in the channel. + +Check the config.toml file to get an idea of how to set the bot up. diff --git a/bin/main.rs b/bin/main.rs deleted file mode 100644 index 86910c0..0000000 --- a/bin/main.rs +++ /dev/null @@ -1,47 +0,0 @@ -extern crate frippy; -extern crate log; -extern crate time; - -use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata}; - -struct Logger; - -impl log::Log for Logger { - fn enabled(&self, metadata: &LogMetadata) -> bool { - metadata.target().contains("frippy") - } - - fn log(&self, record: &LogRecord) { - if self.enabled(record.metadata()) { - if record.metadata().level() >= LogLevel::Debug { - println!("[{}]({}) {} -> {}", - time::now().rfc822(), - record.level(), - record.target(), - record.args()); - } else { - println!("[{}]({}) {}", - time::now().rfc822(), - record.level(), - record.args()); - } - } - } -} - -fn main() { - - let log_level = if cfg!(debug_assertions) { - LogLevelFilter::Debug - } else { - LogLevelFilter::Info - }; - - log::set_logger(|max_log_level| { - max_log_level.set(log_level); - Box::new(Logger) - }) - .unwrap(); - - frippy::run(); -} diff --git a/configs/config.toml b/configs/config.toml index 5ad66e2..56e5240 100644 --- a/configs/config.toml +++ b/configs/config.toml @@ -23,3 +23,8 @@ source = "https://github.com/Mavulp/frippy" #[channel_keys] #"#frippy" = "" + +[options] +#disabled_plugins = "Url" +# If no database url is set a HashMap is used +#mysql_url = "mysql://user:password@address/db" diff --git a/plugin_derive/Cargo.toml b/frippy_derive/Cargo.toml index 0b62f9f..b258f57 100644 --- a/plugin_derive/Cargo.toml +++ b/frippy_derive/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "plugin_derive" +name = "frippy_derive" version = "0.1.0" authors = ["Jokler <jokler.contact@gmail.com>"] @@ -7,5 +7,6 @@ authors = ["Jokler <jokler.contact@gmail.com>"] proc-macro = true [dependencies] -syn = "0.11.11" -quote = "0.3.15" +syn = "0.12.13" +quote = "0.4.2" +failure = "0.1.1" diff --git a/frippy_derive/src/lib.rs b/frippy_derive/src/lib.rs new file mode 100644 index 0000000..efa349a --- /dev/null +++ b/frippy_derive/src/lib.rs @@ -0,0 +1,109 @@ +//! Provides the plugin derive macro +#![recursion_limit="128"] + +extern crate proc_macro; +extern crate syn; +#[macro_use] +extern crate quote; + +extern crate failure; + +use proc_macro::TokenStream; + +#[proc_macro_derive(PluginName)] +pub fn derive_plugin(data: TokenStream) -> TokenStream { + let ast = syn::parse(data).unwrap(); + let gen = expand_plugin(&ast); + gen.into() +} + +fn expand_plugin(ast: &syn::DeriveInput) -> quote::Tokens { + let name = &ast.ident; + let generics = &ast.generics; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + quote! { + impl #impl_generics PluginName for #name #ty_generics #where_clause { + fn name(&self) -> &str { + stringify!(#name) + } + } + } +} + +#[proc_macro_derive(Error, attributes(error))] +pub fn derive_error(data: TokenStream) -> TokenStream { + let ast = syn::parse(data).unwrap(); + let tokens = expand_error(&ast); + // panic!("{}", tokens.to_string()); + tokens.into() +} + +fn expand_error(ast: &syn::DeriveInput) -> quote::Tokens { + if let syn::Data::Enum(_) = ast.data { + } else { + panic!("Error should only be derived on ErrorKind enums"); + }; + + let mut name = None; + for attr in &ast.attrs { + if let Some(syn::Meta::NameValue(name_value)) = attr.interpret_meta() { + if "error" == name_value.ident.to_string() { + if let syn::Lit::Str(lit) = name_value.lit { + name = Some(lit.value()); + } + } + } + }; + + let struct_name = if let Some(name) = name { + syn::Ident::from(name) + } else { + panic!("Define the error attribute for all Error derives"); + }; + + let enum_name = &ast.ident; + + quote! { + #[derive(Debug)] + pub struct #struct_name { + inner: ::failure::Context<#enum_name>, + } + + impl #struct_name { + pub fn kind(&self) -> #enum_name { + *self.inner.get_context() + } + } + + impl From<#enum_name> for #struct_name { + fn from(kind: #enum_name) -> #struct_name { + #struct_name { + inner: ::failure::Context::new(kind), + } + } + } + + impl From<::failure::Context<#enum_name>> for #struct_name { + fn from(inner: ::failure::Context<#enum_name>) -> #struct_name { + #struct_name { inner: inner } + } + } + + impl ::failure::Fail for #struct_name { + fn cause(&self) -> Option<&::failure::Fail> { + self.inner.cause() + } + + fn backtrace(&self) -> Option<&::failure::Backtrace> { + self.inner.backtrace() + } + } + + impl ::std::fmt::Display for #struct_name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + use std::fmt; + fmt::Display::fmt(&self.inner, f) + } + } + } +} diff --git a/migrations/2017-11-03-164322_create_factoids/down.sql b/migrations/2017-11-03-164322_create_factoids/down.sql new file mode 100644 index 0000000..58c2110 --- /dev/null +++ b/migrations/2017-11-03-164322_create_factoids/down.sql @@ -0,0 +1 @@ +DROP TABLE factoids diff --git a/migrations/2017-11-03-164322_create_factoids/up.sql b/migrations/2017-11-03-164322_create_factoids/up.sql new file mode 100644 index 0000000..784a3f4 --- /dev/null +++ b/migrations/2017-11-03-164322_create_factoids/up.sql @@ -0,0 +1,8 @@ +CREATE TABLE factoids ( + name VARCHAR(32) NOT NULL, + idx INTEGER NOT NULL, + content TEXT NOT NULL, + author VARCHAR(32) NOT NULL, + created TIMESTAMP NOT NULL, + PRIMARY KEY (name, idx) +) diff --git a/migrations/2018-02-25-154922_create_tells/down.sql b/migrations/2018-02-25-154922_create_tells/down.sql new file mode 100644 index 0000000..73c9b9b --- /dev/null +++ b/migrations/2018-02-25-154922_create_tells/down.sql @@ -0,0 +1 @@ +DROP TABLE tells diff --git a/migrations/2018-02-25-154922_create_tells/up.sql b/migrations/2018-02-25-154922_create_tells/up.sql new file mode 100644 index 0000000..9de037c --- /dev/null +++ b/migrations/2018-02-25-154922_create_tells/up.sql @@ -0,0 +1,7 @@ +CREATE TABLE tells ( + id SERIAL PRIMARY KEY, + sender VARCHAR(32) NOT NULL, + receiver VARCHAR(32) NOT NULL, + time TIMESTAMP NOT NULL, + message VARCHAR(512) NOT NULL +) diff --git a/plugin_derive/src/lib.rs b/plugin_derive/src/lib.rs deleted file mode 100644 index 704d6ef..0000000 --- a/plugin_derive/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ - -//! Provides the plugin derive macro - -extern crate proc_macro; -extern crate syn; -#[macro_use] -extern crate quote; - -use proc_macro::TokenStream; - -#[proc_macro_derive(PluginName)] -pub fn derive_plugin(data: TokenStream) -> TokenStream { - let ast = syn::parse_derive_input(&data.to_string()).unwrap(); - let gen = expand_plugin(&ast); - gen.parse().unwrap() -} - -fn expand_plugin(ast: &syn::DeriveInput) -> quote::Tokens { - let name = &ast.ident; - quote! { - impl PluginName for #name { - fn name(&self) -> &str { - stringify!(#name) - } - } - } -} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..36d5724 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,31 @@ +//! Errors for `frippy` crate using `failure`. + +use failure::Fail; + +pub fn log_error(e: FrippyError) { + let text = e.causes() + .skip(1) + .fold(format!("{}", e), |acc, err| format!("{}: {}", acc, err)); + error!("{}", text); +} + +/// The main crate-wide error type. +#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)] +#[error = "FrippyError"] +pub enum ErrorKind { + /// Connection error + #[fail(display = "A connection error occured")] + Connection, + + /// A Url error + #[fail(display = "A Url error has occured")] + Url, + + /// A Tell error + #[fail(display = "A Tell error has occured")] + Tell, + + /// A Factoids error + #[fail(display = "A Factoids error has occured")] + Factoids, +} @@ -1,135 +1,196 @@ -#![cfg_attr(feature="clippy", feature(plugin))] -#![cfg_attr(feature="clippy", plugin(clippy))] +#![cfg_attr(feature = "clippy", feature(plugin))] +#![cfg_attr(feature = "clippy", plugin(clippy))] //! Frippy is an IRC bot that runs plugins on each message //! received. //! -//! ## Example +//! ## Examples //! ```no_run -//! extern crate frippy; +//! # extern crate irc; +//! # extern crate frippy; +//! # fn main() { +//! use frippy::{plugins, Config, Bot}; +//! use irc::client::reactor::IrcReactor; //! -//! frippy::run(); +//! let config = Config::load("config.toml").unwrap(); +//! let mut reactor = IrcReactor::new().unwrap(); +//! let mut bot = Bot::new(); +//! +//! bot.add_plugin(plugins::help::Help::new()); +//! bot.add_plugin(plugins::emoji::Emoji::new()); +//! bot.add_plugin(plugins::currency::Currency::new()); +//! +//! bot.connect(&mut reactor, &config).unwrap(); +//! reactor.run().unwrap(); +//! # } //! ``` //! //! # Logging //! Frippy uses the [log](https://docs.rs/log) crate so you can log events //! which might be of interest. +#[cfg(feature = "mysql")] #[macro_use] -extern crate log; +extern crate diesel; +#[cfg(feature = "mysql")] +extern crate r2d2; +#[cfg(feature = "mysql")] +extern crate r2d2_diesel; + +#[macro_use] +extern crate failure; +#[macro_use] +extern crate frippy_derive; #[macro_use] -extern crate plugin_derive; +extern crate lazy_static; +#[macro_use] +extern crate log; +extern crate chrono; +extern crate humantime; extern crate irc; -extern crate tokio_core; -extern crate futures; -extern crate glob; +extern crate reqwest; +extern crate time; -mod plugin; -mod plugins; +pub mod plugin; +pub mod plugins; +pub mod utils; +pub mod error; +use std::collections::HashMap; +use std::fmt; +use std::thread::spawn; use std::sync::Arc; -use irc::client::prelude::*; -use irc::error::Error as IrcError; - -use tokio_core::reactor::Core; -use futures::future; -use glob::glob; +pub use irc::client::prelude::*; +pub use irc::error::IrcError; +use error::*; +use failure::ResultExt; use plugin::*; -/// Runs the bot -/// -/// # Remarks -/// -/// This blocks the current thread while the bot is running -pub fn run() { - - // Load all toml files in the configs directory - let mut configs = Vec::new(); - for toml in glob("configs/*.toml").unwrap() { - match toml { - Ok(path) => { - info!("Loading {}", path.to_str().unwrap()); - match Config::load(path) { - Ok(v) => configs.push(v), - Err(e) => error!("Incorrect config file {}", e), - } - } - Err(e) => error!("Failed to read path {}", e), +/// The bot which contains the main logic. +#[derive(Default)] +pub struct Bot { + plugins: ThreadedPlugins, +} + +impl Bot { + /// Creates a `Bot`. + /// By itself the bot only responds to a few simple CTCP commands + /// defined per config file. + /// Any other functionality has to be provided by plugins + /// which need to implement [`Plugin`](plugin/trait.Plugin.html). + /// + /// # Examples + /// ``` + /// use frippy::Bot; + /// let mut bot = Bot::new(); + /// ``` + pub fn new() -> Bot { + Bot { + plugins: ThreadedPlugins::new(), } } - // Without configs the bot would just idle - if configs.is_empty() { - error!("No config file found"); - return; + /// Adds the [`Plugin`](plugin/trait.Plugin.html). + /// These plugins will be used to evaluate incoming messages from IRC. + /// + /// # Examples + /// ``` + /// use frippy::{plugins, Bot}; + /// + /// let mut bot = frippy::Bot::new(); + /// bot.add_plugin(plugins::help::Help::new()); + /// ``` + pub fn add_plugin<T: Plugin + 'static>(&mut self, plugin: T) { + self.plugins.add(plugin); } - // The list of plugins in use - let mut plugins = ThreadedPlugins::new(); - plugins.add(plugins::Help::new()); - plugins.add(plugins::Emoji::new()); - plugins.add(plugins::Currency::new()); - info!("Plugins loaded: {}", plugins); - - // Create an event loop to run the connections on. - let mut reactor = Core::new().unwrap(); - - // Open a connection and add work for each config - for config in configs { - let server = - match IrcServer::new_future(reactor.handle(), &config).and_then(|f| reactor.run(f)) { - Ok(v) => v, - Err(e) => { - error!("Failed to connect: {}", e); - return; - } - }; + /// Removes a [`Plugin`](plugin/trait.Plugin.html) based on its name. + /// The binary currently uses this to disable plugins + /// based on user configuration. + /// + /// # Examples + /// ``` + /// use frippy::{plugins, Bot}; + /// + /// let mut bot = frippy::Bot::new(); + /// bot.add_plugin(plugins::help::Help::new()); + /// bot.remove_plugin("Help"); + /// ``` + pub fn remove_plugin(&mut self, name: &str) -> Option<()> { + self.plugins.remove(name) + } - info!("Connected to server"); + /// This connects the `Bot` to IRC and creates a task on the + /// [`IrcReactor`](../irc/client/reactor/struct.IrcReactor.html) + /// which returns an Ok if the connection was cleanly closed and + /// an Err if the connection was lost. + /// + /// You need to run the [`IrcReactor`](../irc/client/reactor/struct.IrcReactor.html), + /// so that the `Bot` + /// can actually do its work. + /// + /// # Examples + /// ```no_run + /// # extern crate irc; + /// # extern crate frippy; + /// # fn main() { + /// use frippy::{Config, Bot}; + /// use irc::client::reactor::IrcReactor; + /// + /// let config = Config::load("config.toml").unwrap(); + /// let mut reactor = IrcReactor::new().unwrap(); + /// let mut bot = Bot::new(); + /// + /// bot.connect(&mut reactor, &config).unwrap(); + /// reactor.run().unwrap(); + /// # } + /// ``` + pub fn connect(&self, reactor: &mut IrcReactor, config: &Config) -> Result<(), FrippyError> { + info!("Plugins loaded: {}", self.plugins); - match server.identify() { - Ok(_) => info!("Identified"), - Err(e) => error!("Failed to identify: {}", e), - }; + let client = reactor + .prepare_client_and_connect(config) + .context(ErrorKind::Connection)?; + + info!("Connected to IRC server"); + + client.identify().context(ErrorKind::Connection)?; + info!("Identified"); // TODO Verify if we actually need to clone plugins twice - let plugins = plugins.clone(); + let plugins = self.plugins.clone(); - let task = server - .stream() - .for_each(move |message| process_msg(&server, plugins.clone(), message)) - .map_err(|e| error!("Failed to process message: {}", e)); + reactor.register_client_with_handler(client, move |client, message| { + process_msg(client, plugins.clone(), message) + }); - reactor.handle().spawn(task); + Ok(()) } - - // Run the main loop forever - reactor.run(future::empty::<(), ()>()).unwrap(); } -fn process_msg(server: &IrcServer, - mut plugins: ThreadedPlugins, - message: Message) - -> Result<(), IrcError> { - +fn process_msg( + client: &IrcClient, + mut plugins: ThreadedPlugins, + message: Message, +) -> Result<(), IrcError> { + // Log any channels we join if let Command::JOIN(ref channel, _, _) = message.command { - if message.source_nickname().unwrap() == server.current_nickname() { + if message.source_nickname().unwrap() == client.current_nickname() { info!("Joined {}", channel); } } // Check for possible command and save the result for later - let command = PluginCommand::from(&server.current_nickname().to_lowercase(), &message); + let command = PluginCommand::from(&client.current_nickname().to_lowercase(), &message); - let message = Arc::new(message); - plugins.execute_plugins(server, message); + plugins.execute_plugins(client, message); // If the message contained a command, handle it if let Some(command) = command { - if let Err(e) = plugins.handle_command(server, command) { + if let Err(e) = plugins.handle_command(client, command) { error!("Failed to handle command: {}", e); } } @@ -137,6 +198,110 @@ fn process_msg(server: &IrcServer, Ok(()) } +#[derive(Clone, Default, Debug)] +struct ThreadedPlugins { + plugins: HashMap<String, Arc<Plugin>>, +} + +impl ThreadedPlugins { + pub fn new() -> ThreadedPlugins { + ThreadedPlugins { + plugins: HashMap::new(), + } + } + + pub fn add<T: Plugin + 'static>(&mut self, plugin: T) { + let name = plugin.name().to_lowercase(); + let safe_plugin = Arc::new(plugin); -#[cfg(test)] -mod tests {} + self.plugins.insert(name, safe_plugin); + } + + pub fn remove(&mut self, name: &str) -> Option<()> { + self.plugins.remove(&name.to_lowercase()).map(|_| ()) + } + + pub fn execute_plugins(&mut self, client: &IrcClient, message: Message) { + let message = Arc::new(message); + + for (name, plugin) in self.plugins.clone() { + // Send the message to the plugin if the plugin needs it + match plugin.execute(client, &message) { + ExecutionStatus::Done => (), + ExecutionStatus::Err(e) => log_error(e), + ExecutionStatus::RequiresThread => { + debug!( + "Spawning thread to execute {} with {}", + name, + message.to_string().replace("\r\n", "") + ); + + // Clone everything before the move - the client uses an Arc internally too + let plugin = Arc::clone(&plugin); + let message = Arc::clone(&message); + let client = client.clone(); + + // Execute the plugin in another thread + spawn(move || { + if let Err(e) = plugin.execute_threaded(&client, &message) { + log_error(e); + }; + }); + } + } + } + } + + pub fn handle_command( + &mut self, + client: &IrcClient, + mut command: PluginCommand, + ) -> Result<(), FrippyError> { + if !command.tokens.iter().any(|s| !s.is_empty()) { + let help = format!("Use \"{} help\" to get help", client.current_nickname()); + client + .send_notice(&command.source, &help) + .context(ErrorKind::Connection)?; + } + + // Check if the command is for this plugin + if let Some(plugin) = self.plugins.get(&command.tokens[0].to_lowercase()) { + // The first token contains the name of the plugin + let name = command.tokens.remove(0); + + debug!("Sending command \"{:?}\" to {}", command, name); + + // Clone for the move - the client uses an Arc internally + let client = client.clone(); + let plugin = Arc::clone(plugin); + spawn(move || { + if let Err(e) = plugin.command(&client, command) { + log_error(e); + }; + }); + + Ok(()) + } else { + let help = format!( + "\"{} {}\" is not a command, \ + try \"{0} help\" instead.", + client.current_nickname(), + command.tokens[0] + ); + + Ok(client + .send_notice(&command.source, &help) + .context(ErrorKind::Connection)?) + } + } +} + +impl fmt::Display for ThreadedPlugins { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let plugin_names = self.plugins + .iter() + .map(|(_, p)| p.name().to_owned()) + .collect::<Vec<String>>(); + write!(f, "{}", plugin_names.join(", ")) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b9a4b8f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,191 @@ +#![cfg_attr(feature = "clippy", feature(plugin))] +#![cfg_attr(feature = "clippy", plugin(clippy))] + +extern crate frippy; +extern crate glob; +extern crate irc; +extern crate time; + +#[cfg(feature = "mysql")] +extern crate diesel; +#[cfg(feature = "mysql")] +#[macro_use] +extern crate diesel_migrations; +#[cfg(feature = "mysql")] +extern crate r2d2; +#[cfg(feature = "mysql")] +extern crate r2d2_diesel; + +#[macro_use] +extern crate failure; +#[macro_use] +extern crate log; + +#[cfg(feature = "mysql")] +use std::sync::Arc; +use std::collections::HashMap; +use log::{Level, LevelFilter, Metadata, Record}; + +use irc::client::reactor::IrcReactor; +use glob::glob; + +pub use frippy::plugins::help::Help; +pub use frippy::plugins::url::Url; +pub use frippy::plugins::emoji::Emoji; +pub use frippy::plugins::tell::Tell; +pub use frippy::plugins::currency::Currency; +pub use frippy::plugins::keepnick::KeepNick; +pub use frippy::plugins::factoids::Factoids; + +use frippy::Config; +use failure::Error; + +#[cfg(feature = "mysql")] +embed_migrations!(); + +struct Logger; + +impl log::Log for Logger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.target().contains("frippy") + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + if record.metadata().level() >= Level::Debug { + println!( + "[{}]({}) {} -> {}", + time::now().rfc822(), + record.level(), + record.target(), + record.args() + ); + } else { + println!( + "[{}]({}) {}", + time::now().rfc822(), + record.level(), + record.args() + ); + } + } + } + + fn flush(&self) {} +} + +static LOGGER: Logger = Logger; + +fn main() { + // Print any errors that caused frippy to shut down + if let Err(e) = run() { + let text = e.causes() + .skip(1) + .fold(format!("{}", e), |acc, err| format!("{}: {}", acc, err)); + error!("{}", text); + }; +} + +fn run() -> Result<(), Error> { + log::set_max_level(if cfg!(debug_assertions) { + LevelFilter::Debug + } else { + LevelFilter::Info + }); + + log::set_logger(&LOGGER).unwrap(); + + // Load all toml files in the configs directory + let mut configs = Vec::new(); + for toml in glob("configs/*.toml").unwrap() { + match toml { + Ok(path) => { + info!("Loading {}", path.to_str().unwrap()); + match Config::load(path) { + Ok(v) => configs.push(v), + Err(e) => error!("Incorrect config file {}", e), + } + } + Err(e) => error!("Failed to read path {}", e), + } + } + + // Without configs the bot would just idle + if configs.is_empty() { + bail!("No config file was found"); + } + + // Create an event loop to run the connections on. + let mut reactor = IrcReactor::new()?; + + // Open a connection and add work for each config + for config in configs { + let mut disabled_plugins = None; + let mut mysql_url = None; + if let Some(ref options) = config.options { + if let Some(disabled) = options.get("disabled_plugins") { + disabled_plugins = Some(disabled.split(',').map(|p| p.trim()).collect::<Vec<_>>()); + } + + mysql_url = options.get("mysql_url"); + } + + let mut bot = frippy::Bot::new(); + bot.add_plugin(Help::new()); + bot.add_plugin(Url::new(1024)); + bot.add_plugin(Emoji::new()); + bot.add_plugin(Currency::new()); + bot.add_plugin(KeepNick::new()); + + #[cfg(feature = "mysql")] + { + if let Some(url) = mysql_url { + use diesel::MysqlConnection; + use r2d2; + use r2d2_diesel::ConnectionManager; + + let manager = ConnectionManager::<MysqlConnection>::new(url.clone()); + match r2d2::Pool::builder().build(manager) { + Ok(pool) => match embedded_migrations::run(&*pool.get()?) { + Ok(_) => { + let pool = Arc::new(pool); + bot.add_plugin(Factoids::new(pool.clone())); + bot.add_plugin(Tell::new(pool.clone())); + info!("Connected to MySQL server") + } + Err(e) => { + bot.add_plugin(Factoids::new(HashMap::new())); + bot.add_plugin(Tell::new(HashMap::new())); + error!("Failed to run migrations: {}", e); + } + }, + Err(e) => error!("Failed to connect to database: {}", e), + } + } else { + bot.add_plugin(Factoids::new(HashMap::new())); + bot.add_plugin(Tell::new(HashMap::new())); + } + } + #[cfg(not(feature = "mysql"))] + { + if mysql_url.is_some() { + error!("frippy was not built with the mysql feature") + } + bot.add_plugin(Factoids::new(HashMap::new())); + bot.add_plugin(Tell::new(HashMap::new())); + } + + if let Some(disabled_plugins) = disabled_plugins { + for name in disabled_plugins { + if bot.remove_plugin(name).is_none() { + error!("\"{}\" was not found - could not disable", name); + } + } + } + + bot.connect(&mut reactor, &config)?; + } + + // Run the bots until they throw an error - an error could be loss of connection + Ok(reactor.run()?) +} diff --git a/src/plugin.rs b/src/plugin.rs index d1f849a..bc428d5 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,49 +1,85 @@ +//! Definitions required for every `Plugin` use std::fmt; -use std::collections::HashMap; -use std::thread::spawn; -use std::sync::Arc; use irc::client::prelude::*; -use irc::error::Error as IrcError; +use error::FrippyError; + +/// Describes if a [`Plugin`](trait.Plugin.html) is done working on a +/// [`Message`](../../irc/proto/message/struct.Message.html) or if another thread is required. +#[derive(Debug)] +pub enum ExecutionStatus { + /// The [`Plugin`](trait.Plugin.html) does not need to do any more work on this + /// [`Message`](../../irc/proto/message/struct.Message.html). + Done, + /// An error occured during the execution. + Err(FrippyError), + /// The execution needs to be done by [`execute_threaded()`](trait.Plugin.html#tymethod.execute_threaded). + RequiresThread, +} +/// `Plugin` has to be implemented for any struct that should be usable +/// as a `Plugin` in frippy. pub trait Plugin: PluginName + Send + Sync + fmt::Debug { - fn is_allowed(&self, server: &IrcServer, message: &Message) -> bool; - fn execute(&self, server: &IrcServer, message: &Message) -> Result<(), IrcError>; - fn command(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError>; + /// Handles messages which are not commands or returns + /// [`RequiresThread`](enum.ExecutionStatus.html#variant.RequiresThread) + /// if [`execute_threaded()`](trait.Plugin.html#tymethod.execute_threaded) should be used instead. + fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus; + /// Handles messages which are not commands in a new thread. + fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError>; + /// Handles any command directed at this plugin. + fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError>; + /// Similar to [`command()`](trait.Plugin.html#tymethod.command) but return a String instead of + /// sending messages directly to IRC. + fn evaluate(&self, client: &IrcClient, command: PluginCommand) -> Result<String, String>; } -pub trait PluginName: Send + Sync + fmt::Debug { +/// `PluginName` is required by [`Plugin`](trait.Plugin.html). +/// +/// To implement it simply add `#[derive(PluginName)]` +/// above the definition of the struct. +/// +/// # Examples +/// ```ignore +/// #[macro_use] extern crate frippy_derive; +/// +/// #[derive(PluginName)] +/// struct Foo; +/// ``` +pub trait PluginName { + /// Returns the name of the `Plugin`. fn name(&self) -> &str; } +/// Represents a command sent by a user to the bot. #[derive(Clone, Debug)] pub struct PluginCommand { + /// The sender of the command. pub source: String, + /// If the command was sent to a channel, this will be that channel + /// otherwise it is the same as `source`. pub target: String, + /// The remaining part of the message that has not been processed yet - split by spaces. pub tokens: Vec<String>, } impl PluginCommand { + /// Creates a `PluginCommand` from [`Message`](../../irc/proto/message/struct.Message.html) + /// if it contains a [`PRIVMSG`](../../irc/proto/command/enum.Command.html#variant.PRIVMSG) + /// that starts with the provided `nick`. pub fn from(nick: &str, message: &Message) -> Option<PluginCommand> { - // Get the actual message out of PRIVMSG if let Command::PRIVMSG(_, ref content) = message.command { - // Split content by spaces and filter empty tokens let mut tokens: Vec<String> = content.split(' ').map(ToOwned::to_owned).collect(); // Commands start with our name if tokens[0].to_lowercase().starts_with(nick) { - // Remove the bot's name from the first token tokens[0].drain(..nick.len()); // We assume that only ':' and ',' are used as suffixes on IRC // If there are any other chars we assume that it is not ment for the bot - tokens[0] = tokens[0] - .chars() - .filter(|&c| !":,".contains(c)) - .collect(); + tokens[0] = tokens[0].chars().filter(|&c| !":,".contains(c)).collect(); if !tokens[0].is_empty() { return None; } @@ -52,10 +88,10 @@ impl PluginCommand { tokens.remove(0); Some(PluginCommand { - source: message.source_nickname().unwrap().to_string(), - target: message.response_target().unwrap().to_string(), - tokens: tokens, - }) + source: message.source_nickname().unwrap().to_string(), + target: message.response_target().unwrap().to_string(), + tokens: tokens, + }) } else { None } @@ -64,96 +100,3 @@ impl PluginCommand { } } } - -#[derive(Clone, Debug)] -pub struct ThreadedPlugins { - plugins: HashMap<String, Arc<Plugin>>, -} - -impl ThreadedPlugins { - pub fn new() -> ThreadedPlugins { - ThreadedPlugins { plugins: HashMap::new() } - } - - pub fn add<T: Plugin + 'static>(&mut self, plugin: T) { - let name = plugin.name().to_lowercase(); - let safe_plugin = Arc::new(plugin); - - self.plugins.insert(name, safe_plugin); - } - - pub fn execute_plugins(&mut self, server: &IrcServer, message: Arc<Message>) { - - for (name, plugin) in self.plugins.clone() { - // Send the message to the plugin if the plugin needs it - if plugin.is_allowed(server, &message) { - - debug!("Executing {} with {}", - name, - message.to_string().replace("\r\n", "")); - - // Clone everything before the move - // The server uses an Arc internally too - let plugin = Arc::clone(&plugin); - let message = Arc::clone(&message); - let server = server.clone(); - - // Execute the plugin in another thread - spawn(move || { - if let Err(e) = plugin.execute(&server, &message) { - error!("Error in {} - {}", name, e); - }; - }); - } - } - } - - pub fn handle_command(&mut self, - server: &IrcServer, - mut command: PluginCommand) - -> Result<(), IrcError> { - - if !command.tokens.iter().any(|s| !s.is_empty()) { - let help = format!("Use \"{} help\" to get help", server.current_nickname()); - return server.send_notice(&command.source, &help); - } - - // Check if the command is for this plugin - if let Some(plugin) = self.plugins.get(&command.tokens[0].to_lowercase()) { - - // The first token contains the name of the plugin - let name = command.tokens.remove(0); - - debug!("Sending command \"{:?}\" to {}", command, name); - - // Clone for the move - the server uses an Arc internally - let server = server.clone(); - let plugin = Arc::clone(plugin); - spawn(move || { - if let Err(e) = plugin.command(&server, command) { - error!("Error in {} command - {}", name, e); - }; - }); - - Ok(()) - - } else { - let help = format!("\"{} {}\" is not a command, \ - try \"{0} help\" instead.", - server.current_nickname(), - command.tokens[0]); - - server.send_notice(&command.source, &help) - } - } -} - -impl fmt::Display for ThreadedPlugins { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let plugin_names = self.plugins - .iter() - .map(|(_, p)| p.name().to_string()) - .collect::<Vec<String>>(); - write!(f, "{}", plugin_names.join(", ")) - } -} diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs index d6cf928..53a245c 100644 --- a/src/plugins/currency.rs +++ b/src/plugins/currency.rs @@ -6,7 +6,6 @@ use std::io::Read; use std::num::ParseFloatError; use irc::client::prelude::*; -use irc::error::Error as IrcError; use self::reqwest::Client; use self::reqwest::header::Connection; @@ -14,7 +13,11 @@ use self::serde_json::Value; use plugin::*; -#[derive(PluginName, Debug)] +use error::FrippyError; +use error::ErrorKind as FrippyErrorKind; +use failure::ResultExt; + +#[derive(PluginName, Default, Debug)] pub struct Currency; struct ConvertionRequest<'a> { @@ -23,18 +26,8 @@ struct ConvertionRequest<'a> { target: &'a str, } -macro_rules! try_option { - ($e:expr) => { - match $e { - Some(v) => v, - None => { return None; } - } - } -} - impl<'a> ConvertionRequest<'a> { fn send(&self) -> Option<f64> { - let response = Client::new() .get("https://api.fixer.io/latest") .form(&[("base", self.source)]) @@ -44,16 +37,14 @@ impl<'a> ConvertionRequest<'a> { match response { Ok(mut response) => { let mut body = String::new(); - try_option!(response.read_to_string(&mut body).ok()); + response.read_to_string(&mut body).ok()?; let convertion_rates: Result<Value, _> = serde_json::from_str(&body); match convertion_rates { Ok(convertion_rates) => { - - let rates: &Value = try_option!(convertion_rates.get("rates")); - let target_rate: &Value = - try_option!(rates.get(self.target.to_uppercase())); - Some(self.value * try_option!(target_rate.as_f64())) + let rates: &Value = convertion_rates.get("rates")?; + let target_rate: &Value = rates.get(self.target.to_uppercase())?; + Some(self.value * target_rate.as_f64()?) } Err(_) => None, } @@ -68,7 +59,10 @@ impl Currency { Currency {} } - fn eval_command<'a>(&self, tokens: &'a [String]) -> Result<ConvertionRequest<'a>, ParseFloatError> { + fn eval_command<'a>( + &self, + tokens: &'a [String], + ) -> Result<ConvertionRequest<'a>, ParseFloatError> { Ok(ConvertionRequest { value: tokens[0].parse()?, source: &tokens[1], @@ -76,76 +70,97 @@ impl Currency { }) } - fn convert(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { - + fn convert(&self, client: &IrcClient, command: &mut PluginCommand) -> Result<String, String> { if command.tokens.len() < 3 { - return self.invalid_command(server, &command); + return Err(self.invalid_command(client)); } let request = match self.eval_command(&command.tokens) { Ok(request) => request, Err(_) => { - return self.invalid_command(server, &command); + return Err(self.invalid_command(client)); } }; match request.send() { Some(response) => { - let response = format!("{} {} => {:.4} {}", - request.value, - request.source.to_lowercase(), - response / 1.00000000, - request.target.to_lowercase()); - - server.send_privmsg(&command.target, &response) + let response = format!( + "{} {} => {:.4} {}", + request.value, + request.source.to_lowercase(), + response / 1.00000000, + request.target.to_lowercase() + ); + + Ok(response) } - None => server.send_notice(&command.source, "Error while converting given currency"), + None => Err(String::from( + "An error occured during the conversion of the given currency", + )), } } - fn help(&self, server: &IrcServer, command: &mut PluginCommand) -> Result<(), IrcError> { - let help = format!("usage: {} currency value from_currency to_currency\r\n\ - example: 1.5 eur usd\r\n\ - available currencies: AUD, BGN, BRL, CAD, \ - CHF, CNY, CZK, DKK, GBP, HKD, HRK, HUF, \ - IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \ - NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \ - TRY, USD, ZAR", - server.current_nickname()); - - server.send_notice(&command.source, &help) + fn help(&self, client: &IrcClient) -> String { + format!( + "usage: {} currency value from_currency to_currency\r\n\ + example: {0} currency 1.5 eur usd\r\n\ + available currencies: AUD, BGN, BRL, CAD, \ + CHF, CNY, CZK, DKK, GBP, HKD, HRK, HUF, \ + IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \ + NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \ + TRY, USD, ZAR", + client.current_nickname() + ) } - fn invalid_command(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> { - let help = format!("Incorrect Command. \ - Send \"{} currency help\" for help.", - server.current_nickname()); - - server.send_notice(&command.source, &help) + fn invalid_command(&self, client: &IrcClient) -> String { + format!( + "Incorrect Command. \ + Send \"{} currency help\" for help.", + client.current_nickname() + ) } } impl Plugin for Currency { - fn is_allowed(&self, _: &IrcServer, _: &Message) -> bool { - false + fn execute(&self, _: &IrcClient, _: &Message) -> ExecutionStatus { + ExecutionStatus::Done } - fn execute(&self, _: &IrcServer, _: &Message) -> Result<(), IrcError> { + fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> { panic!("Currency does not implement the execute function!") } - fn command(&self, server: &IrcServer, mut command: PluginCommand) -> Result<(), IrcError> { + fn command(&self, client: &IrcClient, mut command: PluginCommand) -> Result<(), FrippyError> { + if command.tokens.is_empty() { + return Ok(client + .send_notice(&command.source, &self.invalid_command(client)) + .context(FrippyErrorKind::Connection)?); + } + + match command.tokens[0].as_ref() { + "help" => Ok(client + .send_notice(&command.source, &self.help(client)) + .context(FrippyErrorKind::Connection)?), + _ => match self.convert(client, &mut command) { + Ok(msg) => Ok(client + .send_privmsg(&command.target, &msg) + .context(FrippyErrorKind::Connection)?), + Err(msg) => Ok(client + .send_notice(&command.source, &msg) + .context(FrippyErrorKind::Connection)?), + }, + } + } + fn evaluate(&self, client: &IrcClient, mut command: PluginCommand) -> Result<String, String> { if command.tokens.is_empty() { - return self.invalid_command(server, &command); + return Err(self.invalid_command(client)); } match command.tokens[0].as_ref() { - "help" => self.help(server, &mut command), - _ => self.convert(server, command), + "help" => Ok(self.help(client)), + _ => self.convert(client, &mut command), } } } - -#[cfg(test)] -mod tests {} diff --git a/src/plugins/emoji.rs b/src/plugins/emoji.rs index 1bb714c..f1d9376 100644 --- a/src/plugins/emoji.rs +++ b/src/plugins/emoji.rs @@ -3,10 +3,14 @@ extern crate unicode_names; use std::fmt; use irc::client::prelude::*; -use irc::error::Error as IrcError; use plugin::*; +use error::FrippyError; +use error::ErrorKind as FrippyErrorKind; +use failure::Fail; +use failure::ResultExt; + struct EmojiHandle { symbol: char, count: i32, @@ -14,7 +18,6 @@ struct EmojiHandle { impl fmt::Display for EmojiHandle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let name = match unicode_names::name(self.symbol) { Some(sym) => sym.to_string().to_lowercase(), None => String::from("UNKNOWN"), @@ -28,7 +31,7 @@ impl fmt::Display for EmojiHandle { } } -#[derive(PluginName, Debug)] +#[derive(PluginName, Default, Debug)] pub struct Emoji; impl Emoji { @@ -36,13 +39,12 @@ impl Emoji { Emoji {} } - fn emoji(&self, server: &IrcServer, content: &str, target: &str) -> Result<(), IrcError> { - let names = self.return_emojis(content) + fn emoji(&self, content: &str) -> String { + self.return_emojis(content) .iter() .map(|e| e.to_string()) - .collect::<Vec<String>>(); - - server.send_privmsg(target, &names.join(", ")) + .collect::<Vec<String>>() + .join(", ") } fn return_emojis(&self, string: &str) -> Vec<EmojiHandle> { @@ -53,7 +55,6 @@ impl Emoji { count: 0, }; - for c in string.chars() { if !self.is_emoji(&c) { continue; @@ -61,7 +62,6 @@ impl Emoji { if current.symbol == c { current.count += 1; - } else { if current.count > 0 { emojis.push(current); @@ -98,27 +98,37 @@ impl Emoji { } impl Plugin for Emoji { - fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool { + fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus { match message.command { - Command::PRIVMSG(_, _) => true, - _ => false, + Command::PRIVMSG(_, ref content) => match client + .send_privmsg(message.response_target().unwrap(), &self.emoji(content)) + { + Ok(_) => ExecutionStatus::Done, + Err(e) => ExecutionStatus::Err(e.context(FrippyErrorKind::Connection).into()), + }, + _ => ExecutionStatus::Done, } } - fn execute(&self, server: &IrcServer, message: &Message) -> Result<(), IrcError> { - match message.command { - Command::PRIVMSG(_, ref content) => { - self.emoji(server, content, message.response_target().unwrap()) - } - _ => Ok(()), - } + fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> { + panic!("Emoji should not use threading") } - fn command(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { - server.send_notice(&command.source, - "This Plugin does not implement any commands.") + fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> { + Ok(client + .send_notice( + &command.source, + "This Plugin does not implement any commands.", + ) + .context(FrippyErrorKind::Connection)?) } -} -#[cfg(test)] -mod tests {} + fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> { + let emojis = self.emoji(&command.tokens[0]); + if emojis.is_empty() { + Ok(emojis) + } else { + Err(String::from("No emojis were found.")) + } + } +} diff --git a/src/plugins/factoids/database.rs b/src/plugins/factoids/database.rs new file mode 100644 index 0000000..b1fe8dd --- /dev/null +++ b/src/plugins/factoids/database.rs @@ -0,0 +1,163 @@ +#[cfg(feature = "mysql")] +extern crate dotenv; + +#[cfg(feature = "mysql")] +use std::sync::Arc; +use std::collections::HashMap; + +#[cfg(feature = "mysql")] +use diesel::prelude::*; +#[cfg(feature = "mysql")] +use diesel::mysql::MysqlConnection; +#[cfg(feature = "mysql")] +use r2d2::Pool; +#[cfg(feature = "mysql")] +use r2d2_diesel::ConnectionManager; +#[cfg(feature = "mysql")] +use failure::ResultExt; + +use chrono::NaiveDateTime; + +use super::error::*; + +#[cfg_attr(feature = "mysql", derive(Queryable))] +#[derive(Clone, Debug)] +pub struct Factoid { + pub name: String, + pub idx: i32, + pub content: String, + pub author: String, + pub created: NaiveDateTime, +} + +#[cfg_attr(feature = "mysql", derive(Insertable))] +#[cfg_attr(feature = "mysql", table_name = "factoids")] +pub struct NewFactoid<'a> { + pub name: &'a str, + pub idx: i32, + pub content: &'a str, + pub author: &'a str, + pub created: NaiveDateTime, +} + +pub trait Database: Send { + fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidsError>; + fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidsError>; + fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidsError>; + fn count_factoids(&self, name: &str) -> Result<i32, FactoidsError>; +} + +// HashMap +impl Database for HashMap<(String, i32), Factoid> { + fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidsError> { + let factoid = Factoid { + name: String::from(factoid.name), + idx: factoid.idx, + content: factoid.content.to_string(), + author: factoid.author.to_string(), + created: factoid.created, + }; + + let name = factoid.name.clone(); + match self.insert((name, factoid.idx), factoid) { + None => Ok(()), + Some(_) => Err(ErrorKind::Duplicate)?, + } + } + + fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidsError> { + Ok(self.get(&(String::from(name), idx)) + .cloned() + .ok_or(ErrorKind::NotFound)?) + } + + fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidsError> { + match self.remove(&(String::from(name), idx)) { + Some(_) => Ok(()), + None => Err(ErrorKind::NotFound)?, + } + } + + fn count_factoids(&self, name: &str) -> Result<i32, FactoidsError> { + Ok(self.iter().filter(|&(&(ref n, _), _)| n == name).count() as i32) + } +} + +// Diesel automatically defines the factoids module as public. +// We create a schema module to keep it private. +#[cfg(feature = "mysql")] +mod schema { + table! { + factoids (name, idx) { + name -> Varchar, + idx -> Integer, + content -> Text, + author -> Varchar, + created -> Timestamp, + } + } +} + +#[cfg(feature = "mysql")] +use self::schema::factoids; + +#[cfg(feature = "mysql")] +impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> { + fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidsError> { + use diesel; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + diesel::insert_into(factoids::table) + .values(factoid) + .execute(conn) + .context(ErrorKind::MysqlError)?; + + Ok(()) + } + + fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidsError> { + let conn = &*self.get().context(ErrorKind::NoConnection)?; + Ok(factoids::table + .find((name, idx)) + .first(conn) + .context(ErrorKind::MysqlError)?) + } + + fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidsError> { + use diesel; + use self::factoids::columns; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + match diesel::delete( + factoids::table + .filter(columns::name.eq(name)) + .filter(columns::idx.eq(idx)), + ).execute(conn) + { + Ok(v) => { + if v > 0 { + Ok(()) + } else { + Err(ErrorKind::NotFound)? + } + } + Err(e) => Err(e).context(ErrorKind::MysqlError)?, + } + } + + fn count_factoids(&self, name: &str) -> Result<i32, FactoidsError> { + use diesel; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + let count: Result<i64, _> = factoids::table + .filter(factoids::columns::name.eq(name)) + .count() + .get_result(conn); + + match count { + Ok(c) => Ok(c as i32), + Err(diesel::NotFound) => Ok(0), + Err(e) => Err(e).context(ErrorKind::MysqlError)?, + } + } +} diff --git a/src/plugins/factoids/mod.rs b/src/plugins/factoids/mod.rs new file mode 100644 index 0000000..2f3690f --- /dev/null +++ b/src/plugins/factoids/mod.rs @@ -0,0 +1,342 @@ +extern crate rlua; + +use std::fmt; +use std::str::FromStr; +use std::sync::Mutex; +use self::rlua::prelude::*; +use irc::client::prelude::*; + +use time; +use chrono::NaiveDateTime; + +use plugin::*; +pub mod database; +use self::database::Database; + +mod utils; +use self::utils::*; + +use failure::ResultExt; +use error::ErrorKind as FrippyErrorKind; +use error::FrippyError; +use self::error::*; + +static LUA_SANDBOX: &'static str = include_str!("sandbox.lua"); + +#[derive(PluginName)] +pub struct Factoids<T: Database> { + factoids: Mutex<T>, +} + +macro_rules! try_lock { + ( $m:expr ) => { + match $m.lock() { + Ok(guard) => guard, + Err(poisoned) => poisoned.into_inner(), + } + } +} + +impl<T: Database> Factoids<T> { + pub fn new(db: T) -> Factoids<T> { + Factoids { + factoids: Mutex::new(db), + } + } + + fn create_factoid( + &self, + name: &str, + content: &str, + author: &str, + ) -> Result<&str, FactoidsError> { + let count = try_lock!(self.factoids).count_factoids(name)?; + let tm = time::now().to_timespec(); + + let factoid = database::NewFactoid { + name: name, + idx: count, + content: content, + author: author, + created: NaiveDateTime::from_timestamp(tm.sec, 0u32), + }; + + Ok(try_lock!(self.factoids) + .insert_factoid(&factoid) + .map(|()| "Successfully added!")?) + } + + fn add(&self, command: &mut PluginCommand) -> Result<&str, FactoidsError> { + if command.tokens.len() < 2 { + Err(ErrorKind::InvalidCommand)?; + } + + let name = command.tokens.remove(0); + let content = command.tokens.join(" "); + + Ok(self.create_factoid(&name, &content, &command.source)?) + } + + fn add_from_url(&self, command: &mut PluginCommand) -> Result<&str, FactoidsError> { + if command.tokens.len() < 2 { + Err(ErrorKind::InvalidCommand)?; + } + + let name = command.tokens.remove(0); + let url = &command.tokens[0]; + let content = ::utils::download(url, Some(1024)).context(ErrorKind::Download)?; + + Ok(self.create_factoid(&name, &content, &command.source)?) + } + + fn remove(&self, command: &mut PluginCommand) -> Result<&str, FactoidsError> { + if command.tokens.len() < 1 { + Err(ErrorKind::InvalidCommand)?; + } + + let name = command.tokens.remove(0); + let count = try_lock!(self.factoids).count_factoids(&name)?; + + match try_lock!(self.factoids).delete_factoid(&name, count - 1) { + Ok(()) => Ok("Successfully removed"), + Err(e) => Err(e)?, + } + } + + fn get(&self, command: &PluginCommand) -> Result<String, FactoidsError> { + let (name, idx) = match command.tokens.len() { + 0 => Err(ErrorKind::InvalidCommand)?, + 1 => { + let name = &command.tokens[0]; + let count = try_lock!(self.factoids).count_factoids(name)?; + + if count < 1 { + Err(ErrorKind::NotFound)?; + } + + (name, count - 1) + } + _ => { + let name = &command.tokens[0]; + let idx = match i32::from_str(&command.tokens[1]) { + Ok(i) => i, + Err(_) => Err(ErrorKind::InvalidCommand)?, + }; + + (name, idx) + } + }; + + let factoid = try_lock!(self.factoids) + .get_factoid(name, idx) + .context(ErrorKind::NotFound)?; + + let message = factoid.content.replace("\n", "|").replace("\r", ""); + + Ok(format!("{}: {}", factoid.name, message)) + } + + fn info(&self, command: &PluginCommand) -> Result<String, FactoidsError> { + match command.tokens.len() { + 0 => Err(ErrorKind::InvalidCommand)?, + 1 => { + let name = &command.tokens[0]; + let count = try_lock!(self.factoids).count_factoids(name)?; + + Ok(match count { + 0 => Err(ErrorKind::NotFound)?, + 1 => format!("There is 1 version of {}", name), + _ => format!("There are {} versions of {}", count, name), + }) + } + _ => { + let name = &command.tokens[0]; + let idx = i32::from_str(&command.tokens[1]).context(ErrorKind::InvalidIndex)?; + let factoid = try_lock!(self.factoids).get_factoid(name, idx)?; + + Ok(format!( + "{}: Added by {} at {} UTC", + name, factoid.author, factoid.created + )) + } + } + } + + fn exec(&self, mut command: PluginCommand) -> Result<String, FactoidsError> { + if command.tokens.len() < 1 { + Err(ErrorKind::InvalidIndex)? + } else { + let name = command.tokens.remove(0); + let count = try_lock!(self.factoids).count_factoids(&name)?; + let factoid = try_lock!(self.factoids).get_factoid(&name, count - 1)?; + + let content = factoid.content; + let value = if content.starts_with('>') { + let content = String::from(&content[1..]); + + if content.starts_with('>') { + content + } else { + match self.run_lua(&name, &content, &command) { + Ok(v) => v, + Err(e) => format!("\"{}\"", e), + } + } + } else { + content + }; + + Ok(value.replace("\n", "|").replace("\r", "")) + } + } + + fn run_lua( + &self, + name: &str, + code: &str, + command: &PluginCommand, + ) -> Result<String, rlua::Error> { + let args = command + .tokens + .iter() + .filter(|x| !x.is_empty()) + .map(ToOwned::to_owned) + .collect::<Vec<String>>(); + + let lua = unsafe { Lua::new_with_debug() }; + let globals = lua.globals(); + + globals.set("factoid", code)?; + globals.set("download", lua.create_function(download)?)?; + globals.set("sleep", lua.create_function(sleep)?)?; + globals.set("args", args)?; + globals.set("input", command.tokens.join(" "))?; + globals.set("user", command.source.clone())?; + globals.set("channel", command.target.clone())?; + globals.set("output", lua.create_table()?)?; + + lua.exec::<()>(LUA_SANDBOX, Some(name))?; + let output: Vec<String> = globals.get::<_, Vec<String>>("output")?; + + Ok(output.join("|")) + } +} + +impl<T: Database> Plugin for Factoids<T> { + fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus { + match message.command { + Command::PRIVMSG(_, ref content) => if content.starts_with('!') { + ExecutionStatus::RequiresThread + } else { + ExecutionStatus::Done + }, + _ => ExecutionStatus::Done, + } + } + + fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> { + if let Command::PRIVMSG(_, mut content) = message.command.clone() { + content.remove(0); + + let t: Vec<String> = content.split(' ').map(ToOwned::to_owned).collect(); + + let c = PluginCommand { + source: message.source_nickname().unwrap().to_owned(), + target: message.response_target().unwrap().to_owned(), + tokens: t, + }; + + Ok(match self.exec(c) { + Ok(f) => client + .send_privmsg(&message.response_target().unwrap(), &f) + .context(FrippyErrorKind::Connection)?, + Err(_) => (), + }) + } else { + Ok(()) + } + } + + fn command(&self, client: &IrcClient, mut command: PluginCommand) -> Result<(), FrippyError> { + if command.tokens.is_empty() { + return Ok(client + .send_notice(&command.target, "Invalid command") + .context(FrippyErrorKind::Connection)?); + } + + let target = command.target.clone(); + let source = command.source.clone(); + + let sub_command = command.tokens.remove(0); + let result = match sub_command.as_ref() { + "add" => self.add(&mut command).map(|s| s.to_owned()), + "fromurl" => self.add_from_url(&mut command).map(|s| s.to_owned()), + "remove" => self.remove(&mut command).map(|s| s.to_owned()), + "get" => self.get(&command), + "info" => self.info(&command), + "exec" => self.exec(command), + _ => Err(ErrorKind::InvalidCommand.into()), + }; + + Ok(match result { + Ok(v) => client + .send_privmsg(&target, &v) + .context(FrippyErrorKind::Connection)?, + Err(e) => { + let message = e.to_string(); + client + .send_notice(&source, &message) + .context(FrippyErrorKind::Connection)?; + Err(e).context(FrippyErrorKind::Factoids)? + } + }) + } + + fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> { + Err(String::from( + "Evaluation of commands is not implemented for Factoids at this time", + )) + } +} + +impl<T: Database> fmt::Debug for Factoids<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Factoids {{ ... }}") + } +} + +pub mod error { + #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)] + #[error = "FactoidsError"] + pub enum ErrorKind { + /// Invalid command error + #[fail(display = "Invalid Command")] + InvalidCommand, + + /// Invalid index error + #[fail(display = "Invalid index")] + InvalidIndex, + + /// Download error + #[fail(display = "Download failed")] + Download, + + /// Duplicate error + #[fail(display = "Entry already exists")] + Duplicate, + + /// Not found error + #[fail(display = "Factoid was not found")] + NotFound, + + /// MySQL error + #[cfg(feature = "mysql")] + #[fail(display = "Failed to execute MySQL Query")] + MysqlError, + + /// No connection error + #[cfg(feature = "mysql")] + #[fail(display = "No connection to the database")] + NoConnection, + } +} diff --git a/src/plugins/factoids/sandbox.lua b/src/plugins/factoids/sandbox.lua new file mode 100644 index 0000000..3fc74cd --- /dev/null +++ b/src/plugins/factoids/sandbox.lua @@ -0,0 +1,86 @@ +function send(text) + local text = tostring(text) + local len = #output + if len < 1 then + output = { text } + else + output[len] = output[len] .. text + end +end + +function sendln(text) + send(text) + table.insert(output, "") +end + +local sandbox_env = { + print = send, + println = sendln, + eval = nil, + args = args, + input = input, + user = user, + channel = channel, + request = download, + string = string, + math = math, + table = table, + pairs = pairs, + ipairs = ipairs, + next = next, + select = select, + unpack = unpack, + tostring = tostring, + tonumber = tonumber, + type = type, + assert = assert, + error = error, + pcall = pcall, + xpcall = xpcall, + _VERSION = _VERSION +} + +sandbox_env.os = { + clock = os.clock, + time = os.time, + difftime = os.difftime +} + +sandbox_env.string.rep = nil +sandbox_env.string.dump = nil +sandbox_env.math.randomseed = nil + +-- Temporary evaluation function +function eval(code) + local c, e = load(code, nil, nil, sandbox_env) + if c then + return c() + else + error(e) + end +end + +sandbox_env.eval = eval + +-- Check if the factoid timed out +function checktime(event, line) + if os.time() - time >= timeout then + error("Timed out after " .. timeout .. " seconds", 0) + else + -- Limit the cpu usage of factoids + sleep(1) + end +end + +local f, e = load(factoid, nil, nil, sandbox_env) + +-- Add timeout hook +time = os.time() +timeout = 30 +debug.sethook(checktime, "l") + +if f then + f() +else + error(e) +end diff --git a/src/plugins/factoids/utils.rs b/src/plugins/factoids/utils.rs new file mode 100644 index 0000000..70ac8a7 --- /dev/null +++ b/src/plugins/factoids/utils.rs @@ -0,0 +1,25 @@ +extern crate reqwest; + +use std::thread; +use std::time::Duration; + +use utils; +use super::rlua::prelude::*; + +use self::LuaError::RuntimeError; + +pub fn download(_: &Lua, url: String) -> Result<String, LuaError> { + match utils::download(&url, Some(1024)) { + Ok(v) => Ok(v), + Err(e) => Err(RuntimeError(format!( + "Failed to download {} - {}", + url, + e.to_string() + ))), + } +} + +pub fn sleep(_: &Lua, dur: u64) -> Result<(), LuaError> { + thread::sleep(Duration::from_millis(dur)); + Ok(()) +} diff --git a/src/plugins/help.rs b/src/plugins/help.rs index 8f3fb4d..7e3658d 100644 --- a/src/plugins/help.rs +++ b/src/plugins/help.rs @@ -1,34 +1,36 @@ use irc::client::prelude::*; -use irc::error::Error as IrcError; use plugin::*; -#[derive(PluginName, Debug)] +use error::FrippyError; +use error::ErrorKind as FrippyErrorKind; +use failure::ResultExt; + +#[derive(PluginName, Default, Debug)] pub struct Help; impl Help { pub fn new() -> Help { Help {} } - - fn help(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { - server.send_notice(&command.source, "Help has not been added yet.") - } } impl Plugin for Help { - fn is_allowed(&self, _: &IrcServer, _: &Message) -> bool { - false + fn execute(&self, _: &IrcClient, _: &Message) -> ExecutionStatus { + ExecutionStatus::Done } - fn execute(&self, _: &IrcServer, _: &Message) -> Result<(), IrcError> { - panic!("Help does not implement the execute function!") + fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> { + panic!("Help should not use threading") } - fn command(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> { - self.help(server, command) + fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> { + Ok(client + .send_notice(&command.source, "Help has not been added yet.") + .context(FrippyErrorKind::Connection)?) } -} -#[cfg(test)] -mod tests {} + fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> { + Err(String::from("Help has not been added yet.")) + } +} diff --git a/src/plugins/keepnick.rs b/src/plugins/keepnick.rs new file mode 100644 index 0000000..58ac167 --- /dev/null +++ b/src/plugins/keepnick.rs @@ -0,0 +1,70 @@ +use irc::client::prelude::*; + +use plugin::*; + +use error::FrippyError; +use error::ErrorKind as FrippyErrorKind; +use failure::ResultExt; + +#[derive(PluginName, Default, Debug)] +pub struct KeepNick; + +impl KeepNick { + pub fn new() -> KeepNick { + KeepNick {} + } + + fn check_nick(&self, client: &IrcClient, leaver: &str) -> ExecutionStatus { + let cfg_nick = match client.config().nickname { + Some(ref nick) => nick.clone(), + None => return ExecutionStatus::Done, + }; + + if leaver != cfg_nick { + return ExecutionStatus::Done; + } + + let client_nick = client.current_nickname(); + + if client_nick != cfg_nick { + info!("Trying to switch nick from {} to {}", client_nick, cfg_nick); + match client + .send(Command::NICK(cfg_nick)) + .context(FrippyErrorKind::Connection) + { + Ok(_) => ExecutionStatus::Done, + Err(e) => ExecutionStatus::Err(e.into()), + } + } else { + ExecutionStatus::Done + } + } +} + +impl Plugin for KeepNick { + fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus { + match message.command { + Command::QUIT(ref nick) => { + self.check_nick(client, &nick.clone().unwrap_or_else(String::new)) + } + _ => ExecutionStatus::Done, + } + } + + fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> { + panic!("Tell should not use threading") + } + + fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> { + Ok(client + .send_notice( + &command.source, + "This Plugin does not implement any commands.", + ) + .context(FrippyErrorKind::Connection)?) + } + + fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> { + Err(String::from("This Plugin does not implement any commands.")) + } +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 0dea596..9a3ba2f 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,7 +1,8 @@ -mod help; -mod emoji; -mod currency; - -pub use self::help::Help; -pub use self::emoji::Emoji; -pub use self::currency::Currency; +//! Collection of plugins included +pub mod help; +pub mod url; +pub mod emoji; +pub mod tell; +pub mod currency; +pub mod factoids; +pub mod keepnick; diff --git a/src/plugins/tell/database.rs b/src/plugins/tell/database.rs new file mode 100644 index 0000000..98e9fb3 --- /dev/null +++ b/src/plugins/tell/database.rs @@ -0,0 +1,150 @@ +#[cfg(feature = "mysql")] +extern crate dotenv; + +#[cfg(feature = "mysql")] +use std::sync::Arc; +use std::collections::HashMap; + +#[cfg(feature = "mysql")] +use diesel::prelude::*; +#[cfg(feature = "mysql")] +use diesel::mysql::MysqlConnection; +#[cfg(feature = "mysql")] +use r2d2::Pool; +#[cfg(feature = "mysql")] +use r2d2_diesel::ConnectionManager; + +use chrono::NaiveDateTime; + +#[cfg(feature = "mysql")] +use failure::ResultExt; + +use super::error::*; + +#[cfg_attr(feature = "mysql", derive(Queryable))] +#[derive(PartialEq, Clone, Debug)] +pub struct TellMessage { + pub id: i64, + pub sender: String, + pub receiver: String, + pub time: NaiveDateTime, + pub message: String, +} + +#[cfg_attr(feature = "mysql", derive(Insertable))] +#[cfg_attr(feature = "mysql", table_name = "tells")] +pub struct NewTellMessage<'a> { + pub sender: &'a str, + pub receiver: &'a str, + pub time: NaiveDateTime, + pub message: &'a str, +} + +pub trait Database: Send { + fn insert_tell(&mut self, tell: &NewTellMessage) -> Result<(), TellError>; + fn get_tells(&self, receiver: &str) -> Result<Vec<TellMessage>, TellError>; + fn get_receivers(&self) -> Result<Vec<String>, TellError>; + fn delete_tells(&mut self, receiver: &str) -> Result<(), TellError>; +} + +// HashMap +impl Database for HashMap<String, Vec<TellMessage>> { + fn insert_tell(&mut self, tell: &NewTellMessage) -> Result<(), TellError> { + let tell = TellMessage { + id: 0, + sender: tell.sender.to_string(), + receiver: tell.receiver.to_string(), + time: tell.time, + message: tell.message.to_string(), + }; + + let receiver = tell.receiver.clone(); + let tell_messages = self.entry(receiver) + .or_insert_with(|| Vec::with_capacity(3)); + (*tell_messages).push(tell); + + Ok(()) + } + + fn get_tells(&self, receiver: &str) -> Result<Vec<TellMessage>, TellError> { + Ok(self.get(receiver).cloned().ok_or(ErrorKind::NotFound)?) + } + + fn get_receivers(&self) -> Result<Vec<String>, TellError> { + Ok(self.iter() + .map(|(receiver, _)| receiver.to_owned()) + .collect::<Vec<_>>()) + } + + fn delete_tells(&mut self, receiver: &str) -> Result<(), TellError> { + match self.remove(receiver) { + Some(_) => Ok(()), + None => Err(ErrorKind::NotFound)?, + } + } +} + +// Diesel automatically defines the tells module as public. +// We create a schema module to keep it private. +#[cfg(feature = "mysql")] +mod schema { + table! { + tells (id) { + id -> Bigint, + sender -> Varchar, + receiver -> Varchar, + time -> Timestamp, + message -> Varchar, + } + } +} + +#[cfg(feature = "mysql")] +use self::schema::tells; + +#[cfg(feature = "mysql")] +impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> { + fn insert_tell(&mut self, tell: &NewTellMessage) -> Result<(), TellError> { + use diesel; + + let conn = &*self.get().expect("Failed to get connection"); + diesel::insert_into(tells::table) + .values(tell) + .execute(conn) + .context(ErrorKind::MysqlError)?; + + Ok(()) + } + + fn get_tells(&self, receiver: &str) -> Result<Vec<TellMessage>, TellError> { + use self::tells::columns; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + Ok(tells::table + .filter(columns::receiver.eq(receiver)) + .order(columns::time.asc()) + .load::<TellMessage>(conn) + .context(ErrorKind::MysqlError)?) + } + + fn get_receivers(&self) -> Result<Vec<String>, TellError> { + use self::tells::columns; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + Ok(tells::table + .select(columns::receiver) + .load::<String>(conn) + .context(ErrorKind::MysqlError)?) + } + + fn delete_tells(&mut self, receiver: &str) -> Result<(), TellError> { + use diesel; + use self::tells::columns; + + let conn = &*self.get().context(ErrorKind::NoConnection)?; + diesel::delete(tells::table.filter(columns::receiver.eq(receiver))) + .execute(conn) + .context(ErrorKind::MysqlError)?; + Ok(()) + } +} diff --git a/src/plugins/tell/mod.rs b/src/plugins/tell/mod.rs new file mode 100644 index 0000000..bdfb55c --- /dev/null +++ b/src/plugins/tell/mod.rs @@ -0,0 +1,264 @@ +use irc::client::prelude::*; + +use std::time::Duration; +use std::sync::Mutex; + +use time; +use chrono::NaiveDateTime; +use humantime::format_duration; + +use plugin::*; + +use failure::Fail; +use failure::ResultExt; +use error::ErrorKind as FrippyErrorKind; +use error::FrippyError; +use self::error::*; + +pub mod database; +use self::database::Database; + +macro_rules! try_lock { + ( $m:expr ) => { + match $m.lock() { + Ok(guard) => guard, + Err(poisoned) => poisoned.into_inner(), + } + } +} + +#[derive(PluginName, Default)] +pub struct Tell<T: Database> { + tells: Mutex<T>, +} + +impl<T: Database> Tell<T> { + pub fn new(db: T) -> Tell<T> { + Tell { + tells: Mutex::new(db), + } + } + + fn tell_command( + &self, + client: &IrcClient, + command: PluginCommand, + ) -> Result<String, TellError> { + if command.tokens.len() < 2 { + return Ok(self.invalid_command(client)); + } + + let receiver = &command.tokens[0]; + let sender = command.source; + + if receiver.eq_ignore_ascii_case(client.current_nickname()) { + return Ok(String::from("I am right here!")); + } + + if receiver.eq_ignore_ascii_case(&sender) { + return Ok(String::from("That's your name!")); + } + + if let Some(channels) = client.list_channels() { + for channel in channels { + if let Some(users) = client.list_users(&channel) { + if users + .iter() + .any(|u| u.get_nickname().eq_ignore_ascii_case(&receiver)) + { + return Ok(format!("{} is currently online.", receiver)); + } + } + } + } + + let tm = time::now().to_timespec(); + let message = command.tokens[1..].join(" "); + let tell = database::NewTellMessage { + sender: &sender, + receiver: &receiver.to_lowercase(), + time: NaiveDateTime::from_timestamp(tm.sec, 0u32), + message: &message, + }; + + try_lock!(self.tells).insert_tell(&tell)?; + + Ok(String::from("Got it!")) + } + + fn on_namelist( + &self, + client: &IrcClient, + channel: &str, + ) -> Result<(), FrippyError> { + let receivers = try_lock!(self.tells) + .get_receivers() + .context(FrippyErrorKind::Tell)?; + + if let Some(users) = client.list_users(channel) { + debug!("Outstanding tells for {:?}", receivers); + + for receiver in users + .iter() + .map(|u| u.get_nickname()) + .filter(|u| receivers.iter().any(|r| r == &u.to_lowercase())) + { + self.send_tells(client, receiver)?; + } + + Ok(()) + } else { + Ok(()) + } + } + fn send_tells(&self, client: &IrcClient, receiver: &str) -> Result<(), FrippyError> { + if client.current_nickname() == receiver { + return Ok(()); + } + + let mut tells = try_lock!(self.tells); + + let tell_messages = match tells.get_tells(&receiver.to_lowercase()) { + Ok(t) => t, + Err(e) => { + // This warning only occurs if frippy is built without a database + #[allow(unreachable_patterns)] + return match e.kind() { + ErrorKind::NotFound => Ok(()), + _ => Err(e.context(FrippyErrorKind::Tell))?, + }; + } + }; + + for tell in tell_messages { + let now = Duration::new(time::now().to_timespec().sec as u64, 0); + let dur = now - Duration::new(tell.time.timestamp() as u64, 0); + let human_dur = format_duration(dur); + + client + .send_notice( + receiver, + &format!( + "Tell from {} {} ago: {}", + tell.sender, human_dur, tell.message + ), + ) + .context(FrippyErrorKind::Connection)?; + + debug!( + "Sent {:?} from {:?} to {:?}", + tell.message, tell.sender, receiver + ); + } + + tells + .delete_tells(&receiver.to_lowercase()) + .context(FrippyErrorKind::Tell)?; + + Ok(()) + } + + fn invalid_command(&self, client: &IrcClient) -> String { + format!( + "Incorrect Command. \ + Send \"{} tell help\" for help.", + client.current_nickname() + ) + } + + fn help(&self, client: &IrcClient) -> String { + format!( + "usage: {} tell user message\r\n\ + example: {0} tell Foobar Hello!", + client.current_nickname() + ) + } +} + +impl<T: Database> Plugin for Tell<T> { + fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus { + let res = match message.command { + Command::JOIN(_, _, _) => self.send_tells(client, message.source_nickname().unwrap()), + Command::NICK(ref nick) => self.send_tells(client, nick), + Command::Response(resp, ref chan_info, _) => { + if resp == Response::RPL_NAMREPLY { + debug!("NAMREPLY info: {:?}", chan_info); + + self.on_namelist( + client, + &chan_info[chan_info.len() - 1], + ) + } else { + Ok(()) + } + } + _ => Ok(()), + }; + + match res { + Ok(_) => ExecutionStatus::Done, + Err(e) => ExecutionStatus::Err(e), + } + } + + fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> { + panic!("Tell should not use threading") + } + + fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> { + if command.tokens.is_empty() { + return Ok(client + .send_notice(&command.source, &self.invalid_command(client)) + .context(FrippyErrorKind::Connection)?); + } + + let sender = command.source.to_owned(); + + Ok(match command.tokens[0].as_ref() { + "help" => client + .send_notice(&command.source, &self.help(client)) + .context(FrippyErrorKind::Connection) + .into(), + _ => match self.tell_command(client, command) { + Ok(msg) => client + .send_notice(&sender, &msg) + .context(FrippyErrorKind::Connection), + Err(e) => client + .send_notice(&sender, &e.to_string()) + .context(FrippyErrorKind::Connection) + .into(), + }, + }?) + } + + fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> { + Err(String::from("This Plugin does not implement any commands.")) + } +} + +use std::fmt; +impl<T: Database> fmt::Debug for Tell<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Tell {{ ... }}") + } +} + +pub mod error { + #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)] + #[error = "TellError"] + pub enum ErrorKind { + /// Not found command error + #[fail(display = "Tell was not found")] + NotFound, + + /// MySQL error + #[cfg(feature = "mysql")] + #[fail(display = "Failed to execute MySQL Query")] + MysqlError, + + /// No connection error + #[cfg(feature = "mysql")] + #[fail(display = "No connection to the database")] + NoConnection, + } +} diff --git a/src/plugins/url.rs b/src/plugins/url.rs new file mode 100644 index 0000000..bff840f --- /dev/null +++ b/src/plugins/url.rs @@ -0,0 +1,130 @@ +extern crate htmlescape; +extern crate regex; + +use irc::client::prelude::*; + +use self::regex::Regex; + +use plugin::*; +use utils; + +use self::error::*; +use error::FrippyError; +use error::ErrorKind as FrippyErrorKind; +use failure::Fail; +use failure::ResultExt; + +lazy_static! { + static ref RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap(); +} + +#[derive(PluginName, Debug)] +pub struct Url { + max_kib: usize, +} + +impl Url { + /// If a file is larger than `max_kib` KiB the download is stopped + pub fn new(max_kib: usize) -> Url { + Url { max_kib: max_kib } + } + + fn grep_url(&self, msg: &str) -> Option<String> { + let captures = RE.captures(msg)?; + debug!("Url captures: {:?}", captures); + + Some(captures.get(2)?.as_str().to_owned()) + } + + fn get_title<'a>(&self, body: &str) -> Result<String, UrlError> { + let title = body.find("<title") + .map(|tag| { + body[tag..] + .find('>') + .map(|offset| tag + offset + 1) + .map(|start| { + body[start..] + .find("</title>") + .map(|offset| start + offset) + .map(|end| &body[start..end]) + }) + }) + .and_then(|s| s.and_then(|s| s)) + .ok_or(ErrorKind::MissingTitle)?; + + debug!("Title: {:?}", title); + + htmlescape::decode_html(title).map_err(|_| ErrorKind::HtmlDecoding.into()) + } + + fn url(&self, text: &str) -> Result<String, UrlError> { + let url = self.grep_url(text).ok_or(ErrorKind::MissingUrl)?; + let body = utils::download(&url, Some(self.max_kib)).context(ErrorKind::Download)?; + + let title = self.get_title(&body)?; + + Ok(title.replace('\n', "|").replace('\r', "|")) + } +} + +impl Plugin for Url { + fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus { + match message.command { + Command::PRIVMSG(_, ref msg) => if RE.is_match(msg) { + ExecutionStatus::RequiresThread + } else { + ExecutionStatus::Done + }, + _ => ExecutionStatus::Done, + } + } + + fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> { + Ok(match message.command { + Command::PRIVMSG(_, ref content) => match self.url(content) { + Ok(title) => client + .send_privmsg(message.response_target().unwrap(), &title) + .context(FrippyErrorKind::Connection)?, + Err(e) => Err(e).context(FrippyErrorKind::Url)?, + }, + _ => (), + }) + } + + fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> { + Ok(client + .send_notice( + &command.source, + "This Plugin does not implement any commands.", + ) + .context(FrippyErrorKind::Connection)?) + } + + fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> { + self.url(&command.tokens[0]) + .map_err(|e| e.cause().unwrap().to_string()) + } +} + +pub mod error { + /// A URL plugin error + #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)] + #[error = "UrlError"] + pub enum ErrorKind { + /// A download error + #[fail(display = "A download error occured")] + Download, + + /// Missing URL error + #[fail(display = "No URL was found")] + MissingUrl, + + /// Missing title error + #[fail(display = "No title was found")] + MissingTitle, + + /// Html decoding error + #[fail(display = "Failed to decode Html characters")] + HtmlDecoding, + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..06156be --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,65 @@ +use std::str; +use std::io::{self, Read}; + +use reqwest::Client; +use reqwest::header::Connection; + +use failure::ResultExt; +use self::error::{DownloadError, ErrorKind}; + +/// Downloads the file and converts it to a String. +/// Any invalid bytes are converted to a replacement character. +/// +/// The error indicated either a failed download or that the DownloadLimit was reached +pub fn download(url: &str, max_kib: Option<usize>) -> Result<String, DownloadError> { + let mut response = Client::new() + .get(url) + .header(Connection::close()) + .send() + .context(ErrorKind::Connection)?; + + // 100 kibibyte buffer + let mut buf = [0; 100 * 1024]; + let mut written = 0; + let mut bytes = Vec::new(); + + // Read until we reach EOF or max_kib KiB + loop { + let len = match response.read(&mut buf) { + Ok(0) => break, + Ok(len) => len, + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue, + Err(e) => Err(e).context(ErrorKind::Read)?, + }; + + bytes.extend_from_slice(&buf); + written += len; + + // Check if the file is too large to download + if let Some(max_kib) = max_kib { + if written > max_kib * 1024 { + Err(ErrorKind::DownloadLimit)?; + } + } + } + + Ok(String::from_utf8_lossy(&bytes).into_owned()) +} + +pub mod error { + #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)] + #[error = "DownloadError"] + pub enum ErrorKind { + /// Connection Error + #[fail(display = "A connection error has occured")] + Connection, + + /// Read Error + #[fail(display = "A read error has occured")] + Read, + + /// Reached download limit error + #[fail(display = "Reached download limit")] + DownloadLimit, + } +} |
