23 Commits
0.1 ... sql

Author SHA1 Message Date
AB
5d8d3441d2 Fix /sql command a lot. 2021-01-05 04:30:28 +03:00
AB
34fa54e6f4 add lock file. 2021-01-05 03:58:36 +03:00
7a66034381 Update handlers.rs 2021-01-04 16:40:46 -08:00
AB
47906fe22d Simplify SQL command. Add limit. 2021-01-05 03:30:21 +03:00
AB
83a6045b18 Fix typo. 2021-01-04 15:13:06 +03:00
AB
a1b272bd40 lint. 2021-01-03 22:42:49 +03:00
AB
3f00505659 Add /sql command. 2021-01-03 22:37:37 +03:00
AB
3fd5b124f3 Bump mystem lib. Lint code. 2020-12-31 01:56:20 +03:00
AB
17442819c4 Rewrite command parsing. 2020-12-31 01:42:36 +03:00
AB
7adc629292 Improve omedeto. Detect feminine by verbs. Fix 2020-12-30 15:25:33 +03:00
AB
39640139fa Improve omedeto. Detect feminine by verbs. 2020-12-30 15:12:17 +03:00
AB
0812c9e371 Improve omedeto. Nouns. 2020-12-30 14:30:53 +03:00
AB
f111f54606 Improve omedeto. Nouns. 2020-12-30 11:56:25 +03:00
AB
7e17851131 Improve omedeto 2020-12-30 11:50:19 +03:00
AB
b674ae5b15 Update omedeto 2020-12-30 09:58:17 +03:00
AB
412c3f313c Fix typo. 2020-12-30 09:47:33 +03:00
AB
1838674cab Fix typo. 2020-12-30 09:38:33 +03:00
AB
30d9d470cd Fix omedeto. 2020-12-30 09:24:15 +03:00
AB
3236131377 Move Mystem to external lib. add /omedeto 2020-12-29 17:09:49 +03:00
AB
9aaa8a94f1 Move Mystem to external lib. add /omedeto 2020-12-29 17:01:56 +03:00
AB
2d43a7d875 Fix mystem exec. 2020-12-16 23:25:25 +03:00
AB
00b15e01b6 Fix mystem exec. 2020-12-16 19:15:20 +03:00
AB
731232804b Fix workflow 2020-12-16 19:07:18 +03:00
10 changed files with 817 additions and 317 deletions

View File

@ -86,5 +86,4 @@ jobs:
--name ${artifact} \ --name ${artifact} \
--file ${artifact} --file ${artifact}
done done
./bin/linux/amd64/github-release upload -u house-of-vanity -r furumi --tag ${{ steps.get_version.outputs.FULL_TAG }} --name arch_linux_furumi-${{ steps.get_version.outputs.VERSION }}-x86_64.pkg.tar.zst --file ./furumi-x86_64.pkg.tar.zst

237
Cargo.lock generated
View File

