aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1831
-rw-r--r--Cargo.toml50
-rw-r--r--LICENSE2
-rw-r--r--README.md9
-rw-r--r--configs/config.toml3
-rw-r--r--frippy_derive/Cargo.toml2
-rw-r--r--frippy_derive/src/lib.rs1
-rw-r--r--log.yml15
-rw-r--r--migrations/2018-05-13-150818_create_events/down.sql1
-rw-r--r--migrations/2018-05-13-150818_create_events/up.sql8
-rw-r--r--migrations/2018-09-19-231843_create_quotes/down.sql1
-rw-r--r--migrations/2018-09-19-231843_create_quotes/up.sql9
-rw-r--r--src/error.rs23
-rw-r--r--src/lib.rs169
-rw-r--r--src/main.rs108
-rw-r--r--src/plugin.rs49
-rw-r--r--src/plugins/currency.rs166
-rw-r--r--src/plugins/emoji.rs134
-rw-r--r--src/plugins/factoid/database.rs (renamed from src/plugins/factoids/database.rs)52
-rw-r--r--src/plugins/factoid/mod.rs (renamed from src/plugins/factoids/mod.rs)196
-rw-r--r--src/plugins/factoid/sandbox.lua (renamed from src/plugins/factoids/sandbox.lua)42
-rw-r--r--src/plugins/factoid/utils.rs82
-rw-r--r--src/plugins/factoids/utils.rs25
-rw-r--r--src/plugins/help.rs41
-rw-r--r--src/plugins/keepnick.rs36
-rw-r--r--src/plugins/mod.rs12
-rw-r--r--src/plugins/quote/database.rs142
-rw-r--r--src/plugins/quote/mod.rs278
-rw-r--r--src/plugins/remind/database.rs236
-rw-r--r--src/plugins/remind/mod.rs337
-rw-r--r--src/plugins/remind/parser.rs251
-rw-r--r--src/plugins/sed.rs193
-rw-r--r--src/plugins/tell/database.rs15
-rw-r--r--src/plugins/tell/mod.rs222
-rw-r--r--src/plugins/unicode.rs98
-rw-r--r--src/plugins/url.rs199
-rw-r--r--src/utils.rs119
37 files changed, 3692 insertions, 1465 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2b6a8fa..02a1db2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,14 +1,24 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
[[package]]
name = "adler32"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "aho-corasick"
-version = "0.6.4"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -17,33 +27,51 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "arc-swap"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "arrayvec"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "autocfg"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "backtrace"
-version = "0.3.5"
+version = "0.3.15"
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)",
- "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)",
+ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
-version = "0.1.16"
+version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base64"
-version = "0.9.0"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -53,201 +81,250 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
-version = "1.0.1"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bufstream"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "build_const"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
-version = "1.2.1"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
-version = "0.4.6"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cargo_metadata"
-version = "0.2.3"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cc"
-version = "1.0.4"
+version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
-version = "0.1.2"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
-version = "0.4.0"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "circular-queue"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "clippy"
-version = "0.0.186"
+version = "0.0.212"
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.186 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clippy_lints 0.0.212 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clippy_lints"
-version = "0.0.186"
+version = "0.0.212"
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 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)",
+ "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pulldown-cmark 0.1.2 (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.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.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.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "core-foundation"
-version = "0.2.3"
+name = "cloudabi"
+version = "0.0.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.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "core-foundation-sys"
-version = "0.2.3"
+name = "cookie"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "cookie_store"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "crc"
-version = "1.7.0"
+version = "1.8.1"
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)",
+ "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "derive-error-chain"
-version = "0.10.1"
+name = "crc32fast"
+version = "1.2.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)",
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "derive-error-chain"
-version = "0.11.0"
+name = "crossbeam-deque"
+version = "0.7.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)",
+ "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "diesel"
-version = "1.1.1"
+name = "crossbeam-epoch"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "diesel_derives"
-version = "1.1.0"
+name = "crossbeam-queue"
+version = "0.1.2"
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)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "diesel_infer_schema"
-version = "1.1.0"
+name = "crossbeam-utils"
+version = "0.6.5"
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)",
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "diesel_migrations"
-version = "1.1.0"
+name = "diesel"
+version = "1.4.2"
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)",
+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mysqlclient-sys 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "dotenv"
-version = "0.10.1"
+name = "diesel_derives"
+version = "1.4.0"
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)",
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "dotenv"
-version = "0.11.0"
+name = "diesel_migrations"
+version = "1.4.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)",
+ "migrations_internals 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "migrations_macros 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dtoa"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "either"
-version = "1.4.0"
+version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -309,45 +386,65 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "encoding_rs"
-version = "0.7.2"
+version = "0.8.17"
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)",
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error-chain"
-version = "0.10.0"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "error-chain"
-version = "0.11.0"
+version = "0.12.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)",
+ "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
-version = "0.1.1"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
-version = "0.1.1"
+version = "0.1.5"
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)",
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "flate2"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -362,30 +459,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "frippy"
-version = "0.3.1"
+version = "0.4.0"
dependencies = [
- "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)",
+ "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "circular-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clippy 0.0.212 (registry+https://github.com/rust-lang/crates.io-index)",
+ "diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "diesel_migrations 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.5 (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)",
"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)",
+ "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "irc 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "r2d2 0.8.4 (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)",
+ "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "reqwest 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rlua 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (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)",
]
@@ -393,17 +492,22 @@ dependencies = [
name = "frippy_derive"
version = "0.1.0"
dependencies = [
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.5 (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)",
+ "syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "fuchsia-cprng"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -414,7 +518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures"
-version = "0.1.18"
+version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -422,19 +526,17 @@ name = "futures-cpupool"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.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.17"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "glob"
@@ -442,138 +544,153 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "h2"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (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 = "http"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "httparse"
-version = "1.2.4"
+version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "humantime"
-version = "1.1.0"
+version = "1.2.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)",
+ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hyper"
-version = "0.11.19"
+version = "0.12.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (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)",
+ "h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "httparse 1.3.3 (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.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.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.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hyper-tls"
-version = "0.1.2"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper 0.12.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "idna"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[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"
+version = "0.1.3"
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"
+name = "indexmap"
+version = "1.0.2"
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.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (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.13.4"
+version = "0.13.6"
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.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding 0.2.33 (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)",
+ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
-version = "0.6.5"
+version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
-version = "0.3.4"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -586,239 +703,318 @@ dependencies = [
]
[[package]]
-name = "language-tags"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "lazy_static"
-version = "0.2.11"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "lazy_static"
-version = "1.0.0"
+name = "lazycell"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "lazycell"
-version = "0.6.0"
+name = "libc"
+version = "0.2.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "libc"
-version = "0.2.36"
+name = "linked-hash-map"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "libflate"
-version = "0.1.14"
+name = "lock_api"
+version = "0.1.5"
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.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
-version = "0.3.9"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "log"
-version = "0.4.1"
+name = "log-mdc"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "log4rs"
+version = "0.8.3"
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)",
+ "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "matches"
-version = "0.1.6"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
-version = "2.0.1"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "memoffset"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
-]
[[package]]
name = "migrations_internals"
-version = "1.1.0"
+version = "1.4.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)",
+ "diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "migrations_macros"
-version = "1.1.0"
+version = "1.4.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_internals 1.4.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 = "mime"
-version = "0.3.5"
+version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicase 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mime_guess"
-version = "2.0.0-alpha.4"
+version = "2.0.0-alpha.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "miniz-sys"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "miniz_oxide_c_api"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "mio"
-version = "0.6.13"
+version = "0.6.16"
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)",
"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.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)",
+ "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (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)",
+ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.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 = "mio-uds"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "miow"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (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 = "mysqlclient-sys"
-version = "0.2.3"
+version = "0.2.4"
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)",
+ "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "native-tls"
-version = "0.1.5"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "net2"
-version = "0.2.31"
+version = "0.2.33"
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.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)",
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "num"
-version = "0.1.42"
+name = "nodrop"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "num-integer"
+version = "0.1.39"
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-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)",
+ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "num-integer"
-version = "0.1.36"
+name = "num-traits"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "num_cpus"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "num-iter"
-version = "0.1.35"
+name = "openssl"
+version = "0.10.20"
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)",
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.7 (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.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "num-traits"
-version = "0.1.43"
+name = "openssl-probe"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "num-traits"
-version = "0.2.0"
+name = "ordered-float"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
-name = "num_cpus"
-version = "1.8.0"
+name = "owning_ref"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "openssl"
-version = "0.9.24"
+name = "parking_lot"
+version = "0.7.1"
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.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)",
+ "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "openssl-sys"
-version = "0.9.26"
+name = "parking_lot_core"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -828,42 +1024,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "phf"
-version = "0.7.21"
+version = "0.7.24"
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)",
+ "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "phf_codegen"
-version = "0.7.21"
+version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "phf_generator"
-version = "0.7.21"
+version = "0.7.24"
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.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "phf_shared"
-version = "0.7.21"
+version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pkg-config"
-version = "0.3.9"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -875,17 +1071,37 @@ dependencies = [
]
[[package]]
+name = "proc-macro2"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "publicsuffix"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "pulldown-cmark"
-version = "0.0.15"
+version = "0.1.2"
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.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quick-error"
-version = "1.2.1"
+version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -907,12 +1123,20 @@ dependencies = [
]
[[package]]
+name = "quote"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "r2d2"
-version = "0.8.2"
+version = "0.8.4"
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)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.7.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)",
]
@@ -921,120 +1145,226 @@ 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)",
+ "diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "r2d2 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
-version = "0.3.22"
+version = "0.5.6"
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)",
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
-version = "0.4.2"
+version = "0.6.5"
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)",
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "redox_syscall"
-version = "0.1.37"
+name = "rand_chacha"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
-name = "regex"
-version = "0.2.6"
+name = "rand_core"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "regex-syntax"
-version = "0.4.2"
+name = "rand_core"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "relay"
+name = "rand_hc"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_isaac"
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)",
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "remove_dir_all"
-version = "0.3.0"
+name = "rand_jitter"
+version = "0.1.3"
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)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "reqwest"
-version = "0.8.5"
+name = "rand_os"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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.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.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)",
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rdrand"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "regex"
+version = "1.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.9.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cookie_store 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper 0.12.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rlua"
-version = "0.12.2"
+version = "0.14.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)",
+ "cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
-version = "0.1.6"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "safemem"
-version = "0.2.0"
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ryu"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "schannel"
-version = "0.1.10"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1047,35 +1377,40 @@ dependencies = [
[[package]]
name = "scoped-tls"
-version = "0.1.0"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "scopeguard"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "security-framework"
-version = "0.1.16"
+version = "0.3.1"
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.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)",
+ "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "security-framework-sys"
-version = "0.1.16"
+version = "0.3.1"
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.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
-version = "0.6.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1085,53 +1420,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
-version = "1.0.27"
+version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "serde_derive"
-version = "1.0.27"
+name = "serde-value"
+version = "0.5.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)",
- "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)",
+ "ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "serde_derive_internals"
-version = "0.19.0"
+name = "serde_derive"
+version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
-version = "1.0.9"
+version = "1.0.39"
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.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_urlencoded"
-version = "0.5.1"
+version = "0.5.5"
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.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_yaml"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+ "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "siphasher"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1141,12 +1486,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
-version = "0.4.0"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smallvec"
-version = "0.2.1"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "string"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1161,7 +1516,7 @@ dependencies = [
[[package]]
name = "syn"
-version = "0.12.13"
+version = "0.12.15"
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)",
@@ -1170,6 +1525,16 @@ dependencies = [
]
[[package]]
+name = "syn"
+version = "0.15.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (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"
@@ -1179,69 +1544,144 @@ dependencies = [
[[package]]
name = "synstructure"
-version = "0.6.1"
+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)",
+ "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.33 (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 = "take"
-version = "0.1.0"
+name = "tempfile"
+version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
-name = "tempdir"
-version = "0.3.6"
+name = "thread-id"
+version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
-version = "0.3.5"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
-version = "0.1.39"
+version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-codec"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-core"
-version = "0.1.12"
+version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (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.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-current-thread"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-executor"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-fs"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-io"
-version = "0.1.5"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1249,33 +1689,64 @@ name = "tokio-mockstream"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "tokio-proto"
-version = "0.1.1"
+name = "tokio-reactor"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "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.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.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)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "tokio-service"
-version = "0.1.0"
+name = "tokio-sync"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-tcp"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-threadpool"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1283,43 +1754,123 @@ name = "tokio-timer"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (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-timer"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "tokio-tls"
-version = "0.1.4"
+version = "0.2.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)",
- "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)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-trace-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-udp"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-uds"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
-version = "0.4.5"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "traitobject"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "try-lock"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "try_from"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "typemap"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "ucd-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "unicase"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicase"
-version = "2.1.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1327,11 +1878,19 @@ name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-normalization"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1348,53 +1907,58 @@ 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#d97b80c3c35b9f1d04085409087ef113c94cde17"
+source = "git+https://github.com/Jokler/unicode_names?branch=update-to-latest-unicode#60c2fae478d8e920e6b6f5d00e442faf22aee2d8"
[[package]]
-name = "unreachable"
-version = "1.0.0"
+name = "unsafe-any"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "url"
-version = "1.7.0"
+version = "1.7.2"
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)",
+ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
-version = "1.0.0"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "uuid"
-version = "0.5.1"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vcpkg"
-version = "0.2.2"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
-version = "0.1.3"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "void"
-version = "1.0.2"
+name = "want"
+version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "winapi"
@@ -1403,7 +1967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
-version = "0.3.4"
+version = "0.3.7"
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)",
@@ -1434,38 +1998,54 @@ dependencies = [
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "yaml-rust"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[metadata]
-"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
-"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
+"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
+"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
+"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"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.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4"
+"checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841"
+"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
+"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
+"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
+"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
+"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"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.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.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.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.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.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
+"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
+"checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8"
+"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
+"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
+"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
+"checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0"
+"checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d"
+"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
+"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
+"checksum circular-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be63960d0419728d75f18d0132e5da310d2db6ef31db808a733a8566afe5545"
+"checksum clippy 0.0.212 (registry+https://github.com/rust-lang/crates.io-index)" = "7e253af13a0cc39c7f22cf16f1be49d593dedc5895fe2fbb15f14d66ead00533"
+"checksum clippy_lints 0.0.212 (registry+https://github.com/rust-lang/crates.io-index)" = "bd2326065405649672adbd5cb30dad2fad3a470935653d51c70591d47d3a8512"
+"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
+"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
+"checksum cookie_store 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b0d2f2ecb21dce00e2453268370312978af9b8024020c7a37ae2cc6dbbe64685"
+"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
+"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
+"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
+"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
+"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
+"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4"
+"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
+"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
+"checksum diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d24935ba50c4a8dc375a0fd1f8a2ba6bdbdc4125713126a74b965d6a01a06d7"
+"checksum diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62a27666098617d52c487a41f70de23d44a1dc1f3aa5877ceba2790fb1f1cab4"
+"checksum diesel_migrations 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3cde8413353dc7f5d72fa8ce0b99a560a359d2c5ef1e5817ca731cd9008f4c"
+"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
+"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
"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"
@@ -1473,135 +2053,182 @@ 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 encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
"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 error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
+"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
+"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
+"checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa"
+"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"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-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"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 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "62941eff9507c8177d448bd83a44d9b9760856e184081d8cd79ba9f03dd24981"
"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 getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
+"checksum h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "85ab6286db06040ddefb71641b50017c06874614001a134b423783e2db2920bd"
"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 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 http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a"
+"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
+"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
+"checksum hyper 0.12.28 (registry+https://github.com/rust-lang/crates.io-index)" = "e8e4606fed1c162e3a63d408c07584429f49a4f34c7176cb6cbee60e78f2372c"
+"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f"
+"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
+"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec"
+"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
"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 irc 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8eb7666c9ae95dc77b874467e347bde3789773b6f48887fb3384bfe29552b466"
+"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
+"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"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.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 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.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 lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
+"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
+"checksum libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)" = "ec350a9417dfd244dc9a6c4a71e13895a4db6b92f0b106f07ebbc3f3bc580cee"
+"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
+"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
+"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
+"checksum log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
+"checksum log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "100052474df98158c0738a7d3f4249c99978490178b5f9f68cd835ac57adbd1b"
+"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
+"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
+"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
+"checksum migrations_internals 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8089920229070f914b9ce9b07ef60e175b2b9bc2d35c3edd8bf4433604e863b9"
+"checksum migrations_macros 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1664412abf7db2b8a6d58be42a38b099780cc542b5b350383b805d88932833fe"
+"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425"
+"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed"
+"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649"
+"checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e"
+"checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab"
+"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
+"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
-"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.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 mysqlclient-sys 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7e9637d93448044078aaafea7419aed69d301b4a12bcc4aa0ae856eb169bef85"
+"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
+"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
+"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
+"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
+"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
+"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
+"checksum openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)" = "5a0d6b781aac4ac1bd6cafe2a2f0ad8c16ae8e1dd5184822a16c50139f8838d9"
+"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
+"checksum openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)" = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d"
+"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
+"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
+"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
+"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
"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 phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18"
+"checksum phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
+"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
+"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
+"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"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 proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)" = "64c827cea7a7ab30ce4593e5e04d7a11617ad6ece2fa230605a78b00ff965316"
+"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
+"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
+"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"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 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 quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
+"checksum r2d2 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9dd8a293251281a4d02848925fcdbbc9f466ddb4965981bb06680359b3d12091"
"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.10 (registry+https://github.com/rust-lang/crates.io-index)" = "acece75e0f987c48863a6c792ec8b7d6c4177d4a027f8ccc72f849794f437016"
+"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"
+"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
+"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
+"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
+"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
+"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
+"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
+"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
+"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
+"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
+"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
+"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
+"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
+"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
+"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
+"checksum reqwest 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "943b9f85622f53bcf71721e0996f23688e3942e51fc33766c2e24a959316767b"
+"checksum rlua 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7dea6f2338581160fa14f3b8b60df560b41c62214d1e557520f28f14b270ddf"
+"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
+"checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339"
"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 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.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
+"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28"
+"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
+"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
+"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"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 serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4"
+"checksum serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7a663f873dedc4eac1a559d4c6bc0d0b2c34dc5ac4702e105014b8281489e44f"
+"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79"
+"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
+"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
+"checksum serde_yaml 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0887a8e097a69559b56aa2526bf7aff7c3048cf627dff781f0b56a6001534593"
+"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"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 slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
+"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
+"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
+"checksum string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b639411d0b9c738748b5397d5ceba08e648f4f1992231aa859af1a017f31f60b"
"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 syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5"
+"checksum syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)" = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836"
"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.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 synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
+"checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a"
+"checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1"
+"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
+"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
+"checksum tokio 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "cec6c34409089be085de9403ba2010b80e36938c9ca992c4f67f407bb13db0b1"
+"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f"
+"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71"
+"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
+"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e"
+"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af"
+"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"
"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-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce"
+"checksum tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2f843ffdf8d6e1f90bddd48da43f99ab071660cd92b7ec560ef3cdfd7a409a"
+"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119"
+"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2"
"checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc"
-"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 tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6"
+"checksum tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c"
+"checksum tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "350c9edade9830dc185ae48ba45667a445ab59f6167ef6d0254ec9d2430d9dd3"
+"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92"
+"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445"
+"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
+"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
+"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
+"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
+"checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6"
+"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
-"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
+"checksum unicase 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41d17211f887da8e4a70a45b9536f26fc5de166b81e2d5d80de4a17fd22553bd"
"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-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
+"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"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.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 unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f"
+"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
+"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
+"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
+"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
+"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
+"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
"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 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"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"
+"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
diff --git a/Cargo.toml b/Cargo.toml
index c9aa9c5..3e5600e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "frippy"
-version = "0.4.0"
+version = "0.5.0"
authors = ["Jokler <jokler.contact@gmail.com>"]
repository = "https://github.com/Mavulp/frippy"
readme = "README.md"
@@ -16,48 +16,44 @@ doc = false
[features]
mysql = [
"diesel",
- "diesel_infer_schema",
"diesel_migrations",
- "dotenv",
"r2d2",
"r2d2-diesel"
]
[dependencies]
-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"
+irc = "0.13.6"
+log = "0.4.5"
+time = "0.1.40"
+humantime = "1.1.1"
+rlua = "0.14.2"
+reqwest = "0.9.0"
+regex = "1.0.5"
+lazy_static = "1.1.0"
+serde = "1.0.79"
+serde_json = "1.0.27"
+chrono = "0.4.6"
glob = "0.2.11"
-failure = "0.1.1"
+circular-queue = "0.2.0"
+failure = "0.1.2"
+htmlescape = "0.3.1"
+antidote = "1.0.0"
+log4rs = "0.8.0"
frippy_derive = { path = "frippy_derive" }
-htmlescape = "0.3.1"
+rand = "0.5.5"
[dependencies.unicode_names]
git = 'https://github.com/Jokler/unicode_names'
branch = 'update-to-latest-unicode'
-
[dependencies.diesel]
-version = "1.1.1"
+version = "1.3.3"
optional = true
features = ["mysql", "chrono"]
-[dependencies.diesel_infer_schema]
-version = "1.1.0"
-optional = true
-features = ["mysql"]
-
[dependencies.diesel_migrations]
-version = "1.1.0"
+version = "1.3.0"
optional = true
features = ["mysql"]
@@ -69,10 +65,6 @@ optional = true
version = "1.0.0"
optional = true
-[dependencies.dotenv]
-version = "0.11.0"
-optional = true
-
[dependencies.clippy]
-version = "*"
+version = "0.0.212"
optional = true
diff --git a/LICENSE b/LICENSE
index 3e00266..db8a690 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2017 Mavulp
+Copyright (c) 2018 Mavulp
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index f6e2ece..9b1e1b6 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,11 @@
# frippy [![Build Status](https://travis-ci.org/Mavulp/frippy.svg?branch=master)](https://travis-ci.org/Mavulp/frippy)
-Frippy is an IRC bot which is splits its functions into plugins.
+Frippy is an IRC bot which is splits its functionality into plugins.
Currently it has plugins to:
-* Send the names of emojis used
-* Convert currencies with the help of [fixer.io](https://fixer.io/)
-* Send the titles of HTML pages linked
+* Get unicode information about characters
+* Send the titles of HTML pages linked
* Create factoids with Lua support
-* Send messages to offline users when they join again
+* Store messages intended for offline users
* Automatically change nickname when it is available again
Check the config.toml file to get an idea of how to set the bot up.
diff --git a/configs/config.toml b/configs/config.toml
index 5a78444..655dcdf 100644
--- a/configs/config.toml
+++ b/configs/config.toml
@@ -12,7 +12,7 @@ encoding = "UTF-8"
channels = ["#frippy"]
umodes = "+B"
user_info = "IRC Bot"
-version = "frippy v0.4.0"
+version = "frippy v0.5.0"
source = "https://github.com/Mavulp/frippy"
#ping_time = 180
#ping_timeout = 10
@@ -25,6 +25,7 @@ source = "https://github.com/Mavulp/frippy"
#"#frippy" = ""
[options]
+#prefix = "."
#disabled_plugins = "Url"
# If no database url is set a HashMap is used
#mysql_url = "mysql://user:password@address/db"
diff --git a/frippy_derive/Cargo.toml b/frippy_derive/Cargo.toml
index b258f57..1f22957 100644
--- a/frippy_derive/Cargo.toml
+++ b/frippy_derive/Cargo.toml
@@ -9,4 +9,4 @@ proc-macro = true
[dependencies]
syn = "0.12.13"
quote = "0.4.2"
-failure = "0.1.1"
+failure = "0.1.2"
diff --git a/frippy_derive/src/lib.rs b/frippy_derive/src/lib.rs
index efa349a..dbf7de4 100644
--- a/frippy_derive/src/lib.rs
+++ b/frippy_derive/src/lib.rs
@@ -34,7 +34,6 @@ fn expand_plugin(ast: &syn::DeriveInput) -> quote::Tokens {
pub fn derive_error(data: TokenStream) -> TokenStream {
let ast = syn::parse(data).unwrap();
let tokens = expand_error(&ast);
- // panic!("{}", tokens.to_string());
tokens.into()
}
diff --git a/log.yml b/log.yml
new file mode 100644
index 0000000..f4794d8
--- /dev/null
+++ b/log.yml
@@ -0,0 +1,15 @@
+# Read https://docs.rs/log4rs/0.8.0/log4rs/file/index.html for more information on how to use this file
+refresh_rate: 5 minutes
+
+appenders:
+ stdout:
+ kind: console
+ encoder:
+ kind: pattern
+ pattern: "[{d:35}](({h({l})})) {t} - {m}{n}"
+
+loggers:
+ frippy:
+ level: info
+ appenders:
+ - stdout
diff --git a/migrations/2018-05-13-150818_create_events/down.sql b/migrations/2018-05-13-150818_create_events/down.sql
new file mode 100644
index 0000000..858bcc0
--- /dev/null
+++ b/migrations/2018-05-13-150818_create_events/down.sql
@@ -0,0 +1 @@
+DROP TABLE events
diff --git a/migrations/2018-05-13-150818_create_events/up.sql b/migrations/2018-05-13-150818_create_events/up.sql
new file mode 100644
index 0000000..4e6f14e
--- /dev/null
+++ b/migrations/2018-05-13-150818_create_events/up.sql
@@ -0,0 +1,8 @@
+CREATE TABLE events (
+ id SERIAL PRIMARY KEY,
+ receiver VARCHAR(32) NOT NULL,
+ content TEXT NOT NULL,
+ author VARCHAR(32) NOT NULL,
+ time TIMESTAMP NOT NULL,
+ `repeat` BIGINT UNSIGNED NULL
+)
diff --git a/migrations/2018-09-19-231843_create_quotes/down.sql b/migrations/2018-09-19-231843_create_quotes/down.sql
new file mode 100644
index 0000000..b9d0f8b
--- /dev/null
+++ b/migrations/2018-09-19-231843_create_quotes/down.sql
@@ -0,0 +1 @@
+DROP TABLE quotes
diff --git a/migrations/2018-09-19-231843_create_quotes/up.sql b/migrations/2018-09-19-231843_create_quotes/up.sql
new file mode 100644
index 0000000..357a63a
--- /dev/null
+++ b/migrations/2018-09-19-231843_create_quotes/up.sql
@@ -0,0 +1,9 @@
+CREATE TABLE quotes (
+ quotee VARCHAR(32) NOT NULL,
+ channel VARCHAR(32) NOT NULL,
+ idx INTEGER NOT NULL,
+ content TEXT NOT NULL,
+ author VARCHAR(32) NOT NULL,
+ created TIMESTAMP NOT NULL,
+ PRIMARY KEY (quotee, channel, idx)
+)
diff --git a/src/error.rs b/src/error.rs
index 36d5724..039b71d 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -2,8 +2,9 @@
use failure::Fail;
-pub fn log_error(e: FrippyError) {
- let text = e.causes()
+pub fn log_error(e: &FrippyError) {
+ let text = e
+ .causes()
.skip(1)
.fold(format!("{}", e), |acc, err| format!("{}: {}", acc, err));
error!("{}", text);
@@ -17,6 +18,10 @@ pub enum ErrorKind {
#[fail(display = "A connection error occured")]
Connection,
+ /// Thread spawn error
+ #[fail(display = "Failed to spawn thread")]
+ ThreadSpawn,
+
/// A Url error
#[fail(display = "A Url error has occured")]
Url,
@@ -25,7 +30,15 @@ pub enum ErrorKind {
#[fail(display = "A Tell error has occured")]
Tell,
- /// A Factoids error
- #[fail(display = "A Factoids error has occured")]
- Factoids,
+ /// A Factoid error
+ #[fail(display = "A Factoid error has occured")]
+ Factoid,
+
+ /// A Quote error
+ #[fail(display = "A Quote error has occured")]
+ Quote,
+
+ /// A Remind error
+ #[fail(display = "A Remind error has occured")]
+ Remind,
}
diff --git a/src/lib.rs b/src/lib.rs
index ebadb86..50e6688 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,11 +14,10 @@
//!
//! let config = Config::load("config.toml").unwrap();
//! let mut reactor = IrcReactor::new().unwrap();
-//! let mut bot = Bot::new();
+//! 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.add_plugin(plugins::unicode::Unicode::new());
//!
//! bot.connect(&mut reactor, &config).unwrap();
//! reactor.run().unwrap();
@@ -46,49 +45,72 @@ extern crate lazy_static;
#[macro_use]
extern crate log;
+extern crate antidote;
extern crate chrono;
+extern crate circular_queue;
extern crate humantime;
extern crate irc;
+extern crate rand;
+extern crate regex;
extern crate reqwest;
+extern crate serde_json;
extern crate time;
+pub mod error;
pub mod plugin;
pub mod plugins;
pub mod utils;
-pub mod error;
+
+use plugin::*;
+
+use error::*;
+use failure::ResultExt;
+
+pub use irc::client::data::Config;
+use irc::client::ext::ClientExt;
+use irc::client::reactor::IrcReactor;
+use irc::client::{Client, IrcClient};
+use irc::error::IrcError;
+use irc::proto::{command::Command, Message};
use std::collections::HashMap;
use std::fmt;
-use std::thread::spawn;
use std::sync::Arc;
+use std::thread;
-pub use irc::client::prelude::*;
-pub use irc::error::IrcError;
-use error::*;
-use failure::ResultExt;
+pub trait FrippyClient: Client + Send + Sync + Clone + fmt::Debug {
+ fn current_nickname(&self) -> &str;
+}
-use plugin::*;
+impl FrippyClient for IrcClient {
+ fn current_nickname(&self) -> &str {
+ self.current_nickname()
+ }
+}
/// The bot which contains the main logic.
-#[derive(Default)]
-pub struct Bot {
- plugins: ThreadedPlugins,
+pub struct Bot<'a> {
+ prefix: &'a str,
+ plugins: ThreadedPlugins<IrcClient>,
}
-impl Bot {
- /// Creates a `Bot`.
+impl<'a> Bot<'a> {
+ /// Creates a `Bot` without any plugins.
/// 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).
+ /// To send commands to a plugin
+ /// the message has to start with the plugin's name prefixed by `cmd_prefix`.
///
/// # Examples
/// ```
/// use frippy::Bot;
- /// let mut bot = Bot::new();
+ /// let mut bot = Bot::new(".");
/// ```
- pub fn new() -> Bot {
+ pub fn new(cmd_prefix: &'a str) -> Self {
Bot {
+ prefix: cmd_prefix,
plugins: ThreadedPlugins::new(),
}
}
@@ -100,10 +122,13 @@ impl Bot {
/// ```
/// use frippy::{plugins, Bot};
///
- /// let mut bot = frippy::Bot::new();
+ /// let mut bot = frippy::Bot::new(".");
/// bot.add_plugin(plugins::help::Help::new());
/// ```
- pub fn add_plugin<T: Plugin + 'static>(&mut self, plugin: T) {
+ pub fn add_plugin<T>(&mut self, plugin: T)
+ where
+ T: Plugin<Client = IrcClient> + 'static,
+ {
self.plugins.add(plugin);
}
@@ -115,7 +140,7 @@ impl Bot {
/// ```
/// use frippy::{plugins, Bot};
///
- /// let mut bot = frippy::Bot::new();
+ /// let mut bot = frippy::Bot::new(".");
/// bot.add_plugin(plugins::help::Help::new());
/// bot.remove_plugin("Help");
/// ```
@@ -142,7 +167,7 @@ impl Bot {
///
/// let config = Config::load("config.toml").unwrap();
/// let mut reactor = IrcReactor::new().unwrap();
- /// let mut bot = Bot::new();
+ /// let mut bot = Bot::new(".");
///
/// bot.connect(&mut reactor, &config).unwrap();
/// reactor.run().unwrap();
@@ -160,22 +185,27 @@ impl Bot {
client.identify().context(ErrorKind::Connection)?;
info!("Identified");
- // TODO Verify if we actually need to clone plugins twice
+ // TODO Verify if we actually need to clone twice
let plugins = self.plugins.clone();
+ let prefix = self.prefix.to_owned();
reactor.register_client_with_handler(client, move |client, message| {
- process_msg(client, plugins.clone(), message)
+ process_msg(client, plugins.clone(), &prefix.clone(), message)
});
Ok(())
}
}
-fn process_msg(
- client: &IrcClient,
- mut plugins: ThreadedPlugins,
+fn process_msg<C>(
+ client: &C,
+ mut plugins: ThreadedPlugins<C>,
+ prefix: &str,
message: Message,
-) -> Result<(), IrcError> {
+) -> Result<(), IrcError>
+where
+ C: FrippyClient + 'static,
+{
// Log any channels we join
if let Command::JOIN(ref channel, _, _) = message.command {
if message.source_nickname().unwrap() == client.current_nickname() {
@@ -184,7 +214,7 @@ fn process_msg(
}
// Check for possible command and save the result for later
- let command = PluginCommand::from(&client.current_nickname().to_lowercase(), &message);
+ let command = PluginCommand::try_from(prefix, &message);
plugins.execute_plugins(client, message);
@@ -198,19 +228,22 @@ fn process_msg(
Ok(())
}
-#[derive(Clone, Default, Debug)]
-struct ThreadedPlugins {
- plugins: HashMap<String, Arc<Plugin>>,
+#[derive(Clone, Debug)]
+struct ThreadedPlugins<C: FrippyClient> {
+ plugins: HashMap<String, Arc<Plugin<Client = C>>>,
}
-impl ThreadedPlugins {
- pub fn new() -> ThreadedPlugins {
+impl<C: FrippyClient + 'static> ThreadedPlugins<C> {
+ pub fn new() -> Self {
ThreadedPlugins {
plugins: HashMap::new(),
}
}
- pub fn add<T: Plugin + 'static>(&mut self, plugin: T) {
+ pub fn add<T>(&mut self, plugin: T)
+ where
+ T: Plugin<Client = C> + 'static,
+ {
let name = plugin.name().to_lowercase();
let safe_plugin = Arc::new(plugin);
@@ -221,14 +254,16 @@ impl ThreadedPlugins {
self.plugins.remove(&name.to_lowercase()).map(|_| ())
}
- pub fn execute_plugins(&mut self, client: &IrcClient, message: Message) {
+ /// Runs the execute functions on all plugins.
+ /// Any errors that occur are printed right away.
+ pub fn execute_plugins(&mut self, client: &C, 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::Err(e) => log_error(&e),
ExecutionStatus::RequiresThread => {
debug!(
"Spawning thread to execute {} with {}",
@@ -242,11 +277,19 @@ impl ThreadedPlugins {
let client = client.clone();
// Execute the plugin in another thread
- spawn(move || {
- if let Err(e) = plugin.execute_threaded(&client, &message) {
- log_error(e);
- };
- });
+ if let Err(e) = thread::Builder::new()
+ .name(name)
+ .spawn(move || {
+ if let Err(e) = plugin.execute_threaded(&client, &message) {
+ log_error(&e);
+ } else {
+ debug!("{} sent response from thread", plugin.name());
+ }
+ })
+ .context(ErrorKind::ThreadSpawn)
+ {
+ log_error(&e.into());
+ }
}
}
}
@@ -254,17 +297,10 @@ impl ThreadedPlugins {
pub fn handle_command(
&mut self,
- client: &IrcClient,
+ client: &C,
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
+ // Check if there is a plugin for this command
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);
@@ -274,31 +310,24 @@ impl ThreadedPlugins {
// 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)?)
+ thread::Builder::new()
+ .name(name)
+ .spawn(move || {
+ if let Err(e) = plugin.command(&client, command) {
+ log_error(&e);
+ };
+ })
+ .context(ErrorKind::ThreadSpawn)?;
}
+
+ Ok(())
}
}
-impl fmt::Display for ThreadedPlugins {
+impl<C: FrippyClient> fmt::Display for ThreadedPlugins<C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let plugin_names = self.plugins
+ let plugin_names = self
+ .plugins
.iter()
.map(|(_, p)| p.name().to_owned())
.collect::<Vec<String>>();
diff --git a/src/main.rs b/src/main.rs
index b9a4b8f..ef24e4d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,6 +4,7 @@
extern crate frippy;
extern crate glob;
extern crate irc;
+extern crate log4rs;
extern crate time;
#[cfg(feature = "mysql")]
@@ -21,80 +22,50 @@ extern crate failure;
#[macro_use]
extern crate log;
+use std::collections::HashMap;
#[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;
+use irc::client::reactor::IrcReactor;
-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::plugins::unicode::Unicode;
+use frippy::plugins::factoid::Factoid;
+use frippy::plugins::help::Help;
+use frippy::plugins::keepnick::KeepNick;
+use frippy::plugins::quote::Quote;
+use frippy::plugins::remind::Remind;
+use frippy::plugins::sed::Sed;
+use frippy::plugins::tell::Tell;
+use frippy::plugins::url::UrlTitles;
-use frippy::Config;
use failure::Error;
+use frippy::Config;
#[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 main() {
+ if let Err(e) = log4rs::init_file("log.yml", Default::default()) {
+ use log4rs::Error;
+ match e {
+ Error::Log(e) => eprintln!("Log4rs error: {}", e),
+ Error::Log4rs(e) => eprintln!("Failed to parse \"log.yml\" as log4rs config: {}", e),
}
- }
- fn flush(&self) {}
-}
-
-static LOGGER: Logger = Logger;
+ return;
+ }
-fn main() {
// Print any errors that caused frippy to shut down
if let Err(e) = run() {
- let text = e.causes()
- .skip(1)
+ let text = e
+ .iter_causes()
.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() {
@@ -120,21 +91,24 @@ fn run() -> Result<(), Error> {
// Open a connection and add work for each config
for config in configs {
+ let mut prefix = None;
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<_>>());
}
+ prefix = options.get("prefix");
mysql_url = options.get("mysql_url");
}
+ let prefix = prefix.cloned().unwrap_or_else(|| String::from("."));
- let mut bot = frippy::Bot::new();
+ let mut bot = frippy::Bot::new(&prefix);
bot.add_plugin(Help::new());
- bot.add_plugin(Url::new(1024));
- bot.add_plugin(Emoji::new());
- bot.add_plugin(Currency::new());
+ bot.add_plugin(UrlTitles::new(1024));
+ bot.add_plugin(Sed::new(60));
+ bot.add_plugin(Unicode::new());
bot.add_plugin(KeepNick::new());
#[cfg(feature = "mysql")]
@@ -149,21 +123,27 @@ fn run() -> Result<(), Error> {
Ok(pool) => match embedded_migrations::run(&*pool.get()?) {
Ok(_) => {
let pool = Arc::new(pool);
- bot.add_plugin(Factoids::new(pool.clone()));
+ bot.add_plugin(Factoid::new(pool.clone()));
+ bot.add_plugin(Quote::new(pool.clone()));
bot.add_plugin(Tell::new(pool.clone()));
+ bot.add_plugin(Remind::new(pool.clone()));
info!("Connected to MySQL server")
}
Err(e) => {
- bot.add_plugin(Factoids::new(HashMap::new()));
+ bot.add_plugin(Factoid::new(HashMap::new()));
+ bot.add_plugin(Quote::new(HashMap::new()));
bot.add_plugin(Tell::new(HashMap::new()));
+ bot.add_plugin(Remind::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(Factoid::new(HashMap::new()));
+ bot.add_plugin(Quote::new(HashMap::new()));
bot.add_plugin(Tell::new(HashMap::new()));
+ bot.add_plugin(Remind::new(HashMap::new()));
}
}
#[cfg(not(feature = "mysql"))]
@@ -171,8 +151,10 @@ fn run() -> Result<(), Error> {
if mysql_url.is_some() {
error!("frippy was not built with the mysql feature")
}
- bot.add_plugin(Factoids::new(HashMap::new()));
+ bot.add_plugin(Factoid::new(HashMap::new()));
+ bot.add_plugin(Quote::new(HashMap::new()));
bot.add_plugin(Tell::new(HashMap::new()));
+ bot.add_plugin(Remind::new(HashMap::new()));
}
if let Some(disabled_plugins) = disabled_plugins {
@@ -187,5 +169,7 @@ fn run() -> Result<(), Error> {
}
// Run the bots until they throw an error - an error could be loss of connection
- Ok(reactor.run()?)
+ reactor.run()?;
+
+ Ok(())
}
diff --git a/src/plugin.rs b/src/plugin.rs
index bc428d5..65bfe1f 100644
--- a/src/plugin.rs
+++ b/src/plugin.rs
@@ -1,8 +1,8 @@
//! Definitions required for every `Plugin`
use std::fmt;
-use irc::client::prelude::*;
use error::FrippyError;
+use irc::client::prelude::*;
/// 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.
@@ -20,17 +20,19 @@ pub enum ExecutionStatus {
/// `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 {
+ type Client;
/// 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;
+ fn execute(&self, client: &Self::Client, message: &Message) -> ExecutionStatus;
/// Handles messages which are not commands in a new thread.
- fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError>;
+ fn execute_threaded(&self, client: &Self::Client, message: &Message)
+ -> Result<(), FrippyError>;
/// Handles any command directed at this plugin.
- fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError>;
+ fn command(&self, client: &Self::Client, 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>;
+ fn evaluate(&self, client: &Self::Client, command: PluginCommand) -> Result<String, String>;
}
/// `PluginName` is required by [`Plugin`](trait.Plugin.html).
@@ -66,35 +68,24 @@ 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> {
+ pub fn try_from(prefix: &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
+ // Split content by spaces
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();
- if !tokens[0].is_empty() {
- return None;
- }
-
- // The first token contained the name of the bot
- tokens.remove(0);
-
- Some(PluginCommand {
- source: message.source_nickname().unwrap().to_string(),
- target: message.response_target().unwrap().to_string(),
- tokens: tokens,
- })
- } else {
- None
+ // Commands start with a prefix
+ if !tokens[0].to_lowercase().starts_with(prefix) {
+ return None;
}
+ // Remove the prefix from the first token
+ tokens[0].drain(..prefix.len());
+
+ Some(PluginCommand {
+ source: message.source_nickname().unwrap().to_string(),
+ target: message.response_target().unwrap().to_string(),
+ tokens,
+ })
} else {
None
}
diff --git a/src/plugins/currency.rs b/src/plugins/currency.rs
deleted file mode 100644
index 53a245c..0000000
--- a/src/plugins/currency.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-extern crate reqwest;
-extern crate serde;
-extern crate serde_json;
-
-use std::io::Read;
-use std::num::ParseFloatError;
-
-use irc::client::prelude::*;
-
-use self::reqwest::Client;
-use self::reqwest::header::Connection;
-use self::serde_json::Value;
-
-use plugin::*;
-
-use error::FrippyError;
-use error::ErrorKind as FrippyErrorKind;
-use failure::ResultExt;
-
-#[derive(PluginName, Default, Debug)]
-pub struct Currency;
-
-struct ConvertionRequest<'a> {
- value: f64,
- source: &'a str,
- target: &'a str,
-}
-
-impl<'a> ConvertionRequest<'a> {
- fn send(&self) -> Option<f64> {
- let response = Client::new()
- .get("https://api.fixer.io/latest")
- .form(&[("base", self.source)])
- .header(Connection::close())
- .send();
-
- match response {
- Ok(mut response) => {
- let mut body = String::new();
- 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 = convertion_rates.get("rates")?;
- let target_rate: &Value = rates.get(self.target.to_uppercase())?;
- Some(self.value * target_rate.as_f64()?)
- }
- Err(_) => None,
- }
- }
- Err(_) => None,
- }
- }
-}
-
-impl Currency {
- pub fn new() -> Currency {
- Currency {}
- }
-
- fn eval_command<'a>(
- &self,
- tokens: &'a [String],
- ) -> Result<ConvertionRequest<'a>, ParseFloatError> {
- Ok(ConvertionRequest {
- value: tokens[0].parse()?,
- source: &tokens[1],
- target: &tokens[2],
- })
- }
-
- fn convert(&self, client: &IrcClient, command: &mut PluginCommand) -> Result<String, String> {
- if command.tokens.len() < 3 {
- return Err(self.invalid_command(client));
- }
-
- let request = match self.eval_command(&command.tokens) {
- Ok(request) => request,
- Err(_) => {
- 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()
- );
-
- Ok(response)
- }
- None => Err(String::from(
- "An error occured during the conversion of the given currency",
- )),
- }
- }
-
- 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, client: &IrcClient) -> String {
- format!(
- "Incorrect Command. \
- Send \"{} currency help\" for help.",
- client.current_nickname()
- )
- }
-}
-
-impl Plugin for Currency {
- fn execute(&self, _: &IrcClient, _: &Message) -> ExecutionStatus {
- ExecutionStatus::Done
- }
-
- fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
- panic!("Currency does not implement the execute function!")
- }
-
- 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 Err(self.invalid_command(client));
- }
-
- match command.tokens[0].as_ref() {
- "help" => Ok(self.help(client)),
- _ => self.convert(client, &mut command),
- }
- }
-}
diff --git a/src/plugins/emoji.rs b/src/plugins/emoji.rs
deleted file mode 100644
index f1d9376..0000000
--- a/src/plugins/emoji.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-extern crate unicode_names;
-
-use std::fmt;
-
-use irc::client::prelude::*;
-
-use plugin::*;
-
-use error::FrippyError;
-use error::ErrorKind as FrippyErrorKind;
-use failure::Fail;
-use failure::ResultExt;
-
-struct EmojiHandle {
- symbol: char,
- count: i32,
-}
-
-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"),
- };
-
- if self.count > 1 {
- write!(f, "{}x {}", self.count, name)
- } else {
- write!(f, "{}", name)
- }
- }
-}
-
-#[derive(PluginName, Default, Debug)]
-pub struct Emoji;
-
-impl Emoji {
- pub fn new() -> Emoji {
- Emoji {}
- }
-
- fn emoji(&self, content: &str) -> String {
- self.return_emojis(content)
- .iter()
- .map(|e| e.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- }
-
- fn return_emojis(&self, string: &str) -> Vec<EmojiHandle> {
- let mut emojis: Vec<EmojiHandle> = Vec::new();
-
- let mut current = EmojiHandle {
- symbol: ' ',
- count: 0,
- };
-
- for c in string.chars() {
- if !self.is_emoji(&c) {
- continue;
- }
-
- if current.symbol == c {
- current.count += 1;
- } else {
- if current.count > 0 {
- emojis.push(current);
- }
-
- current = EmojiHandle {
- symbol: c,
- count: 1,
- }
- }
- }
-
- if current.count > 0 {
- emojis.push(current);
- }
-
- emojis
- }
-
- fn is_emoji(&self, c: &char) -> bool {
- // Emoji ranges from stackoverflow:
- // https://stackoverflow.com/questions/30757193/find-out-if-character-in-string-is-emoji
- match *c { '\u{1F600}'...'\u{1F64F}' // Emoticons
- | '\u{1F300}'...'\u{1F5FF}' // Misc Symbols and Pictographs
- | '\u{1F680}'...'\u{1F6FF}' // Transport and Map
- | '\u{2600}' ...'\u{26FF}' // Misc symbols
- | '\u{2700}' ...'\u{27BF}' // Dingbats
- | '\u{FE00}' ...'\u{FE0F}' // Variation Selectors
- | '\u{1F900}'...'\u{1F9FF}' // Supplemental Symbols and Pictographs
- | '\u{20D0}' ...'\u{20FF}' => true, // Combining Diacritical Marks for Symbols
- _ => false,
- }
- }
-}
-
-impl Plugin for Emoji {
- fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
- match message.command {
- 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_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
- panic!("Emoji 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, 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/factoid/database.rs
index b1fe8dd..5e7e24c 100644
--- a/src/plugins/factoids/database.rs
+++ b/src/plugins/factoid/database.rs
@@ -1,20 +1,17 @@
-#[cfg(feature = "mysql")]
-extern crate dotenv;
-
+use std::collections::HashMap;
#[cfg(feature = "mysql")]
use std::sync::Arc;
-use std::collections::HashMap;
#[cfg(feature = "mysql")]
+use diesel::mysql::MysqlConnection;
+#[cfg(feature = "mysql")]
use diesel::prelude::*;
#[cfg(feature = "mysql")]
-use diesel::mysql::MysqlConnection;
+use failure::ResultExt;
#[cfg(feature = "mysql")]
use r2d2::Pool;
#[cfg(feature = "mysql")]
use r2d2_diesel::ConnectionManager;
-#[cfg(feature = "mysql")]
-use failure::ResultExt;
use chrono::NaiveDateTime;
@@ -40,21 +37,21 @@ pub struct NewFactoid<'a> {
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>;
+pub trait Database: Send + Sync {
+ fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidError>;
+ fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidError>;
+ fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidError>;
+ fn count_factoids(&self, name: &str) -> Result<i32, FactoidError>;
}
// HashMap
-impl Database for HashMap<(String, i32), Factoid> {
- fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidsError> {
+impl<S: ::std::hash::BuildHasher + Send + Sync> Database for HashMap<(String, i32), Factoid, S> {
+ fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidError> {
let factoid = Factoid {
- name: String::from(factoid.name),
+ name: factoid.name.to_owned(),
idx: factoid.idx,
- content: factoid.content.to_string(),
- author: factoid.author.to_string(),
+ content: factoid.content.to_owned(),
+ author: factoid.author.to_owned(),
created: factoid.created,
};
@@ -65,20 +62,21 @@ impl Database for HashMap<(String, i32), Factoid> {
}
}
- fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidsError> {
- Ok(self.get(&(String::from(name), idx))
+ fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidError> {
+ Ok(self
+ .get(&(name.to_owned(), idx))
.cloned()
.ok_or(ErrorKind::NotFound)?)
}
- fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidsError> {
- match self.remove(&(String::from(name), idx)) {
+ fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidError> {
+ match self.remove(&(name.to_owned(), idx)) {
Some(_) => Ok(()),
None => Err(ErrorKind::NotFound)?,
}
}
- fn count_factoids(&self, name: &str) -> Result<i32, FactoidsError> {
+ fn count_factoids(&self, name: &str) -> Result<i32, FactoidError> {
Ok(self.iter().filter(|&(&(ref n, _), _)| n == name).count() as i32)
}
}
@@ -103,7 +101,7 @@ use self::schema::factoids;
#[cfg(feature = "mysql")]
impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> {
- fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidsError> {
+ fn insert_factoid(&mut self, factoid: &NewFactoid) -> Result<(), FactoidError> {
use diesel;
let conn = &*self.get().context(ErrorKind::NoConnection)?;
@@ -115,7 +113,7 @@ impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> {
Ok(())
}
- fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidsError> {
+ fn get_factoid(&self, name: &str, idx: i32) -> Result<Factoid, FactoidError> {
let conn = &*self.get().context(ErrorKind::NoConnection)?;
Ok(factoids::table
.find((name, idx))
@@ -123,9 +121,9 @@ impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> {
.context(ErrorKind::MysqlError)?)
}
- fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidsError> {
- use diesel;
+ fn delete_factoid(&mut self, name: &str, idx: i32) -> Result<(), FactoidError> {
use self::factoids::columns;
+ use diesel;
let conn = &*self.get().context(ErrorKind::NoConnection)?;
match diesel::delete(
@@ -145,7 +143,7 @@ impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> {
}
}
- fn count_factoids(&self, name: &str) -> Result<i32, FactoidsError> {
+ fn count_factoids(&self, name: &str) -> Result<i32, FactoidError> {
use diesel;
let conn = &*self.get().context(ErrorKind::NoConnection)?;
diff --git a/src/plugins/factoids/mod.rs b/src/plugins/factoid/mod.rs
index 2f3690f..4fcc7a0 100644
--- a/src/plugins/factoids/mod.rs
+++ b/src/plugins/factoid/mod.rs
@@ -1,46 +1,47 @@
extern crate rlua;
-use std::fmt;
-use std::str::FromStr;
-use std::sync::Mutex;
use self::rlua::prelude::*;
+use antidote::RwLock;
use irc::client::prelude::*;
+use std::fmt;
+use std::marker::PhantomData;
+use std::str::FromStr;
-use time;
use chrono::NaiveDateTime;
+use time;
use plugin::*;
+use FrippyClient;
pub mod database;
use self::database::Database;
mod utils;
use self::utils::*;
+use utils::Url;
-use failure::ResultExt;
+use self::error::*;
use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
-use self::error::*;
+use failure::ResultExt;
static LUA_SANDBOX: &'static str = include_str!("sandbox.lua");
-#[derive(PluginName)]
-pub struct Factoids<T: Database> {
- factoids: Mutex<T>,
+enum FactoidResponse {
+ Public(String),
+ Private(String),
}
-macro_rules! try_lock {
- ( $m:expr ) => {
- match $m.lock() {
- Ok(guard) => guard,
- Err(poisoned) => poisoned.into_inner(),
- }
- }
+#[derive(PluginName)]
+pub struct Factoid<T: Database, C: Client> {
+ factoids: RwLock<T>,
+ phantom: PhantomData<C>,
}
-impl<T: Database> Factoids<T> {
- pub fn new(db: T) -> Factoids<T> {
- Factoids {
- factoids: Mutex::new(db),
+impl<T: Database, C: Client> Factoid<T, C> {
+ pub fn new(db: T) -> Self {
+ Factoid {
+ factoids: RwLock::new(db),
+ phantom: PhantomData,
}
}
@@ -49,24 +50,26 @@ impl<T: Database> Factoids<T> {
name: &str,
content: &str,
author: &str,
- ) -> Result<&str, FactoidsError> {
- let count = try_lock!(self.factoids).count_factoids(name)?;
+ ) -> Result<&str, FactoidError> {
+ let count = self.factoids.read().count_factoids(name)?;
let tm = time::now().to_timespec();
let factoid = database::NewFactoid {
- name: name,
+ name,
idx: count,
- content: content,
- author: author,
+ content,
+ author,
created: NaiveDateTime::from_timestamp(tm.sec, 0u32),
};
- Ok(try_lock!(self.factoids)
+ Ok(self
+ .factoids
+ .write()
.insert_factoid(&factoid)
.map(|()| "Successfully added!")?)
}
- fn add(&self, command: &mut PluginCommand) -> Result<&str, FactoidsError> {
+ fn add(&self, command: &mut PluginCommand) -> Result<&str, FactoidError> {
if command.tokens.len() < 2 {
Err(ErrorKind::InvalidCommand)?;
}
@@ -77,38 +80,41 @@ impl<T: Database> Factoids<T> {
Ok(self.create_factoid(&name, &content, &command.source)?)
}
- fn add_from_url(&self, command: &mut PluginCommand) -> Result<&str, FactoidsError> {
+ fn add_from_url(&self, command: &mut PluginCommand) -> Result<&str, FactoidError> {
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)?;
+ let content = Url::from(url.as_ref())
+ .max_kib(1024)
+ .request()
+ .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 {
+ fn remove(&self, command: &mut PluginCommand) -> Result<&str, FactoidError> {
+ if command.tokens.is_empty() {
Err(ErrorKind::InvalidCommand)?;
}
let name = command.tokens.remove(0);
- let count = try_lock!(self.factoids).count_factoids(&name)?;
+ let count = self.factoids.read().count_factoids(&name)?;
- match try_lock!(self.factoids).delete_factoid(&name, count - 1) {
+ match self.factoids.write().delete_factoid(&name, count - 1) {
Ok(()) => Ok("Successfully removed"),
Err(e) => Err(e)?,
}
}
- fn get(&self, command: &PluginCommand) -> Result<String, FactoidsError> {
+ fn get(&self, command: &PluginCommand) -> Result<String, FactoidError> {
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)?;
+ let count = self.factoids.read().count_factoids(name)?;
if count < 1 {
Err(ErrorKind::NotFound)?;
@@ -127,7 +133,9 @@ impl<T: Database> Factoids<T> {
}
};
- let factoid = try_lock!(self.factoids)
+ let factoid = self
+ .factoids
+ .read()
.get_factoid(name, idx)
.context(ErrorKind::NotFound)?;
@@ -136,12 +144,12 @@ impl<T: Database> Factoids<T> {
Ok(format!("{}: {}", factoid.name, message))
}
- fn info(&self, command: &PluginCommand) -> Result<String, FactoidsError> {
+ fn info(&self, command: &PluginCommand) -> Result<String, FactoidError> {
match command.tokens.len() {
0 => Err(ErrorKind::InvalidCommand)?,
1 => {
let name = &command.tokens[0];
- let count = try_lock!(self.factoids).count_factoids(name)?;
+ let count = self.factoids.read().count_factoids(name)?;
Ok(match count {
0 => Err(ErrorKind::NotFound)?,
@@ -152,7 +160,7 @@ impl<T: Database> Factoids<T> {
_ => {
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)?;
+ let factoid = self.factoids.read().get_factoid(name, idx)?;
Ok(format!(
"{}: Added by {} at {} UTC",
@@ -162,13 +170,13 @@ impl<T: Database> Factoids<T> {
}
}
- fn exec(&self, mut command: PluginCommand) -> Result<String, FactoidsError> {
- if command.tokens.len() < 1 {
+ fn exec(&self, mut command: PluginCommand) -> Result<String, FactoidError> {
+ if command.tokens.is_empty() {
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 count = self.factoids.read().count_factoids(&name)?;
+ let factoid = self.factoids.read().get_factoid(&name, count - 1)?;
let content = factoid.content;
let value = if content.starts_with('>') {
@@ -179,7 +187,10 @@ impl<T: Database> Factoids<T> {
} else {
match self.run_lua(&name, &content, &command) {
Ok(v) => v,
- Err(e) => format!("\"{}\"", e),
+ Err(e) => match e {
+ LuaError::CallbackError { cause, .. } => cause.to_string(),
+ _ => e.to_string(),
+ },
}
}
} else {
@@ -190,12 +201,7 @@ impl<T: Database> Factoids<T> {
}
}
- fn run_lua(
- &self,
- name: &str,
- code: &str,
- command: &PluginCommand,
- ) -> Result<String, rlua::Error> {
+ fn run_lua(&self, name: &str, code: &str, command: &PluginCommand) -> Result<String, LuaError> {
let args = command
.tokens
.iter()
@@ -208,6 +214,7 @@ impl<T: Database> Factoids<T> {
globals.set("factoid", code)?;
globals.set("download", lua.create_function(download)?)?;
+ globals.set("json_decode", lua.create_function(json_decode)?)?;
globals.set("sleep", lua.create_function(sleep)?)?;
globals.set("args", args)?;
globals.set("input", command.tokens.join(" "))?;
@@ -220,10 +227,16 @@ impl<T: Database> Factoids<T> {
Ok(output.join("|"))
}
+
+ fn help(&self) -> &str {
+ "usage: factoids <subcommand>\r\n\
+ subcommands: add, fromurl, remove, get, info, exec, help"
+ }
}
-impl<T: Database> Plugin for Factoids<T> {
- fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
+impl<T: Database, C: FrippyClient> Plugin for Factoid<T, C> {
+ type Client = C;
+ fn execute(&self, _: &Self::Client, message: &Message) -> ExecutionStatus {
match message.command {
Command::PRIVMSG(_, ref content) => if content.starts_with('!') {
ExecutionStatus::RequiresThread
@@ -234,7 +247,11 @@ impl<T: Database> Plugin for Factoids<T> {
}
}
- fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> {
+ fn execute_threaded(
+ &self,
+ client: &Self::Client,
+ message: &Message,
+ ) -> Result<(), FrippyError> {
if let Command::PRIVMSG(_, mut content) = message.command.clone() {
content.remove(0);
@@ -246,22 +263,29 @@ impl<T: Database> Plugin for Factoids<T> {
tokens: t,
};
- Ok(match self.exec(c) {
- Ok(f) => client
+ if let Ok(f) = self.exec(c) {
+ client
.send_privmsg(&message.response_target().unwrap(), &f)
- .context(FrippyErrorKind::Connection)?,
- Err(_) => (),
- })
- } else {
- Ok(())
+ .context(FrippyErrorKind::Connection)?;
+ }
}
+
+ Ok(())
}
- fn command(&self, client: &IrcClient, mut command: PluginCommand) -> Result<(), FrippyError> {
+ fn command(
+ &self,
+ client: &Self::Client,
+ mut command: PluginCommand,
+ ) -> Result<(), FrippyError> {
+ use self::FactoidResponse::{Private, Public};
+
if command.tokens.is_empty() {
- return Ok(client
- .send_notice(&command.target, "Invalid command")
- .context(FrippyErrorKind::Connection)?);
+ client
+ .send_notice(&command.source, "Invalid command")
+ .context(FrippyErrorKind::Connection)?;
+
+ return Ok(());
}
let target = command.target.clone();
@@ -269,45 +293,55 @@ impl<T: Database> Plugin for Factoids<T> {
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),
+ "add" => self.add(&mut command).map(|s| Private(s.to_owned())),
+ "fromurl" => self
+ .add_from_url(&mut command)
+ .map(|s| Private(s.to_owned())),
+ "remove" => self.remove(&mut command).map(|s| Private(s.to_owned())),
+ "get" => self.get(&command).map(Public),
+ "info" => self.info(&command).map(Public),
+ "exec" => self.exec(command).map(Public),
+ "help" => Ok(Private(self.help().to_owned())),
_ => Err(ErrorKind::InvalidCommand.into()),
};
- Ok(match result {
- Ok(v) => client
- .send_privmsg(&target, &v)
- .context(FrippyErrorKind::Connection)?,
+ match result {
+ Ok(v) => match v {
+ Public(m) => client
+ .send_privmsg(&target, &m)
+ .context(FrippyErrorKind::Connection)?,
+ Private(m) => client
+ .send_notice(&source, &m)
+ .context(FrippyErrorKind::Connection)?,
+ },
Err(e) => {
let message = e.to_string();
client
.send_notice(&source, &message)
.context(FrippyErrorKind::Connection)?;
- Err(e).context(FrippyErrorKind::Factoids)?
+ Err(e).context(FrippyErrorKind::Factoid)?
}
- })
+ }
+
+ Ok(())
}
- fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
+ fn evaluate(&self, _: &Self::Client, _: PluginCommand) -> Result<String, String> {
Err(String::from(
- "Evaluation of commands is not implemented for Factoids at this time",
+ "Evaluation of commands is not implemented for Factoid at this time",
))
}
}
-impl<T: Database> fmt::Debug for Factoids<T> {
+impl<T: Database, C: FrippyClient> fmt::Debug for Factoid<T, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Factoids {{ ... }}")
+ write!(f, "Factoid {{ ... }}")
}
}
pub mod error {
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
- #[error = "FactoidsError"]
+ #[error = "FactoidError"]
pub enum ErrorKind {
/// Invalid command error
#[fail(display = "Invalid Command")]
diff --git a/src/plugins/factoids/sandbox.lua b/src/plugins/factoid/sandbox.lua
index 3fc74cd..a927535 100644
--- a/src/plugins/factoids/sandbox.lua
+++ b/src/plugins/factoid/sandbox.lua
@@ -13,13 +13,30 @@ function sendln(text)
table.insert(output, "")
end
+function trim(s)
+ local from = s:match"^%s*()"
+ return from > #s and "" or s:match(".*%S", from)
+end
+
+trimmedInput = trim(input)
+
+if trimmedInput == "" then
+ ioru = user
+else
+ ioru = trimmedInput
+end
+
local sandbox_env = {
print = send,
println = sendln,
+ trim = trim,
eval = nil,
+ sleep = nil,
+ json = {decode = json_decode},
args = args,
input = input,
user = user,
+ ioru = ioru,
channel = channel,
request = download,
string = string,
@@ -60,10 +77,21 @@ function eval(code)
end
end
+-- Only sleeps for 1 second at a time
+-- This ensures that the timeout check can still run
+function safesleep(dur)
+ while dur > 1000 do
+ dur = dur - 1000
+ sleep(1000)
+ end
+ sleep(dur)
+end
+
sandbox_env.eval = eval
+sandbox_env.sleep = safesleep
-- Check if the factoid timed out
-function checktime(event, line)
+function checktime()
if os.time() - time >= timeout then
error("Timed out after " .. timeout .. " seconds", 0)
else
@@ -72,12 +100,24 @@ function checktime(event, line)
end
end
+-- Check if the factoid uses too much memory
+function checkmem()
+ if collectgarbage("count") > maxmem then
+ error("Factoid used over " .. maxmem .. " kbyte of ram")
+ end
+end
+
local f, e = load(factoid, nil, nil, sandbox_env)
-- Add timeout hook
time = os.time()
+-- The timeout is defined in seconds
timeout = 30
debug.sethook(checktime, "l")
+-- Add memory check hook
+-- The max memory is defined in kilobytes
+maxmem = 1000
+debug.sethook(checkmem, "l")
if f then
f()
diff --git a/src/plugins/factoid/utils.rs b/src/plugins/factoid/utils.rs
new file mode 100644
index 0000000..7bd9b20
--- /dev/null
+++ b/src/plugins/factoid/utils.rs
@@ -0,0 +1,82 @@
+use std::thread;
+use std::time::Duration;
+
+use serde_json::{self, Value as SerdeValue};
+
+use super::rlua::Error as LuaError;
+use super::rlua::Error::RuntimeError;
+use super::rlua::{Lua, Value as LuaValue};
+
+use utils::error::ErrorKind::Connection;
+use utils::Url;
+
+use failure::Fail;
+
+pub fn sleep(_: &Lua, dur: u64) -> Result<(), LuaError> {
+ thread::sleep(Duration::from_millis(dur));
+ Ok(())
+}
+
+pub fn download(_: &Lua, url: String) -> Result<String, LuaError> {
+ let url = Url::from(url).max_kib(1024);
+ match url.request() {
+ Ok(v) => Ok(v),
+ Err(e) => {
+ let error = match e.kind() {
+ Connection => e.cause().unwrap().to_string(),
+ _ => e.to_string(),
+ };
+
+ Err(RuntimeError(format!(
+ "Failed to download {} - {}",
+ url.as_str(),
+ error
+ )))
+ }
+ }
+}
+
+fn convert_value(lua: &Lua, sval: SerdeValue, max_recurs: usize) -> Result<LuaValue, LuaError> {
+ if max_recurs == 0 {
+ return Err(RuntimeError(String::from(
+ "Reached max recursion level - json is nested too deep",
+ )));
+ }
+
+ let lval = match sval {
+ SerdeValue::Null => LuaValue::Nil,
+ SerdeValue::Bool(b) => LuaValue::Boolean(b),
+ SerdeValue::String(s) => LuaValue::String(lua.create_string(&s)?),
+ SerdeValue::Number(n) => {
+ let f = n.as_f64().ok_or_else(|| {
+ RuntimeError(String::from("Failed to convert number into double"))
+ })?;
+ LuaValue::Number(f)
+ }
+ SerdeValue::Array(arr) => {
+ let table = lua.create_table()?;
+ for (i, val) in arr.into_iter().enumerate() {
+ table.set(i + 1, convert_value(lua, val, max_recurs - 1)?)?;
+ }
+
+ LuaValue::Table(table)
+ }
+ SerdeValue::Object(obj) => {
+ let table = lua.create_table()?;
+ for (key, val) in obj {
+ table.set(key, convert_value(lua, val, max_recurs - 1)?)?;
+ }
+
+ LuaValue::Table(table)
+ }
+ };
+
+ Ok(lval)
+}
+
+pub fn json_decode(lua: &Lua, json: String) -> Result<LuaValue, LuaError> {
+ let ser_val: SerdeValue =
+ serde_json::from_str(&json).map_err(|e| RuntimeError(e.to_string()))?;
+
+ convert_value(lua, ser_val, 25)
+}
diff --git a/src/plugins/factoids/utils.rs b/src/plugins/factoids/utils.rs
deleted file mode 100644
index 70ac8a7..0000000
--- a/src/plugins/factoids/utils.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-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 7e3658d..d54008a 100644
--- a/src/plugins/help.rs
+++ b/src/plugins/help.rs
@@ -1,36 +1,51 @@
+use std::marker::PhantomData;
+
use irc::client::prelude::*;
use plugin::*;
+use FrippyClient;
-use error::FrippyError;
use error::ErrorKind as FrippyErrorKind;
+use error::FrippyError;
use failure::ResultExt;
#[derive(PluginName, Default, Debug)]
-pub struct Help;
+pub struct Help<C> {
+ phantom: PhantomData<C>,
+}
-impl Help {
- pub fn new() -> Help {
- Help {}
+impl<C: FrippyClient> Help<C> {
+ pub fn new() -> Self {
+ Help {
+ phantom: PhantomData,
+ }
}
}
-impl Plugin for Help {
- fn execute(&self, _: &IrcClient, _: &Message) -> ExecutionStatus {
+impl<C: FrippyClient> Plugin for Help<C> {
+ type Client = C;
+ fn execute(&self, _: &Self::Client, _: &Message) -> ExecutionStatus {
ExecutionStatus::Done
}
- fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
+ fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
panic!("Help should not use threading")
}
- fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
- Ok(client
- .send_notice(&command.source, "Help has not been added yet.")
- .context(FrippyErrorKind::Connection)?)
+ fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
+ client
+ .send_notice(
+ &command.source,
+ "Available commands: help, tell, factoids, remind, quote, unicode\r\n\
+ For more detailed help call help on the specific command.\r\n\
+ Example: 'remind help'",
+ )
+ .context(FrippyErrorKind::Connection)?;
+
+ Ok(())
}
- fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
+ fn evaluate(&self, _: &Self::Client, _: 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
index 58ac167..6ba16c1 100644
--- a/src/plugins/keepnick.rs
+++ b/src/plugins/keepnick.rs
@@ -1,20 +1,27 @@
+use std::marker::PhantomData;
+
use irc::client::prelude::*;
use plugin::*;
+use FrippyClient;
-use error::FrippyError;
use error::ErrorKind as FrippyErrorKind;
+use error::FrippyError;
use failure::ResultExt;
#[derive(PluginName, Default, Debug)]
-pub struct KeepNick;
+pub struct KeepNick<C> {
+ phantom: PhantomData<C>,
+}
-impl KeepNick {
- pub fn new() -> KeepNick {
- KeepNick {}
+impl<C: FrippyClient> KeepNick<C> {
+ pub fn new() -> Self {
+ KeepNick {
+ phantom: PhantomData,
+ }
}
- fn check_nick(&self, client: &IrcClient, leaver: &str) -> ExecutionStatus {
+ fn check_nick(&self, client: &C, leaver: &str) -> ExecutionStatus {
let cfg_nick = match client.config().nickname {
Some(ref nick) => nick.clone(),
None => return ExecutionStatus::Done,
@@ -41,8 +48,9 @@ impl KeepNick {
}
}
-impl Plugin for KeepNick {
- fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
+impl<C: FrippyClient> Plugin for KeepNick<C> {
+ type Client = C;
+ fn execute(&self, client: &Self::Client, message: &Message) -> ExecutionStatus {
match message.command {
Command::QUIT(ref nick) => {
self.check_nick(client, &nick.clone().unwrap_or_else(String::new))
@@ -51,20 +59,22 @@ impl Plugin for KeepNick {
}
}
- fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
+ fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
panic!("Tell should not use threading")
}
- fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
- Ok(client
+ fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
+ client
.send_notice(
&command.source,
"This Plugin does not implement any commands.",
)
- .context(FrippyErrorKind::Connection)?)
+ .context(FrippyErrorKind::Connection)?;
+
+ Ok(())
}
- fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
+ fn evaluate(&self, _: &Self::Client, _: 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 9a3ba2f..0dfb011 100644
--- a/src/plugins/mod.rs
+++ b/src/plugins/mod.rs
@@ -1,8 +1,10 @@
//! Collection of plugins included
+pub mod factoid;
pub mod help;
-pub mod url;
-pub mod emoji;
-pub mod tell;
-pub mod currency;
-pub mod factoids;
pub mod keepnick;
+pub mod quote;
+pub mod remind;
+pub mod sed;
+pub mod tell;
+pub mod unicode;
+pub mod url;
diff --git a/src/plugins/quote/database.rs b/src/plugins/quote/database.rs
new file mode 100644
index 0000000..49d6058
--- /dev/null
+++ b/src/plugins/quote/database.rs
@@ -0,0 +1,142 @@
+use std::collections::HashMap;
+#[cfg(feature = "mysql")]
+use std::sync::Arc;
+
+#[cfg(feature = "mysql")]
+use diesel::mysql::MysqlConnection;
+#[cfg(feature = "mysql")]
+use diesel::prelude::*;
+#[cfg(feature = "mysql")]
+use failure::ResultExt;
+#[cfg(feature = "mysql")]
+use r2d2::Pool;
+#[cfg(feature = "mysql")]
+use r2d2_diesel::ConnectionManager;
+
+use chrono::NaiveDateTime;
+
+use super::error::*;
+
+#[cfg_attr(feature = "mysql", derive(Queryable))]
+#[derive(Clone, Debug)]
+pub struct Quote {
+ pub quotee: String,
+ pub channel: 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 = "quotes")]
+pub struct NewQuote<'a> {
+ pub quotee: &'a str,
+ pub channel: &'a str,
+ pub idx: i32,
+ pub content: &'a str,
+ pub author: &'a str,
+ pub created: NaiveDateTime,
+}
+
+pub trait Database: Send + Sync {
+ fn insert_quote(&mut self, quote: &NewQuote) -> Result<(), QuoteError>;
+ fn get_quote(&self, quotee: &str, channel: &str, idx: i32) -> Result<Quote, QuoteError>;
+ fn count_quotes(&self, quotee: &str, channel: &str) -> Result<i32, QuoteError>;
+}
+
+// HashMap
+impl<S: ::std::hash::BuildHasher + Send + Sync> Database
+ for HashMap<(String, String, i32), Quote, S>
+{
+ fn insert_quote(&mut self, quote: &NewQuote) -> Result<(), QuoteError> {
+ let quote = Quote {
+ quotee: quote.quotee.to_owned(),
+ channel: quote.channel.to_owned(),
+ idx: quote.idx,
+ content: quote.content.to_owned(),
+ author: quote.author.to_owned(),
+ created: quote.created,
+ };
+
+ let quotee = quote.quotee.clone();
+ let channel = quote.channel.clone();
+ match self.insert((quotee, channel, quote.idx), quote) {
+ None => Ok(()),
+ Some(_) => Err(ErrorKind::Duplicate)?,
+ }
+ }
+
+ fn get_quote(&self, quotee: &str, channel: &str, idx: i32) -> Result<Quote, QuoteError> {
+ Ok(self
+ .get(&(quotee.to_owned(), channel.to_owned(), idx))
+ .cloned()
+ .ok_or(ErrorKind::NotFound)?)
+ }
+
+ fn count_quotes(&self, quotee: &str, channel: &str) -> Result<i32, QuoteError> {
+ Ok(self
+ .iter()
+ .filter(|&(&(ref n, ref c, _), _)| n == quotee && c == channel)
+ .count() as i32)
+ }
+}
+
+// Diesel automatically defines the quotes module as public.
+// We create a schema module to keep it private.
+#[cfg(feature = "mysql")]
+mod schema {
+ table! {
+ quotes (quotee, channel, idx) {
+ quotee -> Varchar,
+ channel -> Varchar,
+ idx -> Integer,
+ content -> Text,
+ author -> Varchar,
+ created -> Timestamp,
+ }
+ }
+}
+
+#[cfg(feature = "mysql")]
+use self::schema::quotes;
+
+#[cfg(feature = "mysql")]
+impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> {
+ fn insert_quote(&mut self, quote: &NewQuote) -> Result<(), QuoteError> {
+ use diesel;
+
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+ diesel::insert_into(quotes::table)
+ .values(quote)
+ .execute(conn)
+ .context(ErrorKind::MysqlError)?;
+
+ Ok(())
+ }
+
+ fn get_quote(&self, quotee: &str, channel: &str, idx: i32) -> Result<Quote, QuoteError> {
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+ Ok(quotes::table
+ .find((quotee, channel, idx))
+ .first(conn)
+ .context(ErrorKind::MysqlError)?)
+ }
+
+ fn count_quotes(&self, quotee: &str, channel: &str) -> Result<i32, QuoteError> {
+ use diesel;
+
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+ let count: Result<i64, _> = quotes::table
+ .filter(quotes::columns::quotee.eq(quotee))
+ .filter(quotes::columns::channel.eq(channel))
+ .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/quote/mod.rs b/src/plugins/quote/mod.rs
new file mode 100644
index 0000000..edeed40
--- /dev/null
+++ b/src/plugins/quote/mod.rs
@@ -0,0 +1,278 @@
+use std::fmt;
+use std::marker::PhantomData;
+use std::str::FromStr;
+
+use antidote::RwLock;
+use chrono::NaiveDateTime;
+use irc::client::prelude::*;
+use rand::{thread_rng, Rng};
+use time;
+
+use plugin::*;
+use FrippyClient;
+pub mod database;
+use self::database::Database;
+
+use self::error::*;
+use error::ErrorKind as FrippyErrorKind;
+use error::FrippyError;
+use failure::ResultExt;
+
+enum QuoteResponse {
+ Public(String),
+ Private(String),
+}
+
+#[derive(PluginName)]
+pub struct Quote<T: Database, C: Client> {
+ quotes: RwLock<T>,
+ phantom: PhantomData<C>,
+}
+
+impl<T: Database, C: Client> Quote<T, C> {
+ pub fn new(db: T) -> Self {
+ Quote {
+ quotes: RwLock::new(db),
+ phantom: PhantomData,
+ }
+ }
+
+ fn create_quote(
+ &self,
+ quotee: &str,
+ channel: &str,
+ content: &str,
+ author: &str,
+ ) -> Result<&str, QuoteError> {
+ let count = self.quotes.read().count_quotes(quotee, channel)?;
+ let tm = time::now().to_timespec();
+
+ let quote = database::NewQuote {
+ quotee,
+ channel,
+ idx: count + 1,
+ content,
+ author,
+ created: NaiveDateTime::from_timestamp(tm.sec, 0u32),
+ };
+
+ Ok(self
+ .quotes
+ .write()
+ .insert_quote(&quote)
+ .map(|()| "Successfully added!")?)
+ }
+
+ fn add(&self, command: &mut PluginCommand) -> Result<&str, QuoteError> {
+ if command.tokens.len() < 2 {
+ Err(ErrorKind::InvalidCommand)?;
+ }
+
+ if command.target == command.source {
+ Err(ErrorKind::PrivateMessageNotAllowed)?;
+ }
+
+ let quotee = command.tokens.remove(0);
+ let channel = &command.target;
+ let content = command.tokens.join(" ");
+
+ Ok(self.create_quote(&quotee, channel, &content, &command.source)?)
+ }
+
+ fn get(&self, command: &PluginCommand) -> Result<String, QuoteError> {
+ if command.tokens.is_empty() {
+ Err(ErrorKind::InvalidCommand)?;
+ }
+
+ let quotee = &command.tokens[0];
+ let channel = &command.target;
+ let count = self.quotes.read().count_quotes(quotee, channel)?;
+
+ if count < 1 {
+ Err(ErrorKind::NotFound)?;
+ }
+
+ let len = command.tokens.len();
+ let idx = if len < 2 || command.tokens[1].is_empty() {
+ thread_rng().gen_range(1, count + 1)
+ } else {
+ let idx_string = &command.tokens[1];
+ let idx = match i32::from_str(idx_string) {
+ Ok(i) => i,
+ Err(_) => Err(ErrorKind::InvalidIndex)?,
+ };
+
+ if idx < 0 {
+ count + idx + 1
+ } else {
+ idx
+ }
+ };
+
+ let quote = self
+ .quotes
+ .read()
+ .get_quote(quotee, channel, idx)
+ .context(ErrorKind::NotFound)?;
+
+ Ok(format!(
+ "\"{}\" - {}[{}/{}]",
+ quote.content, quote.quotee, idx, count
+ ))
+ }
+
+ fn info(&self, command: &PluginCommand) -> Result<String, QuoteError> {
+ match command.tokens.len() {
+ 0 => Err(ErrorKind::InvalidCommand)?,
+ 1 => {
+ let quotee = &command.tokens[0];
+ let channel = &command.target;
+ let count = self.quotes.read().count_quotes(quotee, channel)?;
+
+ Ok(match count {
+ 0 => Err(ErrorKind::NotFound)?,
+ 1 => format!("{} has 1 quote", quotee),
+ _ => format!("{} has {} quotes", quotee, count),
+ })
+ }
+ _ => {
+ let quotee = &command.tokens[0];
+ let channel = &command.target;
+ let idx = i32::from_str(&command.tokens[1]).context(ErrorKind::InvalidIndex)?;
+
+ let idx = if idx < 0 {
+ self.quotes.read().count_quotes(quotee, channel)? + idx + 1
+ } else {
+ idx
+ };
+
+ let quote = self
+ .quotes
+ .read()
+ .get_quote(quotee, channel, idx)
+ .context(ErrorKind::NotFound)?;
+
+ Ok(format!(
+ "{}'s quote was added by {} at {} UTC",
+ quotee, quote.author, quote.created
+ ))
+ }
+ }
+ }
+
+ fn help(&self) -> &str {
+ "usage: quotes <subcommand>\r\n\
+ subcommands: add, get, info, help"
+ }
+}
+
+impl<T: Database, C: FrippyClient> Plugin for Quote<T, C> {
+ type Client = C;
+ fn execute(&self, _: &Self::Client, _: &Message) -> ExecutionStatus {
+ ExecutionStatus::Done
+ }
+
+ fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
+ panic!("Quotes should not use threading")
+ }
+
+ fn command(
+ &self,
+ client: &Self::Client,
+ mut command: PluginCommand,
+ ) -> Result<(), FrippyError> {
+ use self::QuoteResponse::{Private, Public};
+
+ if command.tokens.is_empty() {
+ client
+ .send_notice(&command.source, &ErrorKind::InvalidCommand.to_string())
+ .context(FrippyErrorKind::Connection)?;
+
+ return Ok(());
+ }
+
+ 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| Private(s.to_owned())),
+ "get" => self.get(&command).map(Public),
+ "info" => self.info(&command).map(Public),
+ "help" => Ok(Private(self.help().to_owned())),
+ _ => Err(ErrorKind::InvalidCommand.into()),
+ };
+
+ match result {
+ Ok(v) => match v {
+ Public(m) => client
+ .send_privmsg(&target, &m)
+ .context(FrippyErrorKind::Connection)?,
+ Private(m) => client
+ .send_notice(&source, &m)
+ .context(FrippyErrorKind::Connection)?,
+ },
+ Err(e) => {
+ let message = e.to_string();
+ client
+ .send_notice(&source, &message)
+ .context(FrippyErrorKind::Connection)?;
+ Err(e).context(FrippyErrorKind::Quote)?
+ }
+ }
+
+ Ok(())
+ }
+
+ fn evaluate(&self, _: &Self::Client, _: PluginCommand) -> Result<String, String> {
+ Err(String::from(
+ "Evaluation of commands is not implemented for Quote at this time",
+ ))
+ }
+}
+
+impl<T: Database, C: FrippyClient> fmt::Debug for Quote<T, C> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Quote {{ ... }}")
+ }
+}
+
+pub mod error {
+ #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
+ #[error = "QuoteError"]
+ pub enum ErrorKind {
+ /// Invalid command error
+ #[fail(display = "Incorrect command. Send \"quote help\" for help")]
+ InvalidCommand,
+
+ /// Invalid index error
+ #[fail(display = "Invalid index")]
+ InvalidIndex,
+
+ /// Private message error
+ #[fail(display = "You can only add quotes in channel messages")]
+ PrivateMessageNotAllowed,
+
+ /// Download error
+ #[fail(display = "Download failed")]
+ Download,
+
+ /// Duplicate error
+ #[fail(display = "Entry already exists")]
+ Duplicate,
+
+ /// Not found error
+ #[fail(display = "Quote 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/remind/database.rs b/src/plugins/remind/database.rs
new file mode 100644
index 0000000..97d93e8
--- /dev/null
+++ b/src/plugins/remind/database.rs
@@ -0,0 +1,236 @@
+use std::collections::hash_map::Entry;
+use std::collections::HashMap;
+use std::fmt;
+
+#[cfg(feature = "mysql")]
+use std::sync::Arc;
+
+#[cfg(feature = "mysql")]
+use diesel::mysql::MysqlConnection;
+#[cfg(feature = "mysql")]
+use diesel::prelude::*;
+#[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(feature = "mysql")]
+static LAST_ID_SQL: &'static str = "SELECT LAST_INSERT_ID()";
+
+#[cfg_attr(feature = "mysql", derive(Queryable))]
+#[derive(Clone, Debug)]
+pub struct Event {
+ pub id: i64,
+ pub receiver: String,
+ pub content: String,
+ pub author: String,
+ pub time: NaiveDateTime,
+ pub repeat: Option<i64>,
+}
+
+impl fmt::Display for Event {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "{}: {} reminds {} to \"{}\" at {}",
+ self.id, self.author, self.receiver, self.content, self.time
+ )
+ }
+}
+
+#[cfg_attr(feature = "mysql", derive(Insertable))]
+#[cfg_attr(feature = "mysql", table_name = "events")]
+#[derive(Debug)]
+pub struct NewEvent<'a> {
+ pub receiver: &'a str,
+ pub content: &'a str,
+ pub author: &'a str,
+ pub time: &'a NaiveDateTime,
+ pub repeat: Option<i64>,
+}
+
+pub trait Database: Send + Sync {
+ fn insert_event(&mut self, event: &NewEvent) -> Result<i64, RemindError>;
+ fn update_event_time(&mut self, id: i64, time: &NaiveDateTime) -> Result<(), RemindError>;
+ fn get_events_before(&self, time: &NaiveDateTime) -> Result<Vec<Event>, RemindError>;
+ fn get_user_events(&self, user: &str) -> Result<Vec<Event>, RemindError>;
+ fn get_event(&self, id: i64) -> Result<Event, RemindError>;
+ fn delete_event(&mut self, id: i64) -> Result<(), RemindError>;
+}
+
+// HashMap
+impl<S: ::std::hash::BuildHasher + Send + Sync> Database for HashMap<i64, Event, S> {
+ fn insert_event(&mut self, event: &NewEvent) -> Result<i64, RemindError> {
+ let mut id = 0;
+ while self.contains_key(&id) {
+ id += 1;
+ }
+
+ let event = Event {
+ id,
+ receiver: event.receiver.to_owned(),
+ content: event.content.to_owned(),
+ author: event.author.to_owned(),
+ time: *event.time,
+ repeat: event.repeat,
+ };
+
+ match self.insert(id, event) {
+ None => Ok(id),
+ Some(_) => Err(ErrorKind::Duplicate)?,
+ }
+ }
+
+ fn update_event_time(&mut self, id: i64, time: &NaiveDateTime) -> Result<(), RemindError> {
+ let entry = self.entry(id);
+
+ match entry {
+ Entry::Occupied(mut v) => v.get_mut().time = *time,
+ Entry::Vacant(_) => return Err(ErrorKind::NotFound.into()),
+ }
+
+ Ok(())
+ }
+
+ fn get_events_before(&self, time: &NaiveDateTime) -> Result<Vec<Event>, RemindError> {
+ let mut events = Vec::new();
+
+ for (_, event) in self.iter() {
+ if event.time < *time {
+ events.push(event.clone())
+ }
+ }
+
+ if events.is_empty() {
+ Err(ErrorKind::NotFound.into())
+ } else {
+ Ok(events)
+ }
+ }
+
+ fn get_user_events(&self, user: &str) -> Result<Vec<Event>, RemindError> {
+ let mut events = Vec::new();
+
+ for (_, event) in self.iter() {
+ if event.receiver.eq_ignore_ascii_case(user) {
+ events.push(event.clone())
+ }
+ }
+
+ if events.is_empty() {
+ Err(ErrorKind::NotFound.into())
+ } else {
+ Ok(events)
+ }
+ }
+
+ fn get_event(&self, id: i64) -> Result<Event, RemindError> {
+ Ok(self.get(&id).cloned().ok_or(ErrorKind::NotFound)?)
+ }
+
+ fn delete_event(&mut self, id: i64) -> Result<(), RemindError> {
+ match self.remove(&id) {
+ Some(_) => Ok(()),
+ None => Err(ErrorKind::NotFound)?,
+ }
+ }
+}
+
+#[cfg(feature = "mysql")]
+mod schema {
+ table! {
+ events (id) {
+ id -> Bigint,
+ receiver -> Varchar,
+ content -> Text,
+ author -> Varchar,
+ time -> Timestamp,
+ repeat -> Nullable<Bigint>,
+ }
+ }
+}
+
+#[cfg(feature = "mysql")]
+use self::schema::events;
+
+#[cfg(feature = "mysql")]
+impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> {
+ fn insert_event(&mut self, event: &NewEvent) -> Result<i64, RemindError> {
+ use diesel::{self, dsl::sql, types::Bigint};
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+
+ diesel::insert_into(events::table)
+ .values(event)
+ .execute(conn)
+ .context(ErrorKind::MysqlError)?;
+
+ let id = sql::<Bigint>(LAST_ID_SQL)
+ .get_result(conn)
+ .context(ErrorKind::MysqlError)?;
+
+ Ok(id)
+ }
+
+ fn update_event_time(&mut self, id: i64, time: &NaiveDateTime) -> Result<(), RemindError> {
+ use self::events::columns;
+ use diesel;
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+
+ match diesel::update(events::table.filter(columns::id.eq(id)))
+ .set(columns::time.eq(time))
+ .execute(conn)
+ {
+ Ok(0) => Err(ErrorKind::NotFound)?,
+ Ok(_) => Ok(()),
+ Err(e) => Err(e).context(ErrorKind::MysqlError)?,
+ }
+ }
+
+ fn get_events_before(&self, time: &NaiveDateTime) -> Result<Vec<Event>, RemindError> {
+ use self::events::columns;
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+
+ Ok(events::table
+ .filter(columns::time.lt(time))
+ .load::<Event>(conn)
+ .context(ErrorKind::MysqlError)?)
+ }
+
+ fn get_user_events(&self, user: &str) -> Result<Vec<Event>, RemindError> {
+ use self::events::columns;
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+
+ Ok(events::table
+ .filter(columns::receiver.eq(user))
+ .load::<Event>(conn)
+ .context(ErrorKind::MysqlError)?)
+ }
+
+ fn get_event(&self, id: i64) -> Result<Event, RemindError> {
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+
+ Ok(events::table
+ .find(id)
+ .first(conn)
+ .context(ErrorKind::MysqlError)?)
+ }
+
+ fn delete_event(&mut self, id: i64) -> Result<(), RemindError> {
+ use self::events::columns;
+ use diesel;
+
+ let conn = &*self.get().context(ErrorKind::NoConnection)?;
+ match diesel::delete(events::table.filter(columns::id.eq(id))).execute(conn) {
+ Ok(0) => Err(ErrorKind::NotFound)?,
+ Ok(_) => Ok(()),
+ Err(e) => Err(e).context(ErrorKind::MysqlError)?,
+ }
+ }
+}
diff --git a/src/plugins/remind/mod.rs b/src/plugins/remind/mod.rs
new file mode 100644
index 0000000..2a8a093
--- /dev/null
+++ b/src/plugins/remind/mod.rs
@@ -0,0 +1,337 @@
+use std::marker::PhantomData;
+use std::thread::{sleep, spawn};
+use std::{fmt, sync::Arc, time::Duration};
+
+use antidote::RwLock;
+use irc::client::prelude::*;
+
+use chrono::{self, NaiveDateTime};
+use time;
+
+use plugin::*;
+use FrippyClient;
+
+pub mod database;
+mod parser;
+use self::database::Database;
+use self::parser::CommandParser;
+
+use self::error::*;
+use error::ErrorKind as FrippyErrorKind;
+use error::FrippyError;
+use failure::ResultExt;
+
+fn get_time() -> NaiveDateTime {
+ let tm = time::now().to_timespec();
+ NaiveDateTime::from_timestamp(tm.sec, 0u32)
+}
+
+fn get_events<T: Database>(db: &RwLock<T>, in_next: chrono::Duration) -> Vec<database::Event> {
+ loop {
+ let before = get_time() + in_next;
+ match db.read().get_events_before(&before) {
+ Ok(events) => return events,
+ Err(e) => {
+ if e.kind() != ErrorKind::NotFound {
+ error!("Failed to get events: {}", e);
+ }
+ }
+ }
+
+ sleep(in_next.to_std().expect("Failed to convert look ahead time"));
+ }
+}
+
+fn run<T: Database, C: FrippyClient>(client: &C, db: Arc<RwLock<T>>) {
+ let look_ahead = chrono::Duration::minutes(2);
+
+ let mut events = get_events(&db, look_ahead);
+
+ let mut sleep_time = look_ahead
+ .to_std()
+ .expect("Failed to convert look ahead time");
+
+ loop {
+ let now = get_time();
+ for event in events {
+ if event.time <= now {
+ let msg = format!("Reminder from {}: {}", event.author, event.content);
+ if let Err(e) = client.send_notice(&event.receiver, &msg) {
+ error!("Failed to send reminder: {}", e);
+ } else {
+ debug!("Sent reminder {:?}", event);
+
+ if let Some(repeat) = event.repeat {
+ let next_time = event.time + chrono::Duration::seconds(repeat);
+
+ if let Err(e) = db.write().update_event_time(event.id, &next_time) {
+ error!("Failed to update reminder: {}", e);
+ } else {
+ debug!("Updated time");
+ }
+ } else if let Err(e) = db.write().delete_event(event.id) {
+ error!("Failed to delete reminder: {}", e);
+ }
+ }
+ } else {
+ let until_event = (event.time - now)
+ .to_std()
+ .expect("Failed to convert until event time");
+
+ if until_event < sleep_time {
+ sleep_time = until_event + Duration::from_secs(1);
+ }
+ }
+ }
+
+ sleep(sleep_time);
+ sleep_time = Duration::from_secs(120);
+
+ events = get_events(&db, look_ahead);
+ }
+}
+
+#[derive(PluginName)]
+pub struct Remind<T: Database + 'static, C> {
+ events: Arc<RwLock<T>>,
+ has_reminder: RwLock<bool>,
+ phantom: PhantomData<C>,
+}
+
+impl<T: Database + 'static, C: FrippyClient> Remind<T, C> {
+ pub fn new(db: T) -> Self {
+ let events = Arc::new(RwLock::new(db));
+
+ Remind {
+ events,
+ has_reminder: RwLock::new(false),
+ phantom: PhantomData,
+ }
+ }
+
+ fn user_cmd(&self, command: PluginCommand) -> Result<String, RemindError> {
+ let parser = CommandParser::parse_target(command.tokens)?;
+
+ self.set(&parser, &command.source)
+ }
+
+ fn me_cmd(&self, command: PluginCommand) -> Result<String, RemindError> {
+ let source = command.source.clone();
+ let parser = CommandParser::with_target(command.tokens, command.source)?;
+
+ self.set(&parser, &source)
+ }
+
+ fn set(&self, parser: &CommandParser, author: &str) -> Result<String, RemindError> {
+ debug!("parser: {:?}", parser);
+
+ let target = parser.get_target();
+ let time = parser.get_time(Duration::from_secs(120))?;
+
+ let event = database::NewEvent {
+ receiver: target,
+ content: &parser.get_message(),
+ author,
+ time: &time,
+ repeat: parser
+ .get_repeat(Duration::from_secs(300))?
+ .map(|d| d.as_secs() as i64),
+ };
+
+ debug!("New event: {:?}", event);
+
+ Ok(self.events
+ .write()
+ .insert_event(&event)
+ .map(|id| format!("Created reminder with id {} at {} UTC", id, time))?)
+ }
+
+ fn list(&self, user: &str) -> Result<String, RemindError> {
+ let mut events = self.events.read().get_user_events(user)?;
+
+ if events.is_empty() {
+ Err(ErrorKind::NotFound)?;
+ }
+
+ let mut list = events.remove(0).to_string();
+ for ev in events {
+ list.push_str("\r\n");
+ list.push_str(&ev.to_string());
+ }
+
+ Ok(list)
+ }
+
+ fn delete(&self, mut command: PluginCommand) -> Result<&str, RemindError> {
+ let id = command
+ .tokens
+ .remove(0)
+ .parse::<i64>()
+ .context(ErrorKind::Parsing)?;
+ let event = self.events
+ .read()
+ .get_event(id)
+ .context(ErrorKind::NotFound)?;
+
+ if event.receiver.eq_ignore_ascii_case(&command.source)
+ || event.author.eq_ignore_ascii_case(&command.source)
+ {
+ self.events
+ .write()
+ .delete_event(id)
+ .map(|()| "Successfully deleted")
+ } else {
+ Ok("Only the author or receiver can delete a reminder")
+ }
+ }
+
+ fn help(&self) -> &str {
+ "usage: remind <subcommand>\r\n\
+ subcommands: user, me, list, delete, help\r\n\
+ examples\r\n\
+ remind user foo to sleep in 1 hour\r\n\
+ remind me to leave early on 1.1 at 16:00 every week"
+ }
+}
+
+impl<T: Database, C: FrippyClient + 'static> Plugin for Remind<T, C> {
+ type Client = C;
+ fn execute(&self, client: &Self::Client, msg: &Message) -> ExecutionStatus {
+ if let Command::JOIN(_, _, _) = msg.command {
+ let mut has_reminder = self.has_reminder.write();
+
+ if !*has_reminder {
+ let events = Arc::clone(&self.events);
+ let client = client.clone();
+
+ spawn(move || run(&client, events));
+
+ *has_reminder = true;
+ }
+ }
+
+ ExecutionStatus::Done
+ }
+
+ fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
+ panic!("Remind should not use frippy's threading")
+ }
+
+ fn command(
+ &self,
+ client: &Self::Client,
+ mut command: PluginCommand,
+ ) -> Result<(), FrippyError> {
+ if command.tokens.is_empty() {
+ client
+ .send_notice(&command.source, &ErrorKind::InvalidCommand.to_string())
+ .context(FrippyErrorKind::Connection)?;
+ return Ok(());
+ }
+
+ let source = command.source.clone();
+
+ let sub_command = command.tokens.remove(0);
+ let response = match sub_command.as_ref() {
+ "user" => self.user_cmd(command),
+ "me" => self.me_cmd(command),
+ "delete" => self.delete(command).map(|s| s.to_owned()),
+ "list" => self.list(&source),
+ "help" => Ok(self.help().to_owned()),
+ _ => Err(ErrorKind::InvalidCommand.into()),
+ };
+
+ match response {
+ Ok(msg) => client
+ .send_notice(&source, &msg)
+ .context(FrippyErrorKind::Connection)?,
+ Err(e) => {
+ let message = e.to_string();
+
+ client
+ .send_notice(&source, &message)
+ .context(FrippyErrorKind::Connection)?;
+
+ Err(e).context(FrippyErrorKind::Remind)?
+ }
+ }
+
+ Ok(())
+ }
+
+ fn evaluate(&self, _: &Self::Client, _: PluginCommand) -> Result<String, String> {
+ Err(String::from(
+ "Evaluation of commands is not implemented for remind at this time",
+ ))
+ }
+}
+
+impl<T: Database, C: FrippyClient> fmt::Debug for Remind<T, C> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Remind {{ ... }}")
+ }
+}
+
+pub mod error {
+ #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
+ #[error = "RemindError"]
+ pub enum ErrorKind {
+ /// Invalid command error
+ #[fail(display = "Incorrect Command. Send \"remind help\" for help.")]
+ InvalidCommand,
+
+ /// Missing message error
+ #[fail(display = "Reminder needs to have a description")]
+ MissingMessage,
+
+ /// Missing receiver error
+ #[fail(display = "Specify who to remind")]
+ MissingReceiver,
+
+ /// Missing time error
+ #[fail(display = "Reminder needs to have a time")]
+ MissingTime,
+
+ /// Invalid time error
+ #[fail(display = "Could not parse time")]
+ InvalidTime,
+
+ /// Invalid date error
+ #[fail(display = "Could not parse date")]
+ InvalidDate,
+
+ /// Parse error
+ #[fail(display = "Could not parse integers")]
+ Parsing,
+
+ /// Ambigous time error
+ #[fail(display = "Time specified is ambiguous")]
+ AmbiguousTime,
+
+ /// Time too short error
+ #[fail(display = "Reminder needs to be in over 2 minutes")]
+ TimeShort,
+
+ /// Repeat time too short error
+ #[fail(display = "Repeat time needs to be over 5 minutes")]
+ RepeatTimeShort,
+
+ /// Duplicate error
+ #[fail(display = "Entry already exists")]
+ Duplicate,
+
+ /// Not found error
+ #[fail(display = "No events 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/remind/parser.rs b/src/plugins/remind/parser.rs
new file mode 100644
index 0000000..91d13ab
--- /dev/null
+++ b/src/plugins/remind/parser.rs
@@ -0,0 +1,251 @@
+use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
+use humantime::parse_duration;
+use std::time::Duration;
+use time;
+
+use super::error::*;
+use failure::ResultExt;
+
+#[derive(Default, Debug)]
+pub struct CommandParser {
+ on_date: Option<String>,
+ at_time: Option<String>,
+ in_duration: Option<String>,
+ every_time: Option<String>,
+ target: String,
+ message: Option<String>,
+}
+
+#[derive(PartialEq, Clone, Copy)]
+enum ParseState {
+ None,
+ On,
+ At,
+ In,
+ Every,
+ Msg,
+}
+
+impl CommandParser {
+ pub fn parse_target(mut tokens: Vec<String>) -> Result<Self, RemindError> {
+ let mut parser = CommandParser::default();
+
+ if tokens.is_empty() {
+ Err(ErrorKind::MissingReceiver)?;
+ }
+
+ parser.target = tokens.remove(0);
+
+ parser.parse_tokens(tokens)
+ }
+
+ pub fn with_target(tokens: Vec<String>, target: String) -> Result<Self, RemindError> {
+ let mut parser = CommandParser::default();
+ parser.target = target;
+
+ parser.parse_tokens(tokens)
+ }
+
+ fn parse_tokens(mut self, tokens: Vec<String>) -> Result<Self, RemindError> {
+ let mut state = ParseState::None;
+ let mut cur_str = String::new();
+
+ for token in tokens {
+ let next_state = match token.as_ref() {
+ "on" => ParseState::On,
+ "at" => ParseState::At,
+ "in" => ParseState::In,
+ "every" => ParseState::Every,
+ "to" => ParseState::Msg,
+ _ => {
+ if !cur_str.is_empty() {
+ cur_str.push(' ');
+ }
+ cur_str.push_str(&token);
+ state
+ }
+ };
+
+ if next_state != state {
+ if state != ParseState::None {
+ self = self.add_string_by_state(state, cur_str)?;
+ cur_str = String::new();
+ }
+
+ state = next_state;
+ }
+ }
+
+ self = self.add_string_by_state(state, cur_str)?;
+
+ if self.message.is_none() {
+ return Err(ErrorKind::MissingMessage.into());
+ }
+
+ if self.in_duration.is_some() && self.at_time.is_some()
+ || self.in_duration.is_some() && self.on_date.is_some()
+ {
+ return Err(ErrorKind::AmbiguousTime.into());
+ }
+
+ if self.in_duration.is_none() && self.at_time.is_none() && self.on_date.is_none() {
+ return Err(ErrorKind::MissingTime.into());
+ }
+
+ Ok(self)
+ }
+
+ fn add_string_by_state(self, state: ParseState, string: String) -> Result<Self, RemindError> {
+ use self::ParseState::*;
+ let string = Some(string);
+ match state {
+ On if self.on_date.is_none() => Ok(CommandParser {
+ on_date: string,
+ ..self
+ }),
+ At if self.at_time.is_none() => Ok(CommandParser {
+ at_time: string,
+ ..self
+ }),
+ In if self.in_duration.is_none() => Ok(CommandParser {
+ in_duration: string,
+ ..self
+ }),
+ Msg if self.message.is_none() => Ok(CommandParser {
+ message: string,
+ ..self
+ }),
+ Every if self.every_time.is_none() => Ok(CommandParser {
+ every_time: string,
+ ..self
+ }),
+ _ => Err(ErrorKind::MissingMessage.into()),
+ }
+ }
+
+ fn parse_date(&self, str_date: &str) -> Result<NaiveDate, RemindError> {
+ let nums = str_date
+ .split('.')
+ .map(|s| s.parse::<u32>())
+ .collect::<Result<Vec<_>, _>>()
+ .context(ErrorKind::InvalidDate)?;
+
+ if 2 > nums.len() || nums.len() > 3 {
+ return Err(ErrorKind::InvalidDate.into());
+ }
+
+ let day = nums[0];
+ let month = nums[1];
+
+ let parse_date = match nums.get(2) {
+ Some(year) => {
+ NaiveDate::from_ymd_opt(*year as i32, month, day).ok_or(ErrorKind::InvalidDate)?
+ }
+ None => {
+ let now = time::now();
+ let date = NaiveDate::from_ymd_opt(now.tm_year + 1900, month, day)
+ .ok_or(ErrorKind::InvalidDate)?;
+ if date.succ().and_hms(0, 0, 0).timestamp() < now.to_timespec().sec {
+ NaiveDate::from_ymd(now.tm_year + 1901, month, day)
+ } else {
+ date
+ }
+ }
+ };
+
+ Ok(parse_date)
+ }
+
+ fn parse_time(&self, str_time: &str) -> Result<NaiveTime, RemindError> {
+ let nums = str_time
+ .split(':')
+ .map(|s| s.parse::<u32>())
+ .collect::<Result<Vec<_>, _>>()
+ .context(ErrorKind::InvalidTime)?;
+
+ if 2 != nums.len() {
+ return Err(ErrorKind::InvalidTime.into());
+ }
+
+ let hour = nums[0];
+ let minute = nums[1];
+
+ Ok(NaiveTime::from_hms(hour, minute, 0))
+ }
+
+ pub fn get_time(&self, min_dur: Duration) -> Result<NaiveDateTime, RemindError> {
+ if let Some(ref str_duration) = self.in_duration {
+ let duration = parse_duration(&str_duration).context(ErrorKind::InvalidTime)?;
+
+ if duration < min_dur {
+ return Err(ErrorKind::TimeShort.into());
+ }
+
+ let tm = time::now().to_timespec();
+ return Ok(NaiveDateTime::from_timestamp(
+ tm.sec + duration.as_secs() as i64,
+ 0u32,
+ ));
+ }
+
+ let mut date = None;
+ if let Some(ref str_date) = self.on_date {
+ date = Some(self.parse_date(str_date)?);
+ }
+
+ if let Some(ref str_time) = self.at_time {
+ let time = self.parse_time(str_time)?;
+
+ if let Some(date) = date {
+ Ok(date.and_time(time))
+ } else {
+ let now = time::now();
+ let today = NaiveDate::from_ymd_opt(
+ now.tm_year + 1900,
+ now.tm_mon as u32 + 1,
+ now.tm_mday as u32,
+ ).ok_or(ErrorKind::InvalidDate)?;
+
+ let time_today = today.and_time(time);
+
+ if time_today.timestamp() < now.to_timespec().sec {
+ debug!("tomorrow");
+
+ Ok(today.succ().and_time(time))
+ } else {
+ debug!("today");
+
+ Ok(time_today)
+ }
+ }
+ } else {
+ Ok(date.expect("At this point date has to be set")
+ .and_hms(0, 0, 0))
+ }
+ }
+
+ pub fn get_repeat(&self, min_dur: Duration) -> Result<Option<Duration>, RemindError> {
+ if let Some(mut words) = self.every_time.clone() {
+ if !words.chars().next().unwrap().is_digit(10) {
+ words.insert(0, '1');
+ }
+ let dur = parse_duration(&words).context(ErrorKind::InvalidTime)?;
+
+ if dur <= min_dur {
+ return Err(ErrorKind::RepeatTimeShort.into());
+ }
+
+ Ok(Some(dur))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn get_target(&self) -> &str {
+ &self.target
+ }
+
+ pub fn get_message(&self) -> &str {
+ self.message.as_ref().expect("Has to be set")
+ }
+}
diff --git a/src/plugins/sed.rs b/src/plugins/sed.rs
new file mode 100644
index 0000000..2c8522f
--- /dev/null
+++ b/src/plugins/sed.rs
@@ -0,0 +1,193 @@
+use std::collections::HashMap;
+use std::marker::PhantomData;
+
+use antidote::RwLock;
+use circular_queue::CircularQueue;
+use regex::{Regex, RegexBuilder, Captures};
+
+use irc::client::prelude::*;
+
+use plugin::*;
+use FrippyClient;
+
+use self::error::*;
+use error::ErrorKind as FrippyErrorKind;
+use error::FrippyError;
+use failure::Fail;
+use failure::ResultExt;
+
+lazy_static! {
+ static ref RE: Regex =
+ Regex::new(r"^s/((?:\\/|[^/])+)/((?:\\/|[^/])*)/(?:(\w+))?\s*$").unwrap();
+}
+
+#[derive(PluginName, Debug)]
+pub struct Sed<C> {
+ per_channel: usize,
+ channel_messages: RwLock<HashMap<String, CircularQueue<String>>>,
+ phantom: PhantomData<C>,
+}
+
+impl<C: FrippyClient> Sed<C> {
+ pub fn new(per_channel: usize) -> Self {
+ Sed {
+ per_channel,
+ channel_messages: RwLock::new(HashMap::new()),
+ phantom: PhantomData,
+ }
+ }
+
+ fn add_message(&self, channel: String, message: String) {
+ let mut channel_messages = self.channel_messages.write();
+ let messages = channel_messages
+ .entry(channel)
+ .or_insert_with(|| CircularQueue::with_capacity(self.per_channel));
+ messages.push(message);
+ }
+
+ fn format_escaped(&self, input: &str) -> String {
+ let mut output = String::with_capacity(input.len());
+ let mut escape = false;
+
+ for c in input.chars() {
+ if escape && !r"/\".contains(c) {
+ output.push('\\');
+ } else if !escape && c == '\\' {
+ escape = true;
+ continue;
+ }
+ escape = false;
+
+ output.push(c);
+ }
+
+ output
+ }
+
+ fn run_regex(&self, channel: &str, captures: &Captures) -> Result<String, SedError> {
+ let mut global_match = false;
+ let mut case_insens = false;
+ let mut ign_whitespace = false;
+ let mut swap_greed = false;
+ let mut enable_unicode = true;
+
+ debug!("{:?}", captures);
+
+ let first = self.format_escaped(captures.get(1).unwrap().as_str());
+ let second = self.format_escaped(captures.get(2).unwrap().as_str());
+
+ if let Some(flags) = captures.get(3) {
+ let flags = flags.as_str();
+
+ global_match = flags.contains('g');
+ case_insens = flags.contains('i');
+ ign_whitespace = flags.contains('x');
+ swap_greed = flags.contains('U');
+ enable_unicode = !flags.contains('u');
+ }
+
+ let user_re = RegexBuilder::new(&first)
+ .case_insensitive(case_insens)
+ .ignore_whitespace(ign_whitespace)
+ .unicode(enable_unicode)
+ .swap_greed(swap_greed)
+ .build()
+ .context(ErrorKind::InvalidRegex)?;
+
+ let channel_messages = self.channel_messages.read();
+ let messages = channel_messages.get(channel).ok_or(ErrorKind::NoMessages)?;
+
+ for message in messages.iter() {
+ if user_re.is_match(message) {
+ let response = if global_match {
+ user_re.replace_all(message, &second[..])
+ } else {
+ user_re.replace(message, &second[..])
+ };
+
+ return Ok(response.to_string());
+ }
+ }
+
+ Err(ErrorKind::NoMatch)?
+ }
+}
+
+impl<C: FrippyClient> Plugin for Sed<C> {
+ type Client = C;
+ fn execute(&self, client: &Self::Client, message: &Message) -> ExecutionStatus {
+ match message.command {
+ Command::PRIVMSG(_, ref content) => {
+ let channel = message.response_target().unwrap_or("");
+ let user = message.source_nickname().unwrap_or("");
+ if channel == user {
+ return ExecutionStatus::Done;
+ }
+
+ if let Some(captures) = RE.captures(content) {
+ let result = match self.run_regex(channel, &captures) {
+ Ok(msg) => client.send_privmsg(channel, &msg),
+ Err(e) => match e.kind() {
+ ErrorKind::InvalidRegex => {
+ let err = e.cause().unwrap().to_string();
+ client.send_notice(user, &err.replace('\n', "\r\n"))
+ }
+ _ => client.send_notice(user, &e.to_string()),
+ },
+ };
+
+ match result {
+ Err(e) => {
+ ExecutionStatus::Err(e.context(FrippyErrorKind::Connection).into())
+ }
+ Ok(_) => ExecutionStatus::Done,
+ }
+ } else {
+ self.add_message(channel.to_string(), content.to_string());
+
+ ExecutionStatus::Done
+ }
+ }
+ _ => ExecutionStatus::Done,
+ }
+ }
+
+ fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
+ panic!("Sed should not use threading")
+ }
+
+ fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
+ client
+ .send_notice(
+ &command.source,
+ "Currently this Plugin does not implement any commands.",
+ )
+ .context(FrippyErrorKind::Connection)?;
+
+ Ok(())
+ }
+
+ fn evaluate(&self, _: &Self::Client, _: PluginCommand) -> Result<String, String> {
+ Err(String::from(
+ "Evaluation of commands is not implemented for sed at this time",
+ ))
+ }
+}
+
+pub mod error {
+ #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
+ #[error = "SedError"]
+ pub enum ErrorKind {
+ /// Invalid regex error
+ #[fail(display = "Invalid regex")]
+ InvalidRegex,
+
+ /// No messages found error
+ #[fail(display = "No messages were found for this channel")]
+ NoMessages,
+
+ /// No match found error
+ #[fail(display = "No recent messages match this regex")]
+ NoMatch,
+ }
+}
diff --git a/src/plugins/tell/database.rs b/src/plugins/tell/database.rs
index 98e9fb3..cbcb93d 100644
--- a/src/plugins/tell/database.rs
+++ b/src/plugins/tell/database.rs
@@ -1,15 +1,12 @@
-#[cfg(feature = "mysql")]
-extern crate dotenv;
-
+use std::collections::HashMap;
#[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 diesel::prelude::*;
+#[cfg(feature = "mysql")]
use r2d2::Pool;
#[cfg(feature = "mysql")]
use r2d2_diesel::ConnectionManager;
@@ -40,7 +37,7 @@ pub struct NewTellMessage<'a> {
pub message: &'a str,
}
-pub trait Database: Send {
+pub trait Database: Send + Sync {
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>;
@@ -48,7 +45,7 @@ pub trait Database: Send {
}
// HashMap
-impl Database for HashMap<String, Vec<TellMessage>> {
+impl<S: ::std::hash::BuildHasher + Send + Sync> Database for HashMap<String, Vec<TellMessage>, S> {
fn insert_tell(&mut self, tell: &NewTellMessage) -> Result<(), TellError> {
let tell = TellMessage {
id: 0,
@@ -138,8 +135,8 @@ impl Database for Arc<Pool<ConnectionManager<MysqlConnection>>> {
}
fn delete_tells(&mut self, receiver: &str) -> Result<(), TellError> {
- use diesel;
use self::tells::columns;
+ use diesel;
let conn = &*self.get().context(ErrorKind::NoConnection)?;
diesel::delete(tells::table.filter(columns::receiver.eq(receiver)))
diff --git a/src/plugins/tell/mod.rs b/src/plugins/tell/mod.rs
index bdfb55c..3c0dc3d 100644
--- a/src/plugins/tell/mod.rs
+++ b/src/plugins/tell/mod.rs
@@ -1,97 +1,116 @@
-use irc::client::prelude::*;
+use std::marker::PhantomData;
-use std::time::Duration;
-use std::sync::Mutex;
+use antidote::RwLock;
+use irc::client::data::User;
+use irc::client::prelude::*;
-use time;
use chrono::NaiveDateTime;
use humantime::format_duration;
+use std::time::Duration;
+use time;
use plugin::*;
+use FrippyClient;
-use failure::Fail;
-use failure::ResultExt;
+use self::error::*;
use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
-use self::error::*;
+use failure::Fail;
+use failure::ResultExt;
+use log::{debug, trace};
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>,
+#[derive(PluginName)]
+pub struct Tell<T: Database, C> {
+ tells: RwLock<T>,
+ phantom: PhantomData<C>,
}
-impl<T: Database> Tell<T> {
- pub fn new(db: T) -> Tell<T> {
+impl<T: Database, C: FrippyClient> Tell<T, C> {
+ pub fn new(db: T) -> Self {
Tell {
- tells: Mutex::new(db),
+ tells: RwLock::new(db),
+ phantom: PhantomData,
}
}
- fn tell_command(
- &self,
- client: &IrcClient,
- command: PluginCommand,
- ) -> Result<String, TellError> {
+ fn tell_command(&self, client: &C, command: PluginCommand) -> Result<String, TellError> {
if command.tokens.len() < 2 {
- return Ok(self.invalid_command(client));
+ return Ok(self.invalid_command().to_owned());
}
- let receiver = &command.tokens[0];
+ let mut online = Vec::new();
+
+ let receivers = command.tokens[0].split(',').filter(|&s| !s.is_empty());
let sender = command.source;
- if receiver.eq_ignore_ascii_case(client.current_nickname()) {
- return Ok(String::from("I am right here!"));
- }
+ let mut no_receiver = true;
+ for receiver in receivers {
+ if receiver.eq_ignore_ascii_case(client.current_nickname())
+ || receiver.eq_ignore_ascii_case(&sender)
+ {
+ if !online.contains(&receiver) {
+ online.push(receiver);
+ }
+ continue;
+ }
- if receiver.eq_ignore_ascii_case(&sender) {
- return Ok(String::from("That's your name!"));
- }
+ let channels = client
+ .list_channels()
+ .expect("The irc crate should not be compiled with the \"nochanlists\" feature");
+
+ let find_receiver = |option: Option<Vec<User>>| {
+ option.and_then(|users| {
+ users
+ .into_iter()
+ .find(|user| user.get_nickname().eq_ignore_ascii_case(&receiver))
+ })
+ };
- 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));
- }
+ if channels
+ .iter()
+ .map(|channel| client.list_users(&channel))
+ .map(find_receiver)
+ .any(|option| option.is_some())
+ {
+ if !online.contains(&receiver) {
+ // online.push(receiver);
}
+ // TODO Change this when https://github.com/aatxe/irc/issues/136 gets resolved
+ //continue;
}
- }
- 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)?;
+ 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,
+ };
+
+ debug!("Saving tell for {:?}", receiver);
+ self.tells.write().insert_tell(&tell)?;
+ no_receiver = false;
+ }
- Ok(String::from("Got it!"))
+ Ok(if no_receiver && online.is_empty() {
+ String::from("Invalid receiver.")
+ } else {
+ match online.len() {
+ 0 => format!("Got it!"),
+ 1 => format!("{} is currently online.", online[0]),
+ _ => format!("{} are currently online.", online.join(", ")),
+ }
+ })
}
- fn on_namelist(
- &self,
- client: &IrcClient,
- channel: &str,
- ) -> Result<(), FrippyError> {
- let receivers = try_lock!(self.tells)
+ fn on_namelist(&self, client: &C, channel: &str) -> Result<(), FrippyError> {
+ let receivers = self
+ .tells
+ .read()
.get_receivers()
.context(FrippyErrorKind::Tell)?;
@@ -111,12 +130,15 @@ impl<T: Database> Tell<T> {
Ok(())
}
}
- fn send_tells(&self, client: &IrcClient, receiver: &str) -> Result<(), FrippyError> {
+
+ fn send_tells(&self, client: &C, receiver: &str) -> Result<(), FrippyError> {
+ trace!("Checking {} for tells", receiver);
+
if client.current_nickname() == receiver {
return Ok(());
}
- let mut tells = try_lock!(self.tells);
+ let mut tells = self.tells.write();
let tell_messages = match tells.get_tells(&receiver.to_lowercase()) {
Ok(t) => t,
@@ -135,14 +157,13 @@ impl<T: Database> Tell<T> {
let dur = now - Duration::new(tell.time.timestamp() as u64, 0);
let human_dur = format_duration(dur);
+ let message = format!(
+ "Tell from {} {} ago: {}",
+ tell.sender, human_dur, tell.message
+ );
+
client
- .send_notice(
- receiver,
- &format!(
- "Tell from {} {} ago: {}",
- tell.sender, human_dur, tell.message
- ),
- )
+ .send_notice(receiver, &message)
.context(FrippyErrorKind::Connection)?;
debug!(
@@ -158,36 +179,30 @@ impl<T: Database> Tell<T> {
Ok(())
}
- fn invalid_command(&self, client: &IrcClient) -> String {
- format!(
- "Incorrect Command. \
- Send \"{} tell help\" for help.",
- client.current_nickname()
- )
+ fn invalid_command(&self) -> &str {
+ "Incorrect Command. \
+ Send \"tell help\" for help."
}
- fn help(&self, client: &IrcClient) -> String {
- format!(
- "usage: {} tell user message\r\n\
- example: {0} tell Foobar Hello!",
- client.current_nickname()
- )
+ fn help(&self) -> &str {
+ "Used to send messages to offline users which they will receive when they come online.\r\n
+ usage: tell user message\r\n\
+ example: tell Foobar Hello!"
}
}
-impl<T: Database> Plugin for Tell<T> {
- fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
+impl<T: Database, C: FrippyClient> Plugin for Tell<T, C> {
+ type Client = C;
+ fn execute(&self, client: &Self::Client, 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::PRIVMSG(_, _) => self.send_tells(client, message.source_nickname().unwrap()),
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],
- )
+ self.on_namelist(client, &chan_info[chan_info.len() - 1])
} else {
Ok(())
}
@@ -201,43 +216,44 @@ impl<T: Database> Plugin for Tell<T> {
}
}
- fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
+ fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
panic!("Tell should not use threading")
}
- fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
+ fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
if command.tokens.is_empty() {
- return Ok(client
- .send_notice(&command.source, &self.invalid_command(client))
- .context(FrippyErrorKind::Connection)?);
+ client
+ .send_notice(&command.source, &self.invalid_command())
+ .context(FrippyErrorKind::Connection)?;
+ return Ok(());
}
let sender = command.source.to_owned();
- Ok(match command.tokens[0].as_ref() {
+ match command.tokens[0].as_ref() {
"help" => client
- .send_notice(&command.source, &self.help(client))
- .context(FrippyErrorKind::Connection)
- .into(),
+ .send_notice(&command.source, &self.help())
+ .context(FrippyErrorKind::Connection),
_ => 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(),
+ .context(FrippyErrorKind::Connection),
},
- }?)
+ }?;
+
+ Ok(())
}
- fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
+ fn evaluate(&self, _: &Self::Client, _: 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> {
+impl<T: Database, C: FrippyClient> fmt::Debug for Tell<T, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Tell {{ ... }}")
}
diff --git a/src/plugins/unicode.rs b/src/plugins/unicode.rs
new file mode 100644
index 0000000..56c8666
--- /dev/null
+++ b/src/plugins/unicode.rs
@@ -0,0 +1,98 @@
+extern crate unicode_names;
+
+use std::marker::PhantomData;
+
+use irc::client::prelude::*;
+
+use plugin::*;
+use FrippyClient;
+
+use error::ErrorKind as FrippyErrorKind;
+use error::FrippyError;
+use failure::Fail;
+
+#[derive(PluginName, Default, Debug)]
+pub struct Unicode<C> {
+ phantom: PhantomData<C>,
+}
+
+impl<C: FrippyClient> Unicode<C> {
+ pub fn new() -> Unicode<C> {
+ Unicode {
+ phantom: PhantomData,
+ }
+ }
+
+ fn get_name(&self, symbol: char) -> String {
+ match unicode_names::name(symbol) {
+ Some(sym) => sym.to_string().to_lowercase(),
+ None => String::from("UNKNOWN"),
+ }
+ }
+
+ fn format_response(&self, content: &str) -> String {
+ let character = content
+ .chars()
+ .next()
+ .expect("content contains at least one character");
+
+ let mut buf = [0; 4];
+
+ let byte_string = character
+ .encode_utf8(&mut buf)
+ .as_bytes()
+ .iter()
+ .map(|b| format!("{:#b}", b))
+ .collect::<Vec<String>>()
+ .join(",");
+
+ let name = self.get_name(character);
+
+ format!(
+ "{} is '{}' | UTF-8: {2:#x} ({2}), Bytes: [{3}]",
+ character, name, character as u32, byte_string
+ )
+ }
+}
+
+impl<C: FrippyClient> Plugin for Unicode<C> {
+ type Client = C;
+
+ fn execute(&self, _: &Self::Client, _: &Message) -> ExecutionStatus {
+ ExecutionStatus::Done
+ }
+
+ fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
+ panic!("Unicode should not use threading")
+ }
+
+ fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
+ if command.tokens.is_empty() || command.tokens[0].is_empty() {
+ let msg = "No non-space character was found.";
+
+ if let Err(e) = client.send_notice(command.source, msg) {
+ Err(e.context(FrippyErrorKind::Connection))?;
+ }
+
+ return Ok(());
+ }
+
+ let content = &command.tokens[0];
+
+ if let Err(e) = client.send_privmsg(command.target, &self.format_response(&content)) {
+ Err(e.context(FrippyErrorKind::Connection))?;
+ }
+
+ Ok(())
+ }
+
+ fn evaluate(&self, _: &Self::Client, command: PluginCommand) -> Result<String, String> {
+ let tokens = command.tokens;
+
+ if tokens.is_empty() {
+ return Err(String::from("No non-space character was found."));
+ }
+
+ Ok(self.format_response(&tokens[0]))
+ }
+}
diff --git a/src/plugins/url.rs b/src/plugins/url.rs
index bff840f..a884c66 100644
--- a/src/plugins/url.rs
+++ b/src/plugins/url.rs
@@ -1,50 +1,59 @@
extern crate htmlescape;
-extern crate regex;
+
+use std::marker::PhantomData;
+use std::time::Duration;
use irc::client::prelude::*;
-use self::regex::Regex;
+use regex::Regex;
use plugin::*;
-use utils;
+use utils::Url;
+use FrippyClient;
use self::error::*;
-use error::FrippyError;
use error::ErrorKind as FrippyErrorKind;
+use error::FrippyError;
use failure::Fail;
use failure::ResultExt;
lazy_static! {
- static ref RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
+ static ref URL_RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
+ static ref WORD_RE: Regex = Regex::new(r"(\w+)").unwrap();
}
#[derive(PluginName, Debug)]
-pub struct Url {
+pub struct UrlTitles<C> {
max_kib: usize,
+ phantom: PhantomData<C>,
}
-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 }
- }
+#[derive(Clone, Debug)]
+struct Title(String, Option<usize>);
- fn grep_url(&self, msg: &str) -> Option<String> {
- let captures = RE.captures(msg)?;
- debug!("Url captures: {:?}", captures);
+impl From<String> for Title {
+ fn from(title: String) -> Self {
+ Title(title, None)
+ }
+}
- Some(captures.get(2)?.as_str().to_owned())
+impl From<Title> for String {
+ fn from(title: Title) -> Self {
+ title.0
}
+}
- fn get_title<'a>(&self, body: &str) -> Result<String, UrlError> {
- let title = body.find("<title")
+impl Title {
+ fn find_by_delimiters(body: &str, delimiters: [&str; 3]) -> Result<Self, UrlError> {
+ let title = body
+ .find(delimiters[0])
.map(|tag| {
body[tag..]
- .find('>')
- .map(|offset| tag + offset + 1)
+ .find(delimiters[1])
+ .map(|offset| tag + offset + delimiters[1].len())
.map(|start| {
body[start..]
- .find("</title>")
+ .find(delimiters[2])
.map(|offset| start + offset)
.map(|end| &body[start..end])
})
@@ -52,55 +61,145 @@ impl Url {
.and_then(|s| s.and_then(|s| s))
.ok_or(ErrorKind::MissingTitle)?;
- debug!("Title: {:?}", title);
+ debug!("Found title {:?} with delimiters {:?}", title, delimiters);
- htmlescape::decode_html(title).map_err(|_| ErrorKind::HtmlDecoding.into())
+ htmlescape::decode_html(title)
+ .map(|t| t.into())
+ .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)?;
+ fn find_ogtitle(body: &str) -> Result<Self, UrlError> {
+ Self::find_by_delimiters(body, ["property=\"og:title\"", "content=\"", "\""])
+ }
+
+ fn find_title(body: &str) -> Result<Self, UrlError> {
+ Self::find_by_delimiters(body, ["<title", ">", "</title>"])
+ }
+
+ // TODO Improve logic
+ fn get_usefulness(self, url: &str) -> Self {
+ let mut usefulness = 0;
+ for word in WORD_RE.find_iter(&self.0) {
+ let w = word.as_str().to_lowercase();
+ if w.len() > 2 && !url.to_lowercase().contains(&w) {
+ usefulness += 1;
+ }
+ }
+
+ Title(self.0, Some(usefulness))
+ }
+
+ pub fn usefulness(&self) -> usize {
+ self.1.expect("Usefulness should be calculated already")
+ }
+
+ fn clean_up(self) -> Self {
+ Title(self.0.trim().replace('\n', "|").replace('\r', "|"), self.1)
+ }
+
+ pub fn find_clean_ogtitle(body: &str, url: &str) -> Result<Self, UrlError> {
+ let title = Self::find_ogtitle(body)?;
+ Ok(title.get_usefulness(url).clean_up())
+ }
+
+ pub fn find_clean_title(body: &str, url: &str) -> Result<Self, UrlError> {
+ let title = Self::find_title(body)?;
+ Ok(title.get_usefulness(url).clean_up())
+ }
+}
+
+impl<C: FrippyClient> UrlTitles<C> {
+ /// If a file is larger than `max_kib` KiB the download is stopped
+ pub fn new(max_kib: usize) -> Self {
+ UrlTitles {
+ max_kib,
+ phantom: PhantomData,
+ }
+ }
- let title = self.get_title(&body)?;
+ fn grep_url<'a>(&self, msg: &'a str) -> Option<Url<'a>> {
+ let captures = URL_RE.captures(msg)?;
+ debug!("Url captures: {:?}", captures);
+
+ Some(captures.get(2)?.as_str().into())
+ }
+
+ fn url(&self, text: &str) -> Result<String, UrlError> {
+ let url = self
+ .grep_url(text)
+ .ok_or(ErrorKind::MissingUrl)?
+ .max_kib(self.max_kib)
+ .timeout(Duration::from_secs(5));
+ let body = url.request().context(ErrorKind::Download)?;
+
+ let title = Title::find_clean_title(&body, url.as_str());
+ let og_title = Title::find_clean_ogtitle(&body, url.as_str());
+
+ let title = match (title, og_title) {
+ (Ok(title), Ok(og_title)) => {
+ if title.usefulness() > og_title.usefulness() {
+ title
+ } else {
+ og_title
+ }
+ }
+ (Ok(title), _) => title,
+ (_, Ok(title)) => title,
+ (Err(e), _) => Err(e)?,
+ };
+
+ if title.usefulness() == 0 {
+ Err(ErrorKind::UselessTitle)?;
+ }
- Ok(title.replace('\n', "|").replace('\r', "|"))
+ Ok(title.into())
}
}
-impl Plugin for Url {
- fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
+impl<C: FrippyClient> Plugin for UrlTitles<C> {
+ type Client = C;
+ fn execute(&self, _: &Self::Client, message: &Message) -> ExecutionStatus {
match message.command {
- Command::PRIVMSG(_, ref msg) => if RE.is_match(msg) {
- ExecutionStatus::RequiresThread
- } else {
- ExecutionStatus::Done
- },
+ Command::PRIVMSG(_, ref msg) => {
+ if URL_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 execute_threaded(
+ &self,
+ client: &Self::Client,
+ message: &Message,
+ ) -> Result<(), FrippyError> {
+ if let Command::PRIVMSG(_, ref content) = message.command {
+ let title = self.url(content).context(FrippyErrorKind::Url)?;
+ let response = format!("[URL] {}", title);
+
+ client
+ .send_privmsg(message.response_target().unwrap(), &response)
+ .context(FrippyErrorKind::Connection)?;
+ }
+
+ Ok(())
}
- fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
- Ok(client
+ fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
+ client
.send_notice(
&command.source,
"This Plugin does not implement any commands.",
)
- .context(FrippyErrorKind::Connection)?)
+ .context(FrippyErrorKind::Connection)?;
+
+ Ok(())
}
- fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> {
+ fn evaluate(&self, _: &Self::Client, command: PluginCommand) -> Result<String, String> {
self.url(&command.tokens[0])
.map_err(|e| e.cause().unwrap().to_string())
}
@@ -123,6 +222,10 @@ pub mod error {
#[fail(display = "No title was found")]
MissingTitle,
+ /// Useless title error
+ #[fail(display = "The titles found were not useful enough")]
+ UselessTitle,
+
/// Html decoding error
#[fail(display = "Failed to decode Html characters")]
HtmlDecoding,
diff --git a/src/utils.rs b/src/utils.rs
index 06156be..ef4d419 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,49 +1,100 @@
-use std::str;
+use std::borrow::Cow;
use std::io::{self, Read};
+use std::time::Duration;
-use reqwest::Client;
-use reqwest::header::Connection;
+use reqwest::header::{CONNECTION, HeaderValue};
+use reqwest::{Client, ClientBuilder};
-use failure::ResultExt;
use self::error::{DownloadError, ErrorKind};
+use failure::ResultExt;
+
+#[derive(Clone, Debug)]
+pub struct Url<'a> {
+ url: Cow<'a, str>,
+ max_kib: Option<usize>,
+ timeout: Option<Duration>,
+}
-/// 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)?,
+impl<'a> From<String> for Url<'a> {
+ fn from(url: String) -> Self {
+ Url {
+ url: Cow::from(url),
+ max_kib: None,
+ timeout: None,
+ }
+ }
+}
+
+impl<'a> From<&'a str> for Url<'a> {
+ fn from(url: &'a str) -> Self {
+ Url {
+ url: Cow::from(url),
+ max_kib: None,
+ timeout: None,
+ }
+ }
+}
+
+impl<'a> Url<'a> {
+ pub fn max_kib(mut self, limit: usize) -> Self {
+ self.max_kib = Some(limit);
+ self
+ }
+
+ pub fn timeout(mut self, timeout: Duration) -> Self {
+ self.timeout = Some(timeout);
+ self
+ }
+
+ /// 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 limit set by max_kib() was reached.
+ pub fn request(&self) -> Result<String, DownloadError> {
+ let client = if let Some(timeout) = self.timeout {
+ ClientBuilder::new().timeout(timeout).build().unwrap()
+ } else {
+ Client::new()
};
- bytes.extend_from_slice(&buf);
- written += len;
+ let mut response = client
+ .get(self.url.as_ref())
+ .header(CONNECTION, HeaderValue::from_static("close"))
+ .send()
+ .context(ErrorKind::Connection)?;
- // Check if the file is too large to download
- if let Some(max_kib) = max_kib {
- if written > max_kib * 1024 {
- Err(ErrorKind::DownloadLimit)?;
+ // 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[..len]);
+ written += len;
+
+ // Check if the file is too large to download
+ if let Some(max_kib) = self.max_kib {
+ if written > max_kib * 1024 {
+ Err(ErrorKind::DownloadLimit)?;
+ }
}
}
+
+ Ok(String::from_utf8_lossy(&bytes).into_owned())
}
- Ok(String::from_utf8_lossy(&bytes).into_owned())
+ pub fn as_str(&self) -> &str {
+ &self.url
+ }
}
pub mod error {