@ -2,9 +2,9 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.4.6" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6789e291be47ace86a60303502173d84af8327e3627ecf334356ee0f87a164c" checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
@ -15,6 +15,17 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "async-trait"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -79,9 +90,9 @@ checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.65" version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -104,16 +115,6 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "console_error_panic_hook"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
dependencies = [
"cfg-if 0.1.10",
"wasm-bindgen",
]
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.6.4" version = "0.6.4"
@ -159,6 +160,7 @@ dependencies = [
name = "desubot" name = "desubot"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait",
"bytes", "bytes",
"env_logger", "env_logger",
"futures", "futures",
@ -169,11 +171,14 @@ dependencies = [
"log 0.4.11", "log 0.4.11",
"markov", "markov",
"multipart", "multipart",
"mystem",
"rand 0.7.3", "rand 0.7.3",
"regex",
"reqwest", "reqwest",
"rusqlite", "rusqlite",
"serde_json", "serde_json",
"sha1", "sha1",
"sqlparser",
"subprocess", "subprocess",
"telegram-bot", "telegram-bot",
"tokio", "tokio",
@ -184,9 +189,9 @@ dependencies = [
[[package]] [[package]]
name = "dtoa" name = "dtoa"
version = "0.4.6" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
[[package]] [[package]]
name = "either" name = "either"
@ -393,11 +398,11 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.15" version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 1.0.0",
"libc", "libc",
"wasi", "wasi",
] ]
@ -460,9 +465,9 @@ dependencies = [
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" checksum = "84129d298a6d57d246960ff8eb831ca4af3f96d29e2e28848dae275408658e26"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@ -567,9 +572,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.6.0" version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
dependencies = [ dependencies = [
"autocfg 1.0.1", "autocfg 1.0.1",
"hashbrown", "hashbrown",
@ -601,15 +606,15 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.6" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.45" version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -632,9 +637,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.80" version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
@ -737,9 +742,9 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.6.22" version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 0.1.10",
"fuchsia-zircon", "fuchsia-zircon",
@ -748,7 +753,7 @@ dependencies = [
"kernel32-sys", "kernel32-sys",
"libc", "libc",
"log 0.4.11", "log 0.4.11",
"miow 0.2.1", "miow 0.2.2",
"net2", "net2",
"slab", "slab",
"winapi 0.2.8", "winapi 0.2.8",
@ -779,9 +784,9 @@ dependencies = [
[[package]] [[package]]
name = "miow" name = "miow"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
dependencies = [ dependencies = [
"kernel32-sys", "kernel32-sys",
"net2", "net2",
@ -813,10 +818,21 @@ dependencies = [
] ]
[[package]] [[package]]
name = "native-tls" name = "mystem"
version = "0.2.6" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fcc7939b5edc4e4f86b1b4a04bb1498afaaf871b1a6691838ed06fcb48d3a3f" checksum = "cac69b16b860268fce77cd499251a1149c0d4d2295638cf557a4102857c3815f"
dependencies = [
"log 0.4.11",
"serde_json",
"subprocess",
]
[[package]]
name = "native-tls"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
@ -832,9 +848,9 @@ dependencies = [
[[package]] [[package]]
name = "net2" name = "net2"
version = "0.2.35" version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 0.1.10",
"libc", "libc",
@ -868,12 +884,12 @@ checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.30" version = "0.10.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if 0.1.10", "cfg-if 1.0.0",
"foreign-types", "foreign-types",
"lazy_static", "lazy_static",
"libc", "libc",
@ -888,9 +904,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.58" version = "0.9.60"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6"
dependencies = [ dependencies = [
"autocfg 1.0.1", "autocfg 1.0.1",
"cc", "cc",
@ -901,9 +917,9 @@ dependencies = [
[[package]] [[package]]
name = "ordered-float" name = "ordered-float"
version = "1.1.0" version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3741934be594d77de1c8461ebcbbe866f585ea616a9753aa78f2bdc69f0e4579" checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7"
dependencies = [ dependencies = [
"num-traits", "num-traits",
] ]
@ -1062,9 +1078,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.7" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -1260,9 +1276,9 @@ dependencies = [
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.10.9" version = "0.10.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb15d6255c792356a0f578d8a645c677904dc02e862bebe2ecc18e0c01b9a0ce" checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c"
dependencies = [ dependencies = [
"base64 0.13.0", "base64 0.13.0",
"bytes", "bytes",
@ -1289,16 +1305,15 @@ dependencies = [
"url", "url",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-bindgen-test",
"web-sys", "web-sys",
"winreg", "winreg",
] ]
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.16.18" version = "0.16.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70017ed5c555d79ee3538fc63ca09c70ad8f317dcadc1adc2c496b60c22bb24f" checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1365,12 +1380,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]] [[package]]
name = "sct" name = "sct"
version = "0.6.0" version = "0.6.0"
@ -1427,9 +1436,9 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.117" version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -1446,9 +1455,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.117" version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1457,9 +1466,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.59" version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -1498,9 +1507,9 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.2.2" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -1519,19 +1528,18 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.5.1" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.3.17" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902" checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"redox_syscall",
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -1541,6 +1549,15 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "sqlparser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a3da41f3ddf62cbf92635ace62dd037fad9a91c6871c514fbd404e2059f27d"
dependencies = [
"log 0.4.11",
]
[[package]] [[package]]
name = "subprocess" name = "subprocess"
version = "0.2.6" version = "0.2.6"
@ -1553,9 +1570,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.51" version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b4f34193997d92804d359ed09953e25d5138df6bcc055a71bf68ee89fdf9223" checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1641,9 +1658,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "0.2.23" version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6d7ad61edd59bfcc7e80dababf0f4aed2e6d5e0ba1659356ae889752dfc12ff" checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@ -1848,9 +1865,9 @@ dependencies = [
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.10" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
[[package]] [[package]]
name = "version_check" name = "version_check"
@ -1882,11 +1899,11 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.68" version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 1.0.0",
"serde", "serde",
"serde_json", "serde_json",
"wasm-bindgen-macro", "wasm-bindgen-macro",
@ -1894,9 +1911,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.68" version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"lazy_static", "lazy_static",
@ -1909,11 +1926,11 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.18" version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 1.0.0",
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
@ -1921,9 +1938,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.68" version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -1931,9 +1948,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.68" version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1944,39 +1961,15 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.68" version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
[[package]]
name = "wasm-bindgen-test"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34d1cdc8b98a557f24733d50a1199c4b0635e465eecba9c45b214544da197f64"
dependencies = [
"console_error_panic_hook",
"js-sys",
"scoped-tls",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test-macro",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8fb9c67be7439ee8ab1b7db502a49c05e51e2835b66796c705134d9b8e1a585"
dependencies = [
"proc-macro2",
"quote",
]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.45" version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -1984,9 +1977,9 @@ dependencies = [
[[package]] [[package]]
name = "webpki" name = "webpki"
version = "0.21.3" version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
dependencies = [ dependencies = [
"ring", "ring",
"untrusted", "untrusted",
@ -2056,9 +2049,9 @@ dependencies = [
[[package]] [[package]]
name = "yaml-rust" name = "yaml-rust"
version = "0.4.4" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d" checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [ dependencies = [
"linked-hash-map", "linked-hash-map",
] ]

View File

@ -21,8 +21,9 @@ hyper-tls = { version = "0.4", optional = true }
futures = "0.3" futures = "0.3"
hyper-rustls = { version = "0.19", optional = true } hyper-rustls = { version = "0.19", optional = true }
rusqlite = { version = "0.24.1", features = ["bundled"]} rusqlite = { version = "0.24.2", features = ["bundled"]}
html-escape = "0.2" html-escape = "0.2"
regex = "1"
reqwest = "0.10.9" reqwest = "0.10.9"
uuid = { version = "0.8", features = ["v4"] } uuid = { version = "0.8", features = ["v4"] }
sha1 = "*" sha1 = "*"
@ -32,3 +33,6 @@ subprocess = "0.2.6"
serde_json = "1.0" serde_json = "1.0"
markov = "1.1.0" markov = "1.1.0"
rand = "0.7.3" rand = "0.7.3"
mystem = "0.2.1"
async-trait = "0.1.42"
sqlparser = "0.7.0"

5
README
View File

@ -11,5 +11,6 @@ Telegram bot with light group statistic and heavy spy features.
== TODO == == TODO ==
* Syntax highlighting for code exported to image. * Syntax highlighting for code exported to image.
== Notes == == Important ==
* Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH. On Windows it may be placed on working directory. Both Linux and Windows mystem binary is in repo. * Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH.
On Windows it may be placed on working directory. Both Linux and Windows mystem binary is in repo.

View File

@ -1,12 +1,184 @@
#![allow(unused_variables)]
use crate::db; use crate::db;
use crate::errors::Error; use crate::errors::Error;
use crate::errors::Error::{SQLITE3Error, SQLInvalidCommand};
use async_trait::async_trait;
use html_escape::encode_text; use html_escape::encode_text;
use markov::Chain; use markov::Chain;
use mystem::Case::Nominative;
use mystem::Gender::Feminine;
use mystem::MyStem;
use mystem::Person::First;
use mystem::Tense::{Inpresent, Past};
use rand::seq::SliceRandom;
use rand::Rng; use rand::Rng;
use regex::Regex;
use sqlparser::ast::Statement;
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
use telegram_bot::prelude::*; use telegram_bot::prelude::*;
use telegram_bot::{Api, Message, ParseMode}; use telegram_bot::{Api, Message, ParseMode};
pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> { pub struct Here {
pub data: String,
}
pub struct Top {
pub data: String,
}
pub struct MarkovAll {
pub data: String,
}
pub struct Markov {
pub data: String,
}
pub struct Omedeto {
pub data: String,
}
pub struct Sql {
pub data: String,
}
#[async_trait]
pub trait Execute {
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error>;
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error>;
async fn exec_mystem(
&self,
api: &Api,
message: &Message,
mystem: &mut MyStem,
) -> Result<(), Error>;
}
#[async_trait]
impl Execute for Sql {
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
unimplemented!()
}
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
let mut sql = self.data.clone();
let is_head = if sql.starts_with('-') {
sql = sql.replacen("-", "", 1);
false
} else {
true
};
let dialect = GenericDialect {};
let ast: Vec<Statement> = match Parser::parse_sql(&dialect, &sql) {
Ok(ast) => ast,
Err(_) => {
warn!("Invalid SQL - {}", sql);
return Err(SQLInvalidCommand);
}
};
match ast.len() {
l if l > 1 => {
return Err(Error::SQLBannedCommand(
"🚫 One statement per message allowed 🚫".into(),
))
}
_ => (),
}
match ast[0] {
sqlparser::ast::Statement::Query { .. } => {}
_ => {
return Err(Error::SQLBannedCommand(
"🚫 SELECT requests allowed only 🚫".into(),
))
}
}
let conn = db::open()?;
let mut stmt = conn.prepare_cached(&sql)?;
let mut rows = match stmt.query(rusqlite::NO_PARAMS) {
Err(e) => return Err(SQLITE3Error(e)),
Ok(rows) => rows,
};
let mut res: Vec<Vec<String>> = match rows.column_names() {
Some(n) => vec![n
.into_iter()
.map(|s| {
let t = String::from(s);
if t.len() > 10 {
"EMSGSIZE".to_string()
} else {
t
}
})
.collect()],
None => return Err(SQLInvalidCommand),
};
let index_count = match rows.column_count() {
Some(c) => c,
None => return Err(SQLInvalidCommand),
};
while let Some(row) = rows.next().unwrap() {
let mut tmp: Vec<String> = Vec::new();
for i in 0..index_count {
match row.get(i).unwrap_or(None) {
Some(rusqlite::types::Value::Text(t)) => tmp.push(t),
Some(rusqlite::types::Value::Integer(t)) => tmp.push(t.to_string()),
Some(rusqlite::types::Value::Blob(_)) => tmp.push("Binary".to_string()),
Some(rusqlite::types::Value::Real(t)) => tmp.push(t.to_string()),
Some(rusqlite::types::Value::Null) => tmp.push("Null".to_string()),
None => tmp.push("Null".to_string()),
};
}
res.push(tmp);
}
if res.len() > 100 {
return Err(Error::SQLResultTooLong(
"SQL result too long. Lines limit is 100. Use LIMIT".to_string(),
));
}
// add Header
let mut msg = if is_head {
let mut x = String::from("<b>");
for head in res[0].iter() {
x = format!("{} {}", x, head);
}
format!("{}{}", x, "</b>\n")
} else {
String::new()
};
// remove header
res.remove(0);
msg = format!("{}{}", msg, "<pre>");
for line in res.iter() {
for field in line.iter() {
msg = format!("{}{}", msg, format!("{} ", field));
}
msg = format!("{}{}", msg, "\n");
}
msg = format!("{}{}", msg, "</pre>");
msg = if msg.len() > 4096 {
"🚫 Result is too big. Use LIMIT 🚫".into()
} else {
msg
};
Ok(msg)
}
#[allow(unused_variables)]
async fn exec_mystem(
&self,
api: &Api,
message: &Message,
mystem: &mut MyStem,
) -> Result<(), Error> {
unimplemented!()
}
}
#[async_trait]
impl Execute for Here {
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap(); let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap();
for u in &members { for u in &members {
debug!("Found user {:?} in chat {}", u, message.chat.id()); debug!("Found user {:?} in chat {}", u, message.chat.id());
@ -31,12 +203,27 @@ pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
Ok(_) => debug!("/here command sent to {}", message.chat.id()), Ok(_) => debug!("/here command sent to {}", message.chat.id()),
Err(_) => warn!("/here command sent failed to {}", message.chat.id()), Err(_) => warn!("/here command sent failed to {}", message.chat.id()),
} }
//api.send(message.chat.text("Text to message chat")).await?;
//api.send(message.from.text("Private text")).await?;
Ok(()) Ok(())
}
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
unimplemented!()
}
#[allow(unused_variables)]
async fn exec_mystem(
&self,
api: &Api,
message: &Message,
mystem: &mut MyStem,
) -> Result<(), Error> {
unimplemented!()
}
} }
pub(crate) async fn top(api: Api, message: Message) -> Result<(), Error> { #[async_trait]
impl Execute for Top {
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
let top = db::get_top(&message).await?; let top = db::get_top(&message).await?;
let mut msg = "<b>Your top using words:</b>\n<pre>".to_string(); let mut msg = "<b>Your top using words:</b>\n<pre>".to_string();
let mut counter = 1; let mut counter = 1;
@ -55,13 +242,28 @@ pub(crate) async fn top(api: Api, message: Message) -> Result<(), Error> {
Ok(_) => debug!("/top command sent to {}", message.chat.id()), Ok(_) => debug!("/top command sent to {}", message.chat.id()),
Err(_) => warn!("/top command sent failed to {}", message.chat.id()), Err(_) => warn!("/top command sent failed to {}", message.chat.id()),
} }
//api.send(message.chat.text("Text to message chat")).await?;
//api.send(message.from.text("Private text")).await?;
Ok(()) Ok(())
}
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
unimplemented!()
}
#[allow(unused_variables)]
async fn exec_mystem(
&self,
api: &Api,
message: &Message,
mystem: &mut MyStem,
) -> Result<(), Error> {
unimplemented!()
}
} }
pub(crate) async fn markov_all(api: Api, message: Message) -> Result<(), Error> { #[async_trait]
let messages = db::get_random_messages().await?; impl Execute for MarkovAll {
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
let messages = db::get_messages_random_all().await?;
let mut chain = Chain::new(); let mut chain = Chain::new();
chain.feed(messages); chain.feed(messages);
let mut sentences = chain.generate(); let mut sentences = chain.generate();
@ -79,10 +281,27 @@ pub(crate) async fn markov_all(api: Api, message: Message) -> Result<(), Error>
//api.send(message.chat.text("Text to message chat")).await?; //api.send(message.chat.text("Text to message chat")).await?;
//api.send(message.from.text("Private text")).await?; //api.send(message.from.text("Private text")).await?;
Ok(()) Ok(())
}
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
unimplemented!()
}
#[allow(unused_variables)]
async fn exec_mystem(
&self,
api: &Api,
message: &Message,
mystem: &mut MyStem,
) -> Result<(), Error> {
unimplemented!()
}
} }
pub(crate) async fn markov(api: Api, message: Message) -> Result<(), Error> { #[async_trait]
let messages = db::get_random_messages_group(&message).await?; impl Execute for Markov {
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
let messages = db::get_messages_random_group(&message).await?;
let mut chain = Chain::new(); let mut chain = Chain::new();
chain.feed(messages); chain.feed(messages);
let mut sentences = chain.generate(); let mut sentences = chain.generate();
@ -100,4 +319,225 @@ pub(crate) async fn markov(api: Api, message: Message) -> Result<(), Error> {
//api.send(message.chat.text("Text to message chat")).await?; //api.send(message.chat.text("Text to message chat")).await?;
//api.send(message.from.text("Private text")).await?; //api.send(message.from.text("Private text")).await?;
Ok(()) Ok(())
}
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
unimplemented!()
}
#[allow(unused_variables)]
async fn exec_mystem(
&self,
api: &Api,
message: &Message,
mystem: &mut MyStem,
) -> Result<(), Error> {
unimplemented!()
}
}
#[async_trait]
impl Execute for Omedeto {
#[allow(unused_variables)]
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
unimplemented!()
}
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
unimplemented!()
}
#[warn(unused_must_use)]
async fn exec_mystem(
&self,
api: &Api,
message: &Message,
mystem: &mut MyStem,
) -> Result<(), Error> {
let all_msg = db::get_messages_user_all(&message).await?;
let re = Regex::new(r"^[яЯ] [а-яА-Я]+(-[а-яА-Я]+(_[а-яА-Я]+)*)*").unwrap();
let mut nouns: Vec<String> = all_msg
.iter()
.filter(|m| re.is_match(m))
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
.filter(|m| {
let stem = mystem.stemming(m.clone()).unwrap_or_default();
if stem.is_empty() {
false
} else if stem[0].lex.is_empty() {
false
} else {
match stem[0].lex[0].grammem.part_of_speech {
mystem::PartOfSpeech::Noun => stem[0].lex[0]
.grammem
.facts
.contains(&mystem::Fact::Case(Nominative)),
_ => false,
}
}
})
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
.collect();
nouns.sort();
nouns.dedup();
nouns.shuffle(&mut rand::thread_rng());
//debug!("Found {} nouns. {:#?}", nouns.len(), nouns);
let mut verbs_p: Vec<String> = all_msg
.iter()
.filter(|m| re.is_match(m))
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
.filter(|m| {
let stem = mystem.stemming(m.clone()).unwrap_or_default();
if stem.is_empty() {
false
} else if stem[0].lex.is_empty() {
false
} else {
match stem[0].lex[0].grammem.part_of_speech {
mystem::PartOfSpeech::Verb => stem[0].lex[0]
.grammem
.facts
.contains(&mystem::Fact::Tense(Past)),
_ => false,
}
}
})
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
.collect();
verbs_p.sort();
verbs_p.dedup();
verbs_p.shuffle(&mut rand::thread_rng());
//debug!("Found {} past verbs. {:#?}", verbs_p.len(), verbs_p);
let mut verbs_i: Vec<String> = all_msg
.iter()
.filter(|m| re.is_match(m))
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
.filter(|m| {
let stem = mystem.stemming(m.clone()).unwrap_or_default();
if stem.is_empty() {
false
} else if stem[0].lex.is_empty() {
false
} else {
match stem[0].lex[0].grammem.part_of_speech {
mystem::PartOfSpeech::Verb => {
stem[0].lex[0]
.grammem
.facts
.contains(&mystem::Fact::Tense(Inpresent))
&& stem[0].lex[0]
.grammem
.facts
.contains(&mystem::Fact::Person(First))
}
_ => false,
}
}
})
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
.collect();
verbs_i.sort();
verbs_i.dedup();
verbs_i.shuffle(&mut rand::thread_rng());
//debug!("Found {} inpresent verbs. {:#?}", verbs_i.len(), verbs_i);
if nouns.is_empty() {
nouns.push(message.from.first_name.to_string());
}
let start: Vec<String> = vec![
"С новым годом".into(),
"С НГ тебя".into(),
"Поздравляю".into(),
"Поздравляю с НГ".into(),
];
let placeholders: Vec<String> = vec![
"[ДАННЫЕ УДАЛЕНЫ]".into(),
"[СЕКРЕТНО]".into(),
"[НЕТ ДАННЫХ]".into(),
"[ОШИБКА ДОСТУПА]".into(),
];
//debug!("Nouns: {:#?}", nouns);
//debug!("Verbs: {:#?}", verbs);
let fem = {
let mut fm = 0;
let mut mu = 0;
all_msg
.clone()
.into_iter()
.filter(|m| re.is_match(m))
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
.map(|m| {
let stem = mystem.stemming(m.clone()).unwrap_or_default();
if stem.is_empty() {
()
} else if stem[0].lex.is_empty() {
()
} else {
match stem[0].lex[0].grammem.part_of_speech {
mystem::PartOfSpeech::Verb => {
match stem[0].lex[0]
.grammem
.facts
.contains(&mystem::Fact::Tense(Past))
{
true => {
if stem[0].lex[0]
.grammem
.facts
.contains(&mystem::Fact::Gender(Feminine))
{
fm = fm + 1;
} else {
mu = mu + 1;
}
}
false => (),
}
}
_ => (),
}
}
})
.for_each(drop);
//debug!("fm - {}, mu - {}", fm, mu);
if fm >= mu {
true
} else {
false
}
};
//debug!("Is Feminine - {}", fem);
let result = format!(
"{} {} известн{} как {}, {}, а так же конечно {}. В прошедшем году ты часто давал{} нам знать, что ты {}, {} и {}. Нередко ты говорил{} я {}, я {} или даже я {}. =*",
start.choose(&mut rand::thread_rng()).unwrap(),
message.from.first_name.to_string(),
{ if fem { "ая" } else { "ый" } },
nouns.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
nouns.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
nouns.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
{ if fem { "а" } else { "" } },
verbs_p.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
verbs_p.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
verbs_p.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
{ if fem { "а" } else { "" } },
verbs_i.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
verbs_i.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
verbs_i.pop().unwrap_or(placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
);
match api
.send(
message
.text_reply(result.trim())
.parse_mode(ParseMode::Html),
)
.await
{
Ok(_) => debug!("/omedeto command sent to {}", message.chat.id()),
Err(_) => warn!("/omedeto command sent failed to {}", message.chat.id()),
}
Ok(())
}
} }

View File

@ -1,5 +1,4 @@
use crate::errors; use crate::errors;
use crate::mystem;
use crate::utils; use crate::utils;
use rusqlite::{named_params, params, Connection, Error, Result}; use rusqlite::{named_params, params, Connection, Error, Result};
use std::time::SystemTime; use std::time::SystemTime;
@ -82,7 +81,7 @@ pub(crate) fn get_conf(id: telegram_bot::ChatId) -> Result<Conf, errors::Error>
} }
} }
/* #[allow(dead_code)]
pub(crate) fn get_confs() -> Result<Vec<Conf>> { pub(crate) fn get_confs() -> Result<Vec<Conf>> {
let conn = open()?; let conn = open()?;
let mut stmt = conn.prepare("SELECT id, title, date FROM conf")?; let mut stmt = conn.prepare("SELECT id, title, date FROM conf")?;
@ -101,8 +100,8 @@ pub(crate) fn get_confs() -> Result<Vec<Conf>> {
Ok(confs) Ok(confs)
} }
*/
pub(crate) async fn get_random_messages() -> Result<Vec<String>, Error> { pub(crate) async fn get_messages_random_all() -> Result<Vec<String>, Error> {
let conn = open()?; let conn = open()?;
let mut stmt = conn.prepare_cached("SELECT text FROM messages ORDER BY RANDOM() LIMIT 50")?; let mut stmt = conn.prepare_cached("SELECT text FROM messages ORDER BY RANDOM() LIMIT 50")?;
let mut rows = stmt.query_named(named_params![])?; let mut rows = stmt.query_named(named_params![])?;
@ -114,17 +113,18 @@ pub(crate) async fn get_random_messages() -> Result<Vec<String>, Error> {
Ok(messages) Ok(messages)
} }
pub(crate) async fn get_random_messages_group( pub(crate) async fn get_messages_random_group(
message: &telegram_bot::Message message: &telegram_bot::Message,
) -> Result<Vec<String>, Error> { ) -> Result<Vec<String>, Error> {
let conf_id = i64::from(message.chat.id()); let conf_id = i64::from(message.chat.id());
let conn = open()?; let conn = open()?;
let mut stmt = conn.prepare_cached(" let mut stmt = conn.prepare_cached(
"
SELECT m.text FROM messages m SELECT m.text FROM messages m
LEFT JOIN relations r ON r.msg_id = m.id LEFT JOIN relations r ON r.msg_id = m.id
WHERE r.conf_id = :conf_id WHERE r.conf_id = :conf_id
ORDER BY RANDOM() LIMIT 50 ORDER BY RANDOM() LIMIT 50
" ",
)?; )?;
let mut rows = stmt.query_named(named_params! {":conf_id": conf_id})?; let mut rows = stmt.query_named(named_params! {":conf_id": conf_id})?;
let mut messages = Vec::new(); let mut messages = Vec::new();
@ -135,6 +135,51 @@ pub(crate) async fn get_random_messages_group(
Ok(messages) Ok(messages)
} }
#[allow(dead_code)]
pub(crate) async fn get_messages_user_group(
message: &telegram_bot::Message,
) -> Result<Vec<String>, Error> {
let conf_id = i64::from(message.chat.id());
let user_id = i64::from(message.from.id);
let conn = open()?;
let mut stmt = conn.prepare_cached(
"
SELECT m.text FROM messages m
LEFT JOIN relations r ON r.msg_id = m.id
WHERE r.conf_id = :conf_id
AND r.user_id = :user_id
",
)?;
let mut rows = stmt.query_named(named_params! {":conf_id": conf_id, ":user_id": user_id})?;
let mut messages = Vec::new();
while let Some(row) = rows.next()? {
messages.push(row.get(0)?)
}
Ok(messages)
}
pub(crate) async fn get_messages_user_all(
message: &telegram_bot::Message,
) -> Result<Vec<String>, Error> {
let user_id = i64::from(message.from.id);
let conn = open()?;
let mut stmt = conn.prepare_cached(
"
SELECT m.text FROM messages m
LEFT JOIN relations r ON r.msg_id = m.id
WHERE r.user_id = :user_id
",
)?;
let mut rows = stmt.query_named(named_params! {":user_id": user_id})?;
let mut messages = Vec::new();
while let Some(row) = rows.next()? {
messages.push(row.get(0)?)
}
Ok(messages)
}
pub(crate) fn get_members(id: telegram_bot::ChatId) -> Result<Vec<telegram_bot::User>> { pub(crate) fn get_members(id: telegram_bot::ChatId) -> Result<Vec<telegram_bot::User>> {
let conn = open()?; let conn = open()?;
let mut stmt = conn.prepare_cached( let mut stmt = conn.prepare_cached(
@ -300,7 +345,6 @@ pub(crate) async fn get_file(file_id: String) -> Result<i64, errors::Error> {
Ok(id) => Ok(id), Ok(id) => Ok(id),
Err(_) => Err(errors::Error::FileNotFound), Err(_) => Err(errors::Error::FileNotFound),
}; };
file_rowid file_rowid
} }
@ -355,6 +399,7 @@ async fn add_relation(word_id: i64, msg_id: i64, message: &Message) -> Result<i6
Ok(rowid) Ok(rowid)
} }
#[allow(unused_must_use)]
pub(crate) async fn add_sentence( pub(crate) async fn add_sentence(
message: &telegram_bot::Message, message: &telegram_bot::Message,
mystem: &mut mystem::MyStem, mystem: &mut mystem::MyStem,
@ -373,18 +418,21 @@ pub(crate) async fn add_sentence(
}; };
// Save stemmed words // Save stemmed words
let words = mystem.stemming(text).await?; let words = mystem.stemming(text)?;
conn.execute("BEGIN TRANSACTION", params![]); conn.execute("BEGIN TRANSACTION", params![]);
for word in words { for word in words {
match add_word(&word).await { if word.lex.is_empty() {
continue;
}
match add_word(&word.lex[0].lex).await {
Ok(id) => { Ok(id) => {
debug!("Added {}: rowid: {}", &word, id); debug!("Added {}: rowid: {}", &word.lex[0].lex, id);
match add_relation(id, msg_rowid, message).await { match add_relation(id, msg_rowid, message).await {
Ok(_) => {} Ok(_) => {}
Err(e) => panic!("SQLITE3 Error: Relations failed: {:?}", e), Err(e) => panic!("SQLITE3 Error: Relations failed: {:?}", e),
} }
} }
Err(_) => debug!("Word {} is in stop list.", &word), Err(_) => debug!("Word {} is in stop list.", &word.lex[0].lex),
} }
} }
conn.execute("END TRANSACTION", params![]); conn.execute("END TRANSACTION", params![]);
@ -423,5 +471,3 @@ pub(crate) async fn get_top(
} }
Ok(top) Ok(top)
} }

View File

@ -1,3 +1,4 @@
use mystem::AppError as mystem_error;
use reqwest::Error as reqwest_error; use reqwest::Error as reqwest_error;
use rusqlite::Error as sqlite_error; use rusqlite::Error as sqlite_error;
use serde_json::Error as serde_error; use serde_json::Error as serde_error;
@ -18,7 +19,12 @@ pub enum Error {
FileNotFound, FileNotFound,
JsonParseError(serde_error), JsonParseError(serde_error),
PopenError(popen_error), PopenError(popen_error),
MystemError(mystem_error),
SQLBannedCommand(String),
SQLInvalidCommand,
SQLResultTooLong(String),
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "An error occurred.") write!(f, "An error occurred.")
@ -60,3 +66,9 @@ impl From<popen_error> for Error {
return Error::PopenError(e); return Error::PopenError(e);
} }
} }
impl From<mystem_error> for Error {
fn from(e: mystem_error) -> Error {
return Error::MystemError(e);
}
}

View File

@ -1,10 +1,10 @@
use telegram_bot::*; //use crate::commands::Command;
use crate::mystem::MyStem; use crate::commands::{Execute, Here, Markov, MarkovAll, Omedeto, Sql, Top};
use crate::errors;
use crate::db; use crate::db;
use crate::commands; use crate::errors;
use crate::utils; use crate::utils;
use mystem::MyStem;
use telegram_bot::*;
pub async fn handler( pub async fn handler(
api: Api, api: Api,
@ -13,7 +13,6 @@ pub async fn handler(
mystem: &mut MyStem, mystem: &mut MyStem,
me: User, me: User,
) -> Result<(), errors::Error> { ) -> Result<(), errors::Error> {
match message.kind { match message.kind {
MessageKind::Text { ref data, .. } => { MessageKind::Text { ref data, .. } => {
let title = utils::get_title(&message); let title = utils::get_title(&message);
@ -26,12 +25,76 @@ pub async fn handler(
data data
); );
db::add_sentence(&message, mystem).await?; db::add_sentence(&message, mystem).await?;
match data.as_str() { let cleaned_message = data.replace(&format!("@{}", me.clone().username.unwrap()), "");
"/here" => commands::here(api, message).await?, match cleaned_message.as_str() {
"/top" => commands::top(api, message).await?, s if s.contains("/here") => {
"/stat" => commands::top(api, message).await?, Here {
"/markov_all" => commands::markov_all(api, message).await?, data: "".to_string(),
"/markov" => commands::markov(api, message).await?, }
.exec(&api, &message)
.await?
}
s if s.to_string().starts_with("/sql") => match {
Sql {
data: s.replace("/sql ", ""),
}
.exec_with_result(&api, &message)
.await
} {
Ok(msg) => {
let _ = api
.send(
message
.text_reply(msg)
.parse_mode(ParseMode::Html),
)
.await?;
},
Err(e) => {
let _ = api
.send(
message
.text_reply(format!("Error: {:#?}", e))
.parse_mode(ParseMode::Html),
)
.await?;
}
},
"/top" => {
Top {
data: "".to_string(),
}
.exec(&api, &message)
.await?
}
"/stat" => {
Top {
data: "".to_string(),
}
.exec(&api, &message)
.await?
}
"/markov_all" => {
MarkovAll {
data: "".to_string(),
}
.exec(&api, &message)
.await?
}
"/markov" => {
Markov {
data: "".to_string(),
}
.exec(&api, &message)
.await?
}
"/omedeto" => {
Omedeto {
data: "".to_string(),
}
.exec_mystem(&api, &message, mystem)
.await?
}
_ => (), _ => (),
} }
} }

View File

@ -9,16 +9,21 @@ use env_logger::Env;
mod commands; mod commands;
mod db; mod db;
mod errors; mod errors;
mod mystem;
mod utils;
mod handlers; mod handlers;
mod utils;
use mystem::MyStem; use mystem::MyStem;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), errors::Error> { async fn main() -> Result<(), errors::Error> {
env_logger::from_env(Env::default().default_filter_or("info")).init(); env_logger::from_env(Env::default().default_filter_or("info")).init();
let mut mystem = MyStem::new()?; let mut mystem = match MyStem::new() {
Ok(mystem) => mystem,
Err(e) => {
error!("MyStem init error. {:?}", e);
process::exit(0x0002);
}
};
match db::update_scheme() { match db::update_scheme() {
Ok(_) => {} Ok(_) => {}
Err(e) => panic!("Database error: {:?}", e), Err(e) => panic!("Database error: {:?}", e),
@ -33,13 +38,23 @@ async fn main() -> Result<(), errors::Error> {
let api = Api::new(token.clone()); let api = Api::new(token.clone());
let mut stream = api.stream(); let mut stream = api.stream();
let me = api.send(GetMe).await?; let me = api.send(GetMe).await?;
info!("GetMe result: Username: {}, First Name: {}, ID {}", me.username.as_ref().unwrap(), me.first_name, me.id); info!(
"GetMe result: Username: {}, First Name: {}, ID {}",
me.username.as_ref().unwrap(),
me.first_name,
me.id
);
while let Some(update) = stream.next().await { while let Some(update) = stream.next().await {
let update = update?; let update = update?;
if let UpdateKind::Message(message) = update.kind { if let UpdateKind::Message(message) = update.kind {
db::add_conf(message.clone()).await?; db::add_conf(message.clone()).await?;
db::add_user(message.clone()).await?; db::add_user(message.clone()).await?;
handlers::handler(api.clone(), message, token.clone(), &mut mystem, me.clone()).await?; match handlers::handler(api.clone(), message, token.clone(), &mut mystem, me.clone())
.await
{
Ok(_) => {}
Err(e) => warn!("An error occurred handling command. {:?}", e),
}
} }
} }
Ok(()) Ok(())

View File

@ -1,73 +0,0 @@
use crate::errors;
use serde_json::Value;
use std::io::{Error, Write, BufReader, prelude::*};
use subprocess::{Popen, PopenConfig, PopenError, Redirection};
pub struct MyStem {
pub process: Popen,
}
impl MyStem {
pub fn new() -> Result<Self, PopenError> {
Ok(Self {
process: MyStem::open_process()?,
})
}
fn open_process() -> Result<Popen, PopenError> {
Popen::create(
&["mystem", "-d", "--format", "json"],
PopenConfig {
stdout: Redirection::Pipe,
stdin: Redirection::Pipe,
..Default::default()
},
)
}
#[allow(dead_code)]
pub fn terminate(&mut self) -> Result<(), Error> {
self.process.terminate()
}
#[allow(unused_must_use)]
pub async fn stemming(&mut self, text: String) -> Result<Vec<String>, errors::Error> {
if let Some(exit_status) = self.process.poll() {
warn!(
"MyStem process exited with: {:?}. Restarting...",
exit_status
);
self.process = MyStem::open_process()?;
}
let mut words: Vec<String> = vec![];
let clean_text = format!("{}{}", text.trim(), "\n");
self.process
.stdin
.as_ref()
.unwrap()
.write(clean_text.as_bytes());
let mut contents = String::new();
let mut buf_reader = BufReader::new(self.process.stdout.as_ref().unwrap());
buf_reader.read_line(&mut contents);
match Some(contents) {
Some(contents) => {
let v: Vec<Value> = match serde_json::from_str(contents.as_str()) {
Ok(val) => val,
Err(_) => return Ok(vec![]),
};
for i in v {
words.push(i["analysis"][0]["lex"].to_string().replace("\"", ""));
}
words.retain(|x| x != "null");
debug!(
"Mystem PID: {}. Parsed words: {}.",
self.process.pid().unwrap(),
words.join(", ")
);
Ok(words)
}
None => return Ok(vec![]),
}
}
}