mirror of
https://github.com/house-of-vanity/desubot.git
synced 2025-07-08 13:04:06 +00:00
Compare commits
82 Commits
Author | SHA1 | Date | |
---|---|---|---|
2fb5b03fbf | |||
55a7dd6a67 | |||
ff6e04988e | |||
7c067065bd | |||
175f056add | |||
20f366572b | |||
e5079fa584 | |||
fdc52b7198 | |||
789b918bab | |||
66a93e85b8 | |||
e13a2688ab | |||
04220703a3 | |||
9518ffd69b | |||
5a6cb37ebb | |||
6c2837a76f | |||
d97eaf4284 | |||
e7e0c6923e | |||
382cc56492 | |||
6f48f116c9 | |||
282efe5be4 | |||
4175fe9029 | |||
f1dc1d0897 | |||
d5879a82b6 | |||
456c887a53 | |||
d8b37b32df | |||
47c68ee432 | |||
da53927288 | |||
ac2be9929a | |||
7432ce6398 | |||
049a3c4987 | |||
0831e3f503 | |||
a0f4c40be0 | |||
1facef6897 | |||
428416a2a3 | |||
77dec205f1 | |||
6c761d7576 | |||
865fd3bbe4 | |||
30bdb23a32 | |||
f97562e9b7 | |||
2d000101c2 | |||
a26d227190 | |||
cc44f0e23b | |||
96df636195 | |||
a48e25800c | |||
36660d384d | |||
0d24976ec2 | |||
6ae3b2af1f | |||
a39f6a8c2a | |||
788c2cbbd4 | |||
9d5e5a3217 | |||
945da05794 | |||
3085d4c450 | |||
4b142ae8ef | |||
8f3cccf01d | |||
3136bce84f | |||
e09047bb5b | |||
5528177e52 | |||
ed32bd9195 | |||
d14aa3beb4 | |||
43e4f26af1 | |||
5d8d3441d2 | |||
34fa54e6f4 | |||
d5b30cc94e | |||
7a66034381 | |||
47906fe22d | |||
ea6d9b55a1 | |||
83a6045b18 | |||
c8c55782ec | |||
a1b272bd40 | |||
ed68dbd4bd | |||
3f00505659 | |||
5a41d4a0b9 | |||
3fd5b124f3 | |||
17442819c4 | |||
7adc629292 | |||
39640139fa | |||
0812c9e371 | |||
f111f54606 | |||
7e17851131 | |||
b674ae5b15 | |||
412c3f313c | |||
1838674cab |
27
.github/workflows/automerge.yml
vendored
Normal file
27
.github/workflows/automerge.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
name: automerge
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- labeled
|
||||||
|
- unlabeled
|
||||||
|
- synchronize
|
||||||
|
- opened
|
||||||
|
- edited
|
||||||
|
- ready_for_review
|
||||||
|
- reopened
|
||||||
|
- unlocked
|
||||||
|
pull_request_review:
|
||||||
|
types:
|
||||||
|
- submitted
|
||||||
|
check_suite:
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
status: {}
|
||||||
|
jobs:
|
||||||
|
automerge:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: automerge
|
||||||
|
uses: "pascalgn/automerge-action@v0.13.0"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
35
.github/workflows/build-push.yml
vendored
35
.github/workflows/build-push.yml
vendored
@ -31,6 +31,41 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: desubot.exe
|
name: desubot.exe
|
||||||
path: ./target/release/desubot.exe
|
path: ./target/release/desubot.exe
|
||||||
|
build-push-docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Branch name
|
||||||
|
id: branch_name
|
||||||
|
run: |
|
||||||
|
echo ::set-output name=SOURCE_NAME::${GITHUB_REF#refs/*/}
|
||||||
|
echo ::set-output name=SOURCE_BRANCH::${GITHUB_REF#refs/heads/}
|
||||||
|
echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/}
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
id: docker_build_latest
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
tags: ultradesu/desubot:latest
|
||||||
|
-
|
||||||
|
name: Build and push
|
||||||
|
id: docker_build_tag
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
tags: ultradesu/desubot:${{ steps.branch_name.outputs.SOURCE_TAG }}
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
name: Publish release
|
name: Publish release
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,3 +6,6 @@ memory.sqlite3
|
|||||||
/video
|
/video
|
||||||
/voice
|
/voice
|
||||||
/.idea
|
/.idea
|
||||||
|
Cargo.lock
|
||||||
|
k8s/k8s-deploy.yaml
|
||||||
|
/identifier.sqlite
|
||||||
|
22
Cargo.toml
22
Cargo.toml
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "desubot"
|
name = "desubot"
|
||||||
version = "0.1.0"
|
version = "0.5.9"
|
||||||
authors = ["AB <ab@hexor.ru>"]
|
authors = ["AB <ab@hexor.ru>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@ -9,28 +9,34 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bytes = "0.5"
|
bytes = "0.5"
|
||||||
tokio = { version = "0.2", features = ["full"]}
|
tokio = { version = "0.2", features = ["full"]}
|
||||||
|
|
||||||
tracing = "0.1.9"
|
tracing = "0.1.9"
|
||||||
tracing-futures = "0.2"
|
tracing-futures = "0.2"
|
||||||
multipart = { version = "0.16", default-features = false, features = ["client"] }
|
multipart = { version = "0.16", default-features = false, features = ["client"] }
|
||||||
|
#telegram-bot = "0.8.0"
|
||||||
telegram-bot = "0.8.0"
|
telegram-bot = { git = "https://github.com/ayrat555/telegram-bot", branch = "ayrat555/api-fixes-10" }
|
||||||
|
silicon = "0.4.0"
|
||||||
hyper = "0.13"
|
hyper = "0.13"
|
||||||
hyper-tls = { version = "0.4", optional = true }
|
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.2", features = ["bundled"]}
|
rusqlite = { version = "0.24.2", features = ["bundled"]}
|
||||||
html-escape = "0.2"
|
html-escape = "0.2"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
reqwest = "0.10.9"
|
reqwest = "0.10.9"
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
sha1 = "*"
|
sha1 = "0.6.0"
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
log = { version = "^0.4.5", features = ["std"] }
|
log = { version = "^0.4.5", features = ["std"] }
|
||||||
subprocess = "0.2.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"
|
mystem = "^0.2"
|
||||||
|
#mystem = { path = "../mystem-rs" }
|
||||||
|
async-trait = "0.1.42"
|
||||||
|
sqlparser = "0.7.0"
|
||||||
|
|
||||||
|
[dependencies.syntect]
|
||||||
|
version = "4.4"
|
||||||
|
default-features = false
|
||||||
|
features = ["parsing", "dump-load", "regex-onig"]
|
||||||
|
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
FROM rust:latest AS builder
|
||||||
|
WORKDIR /desubot
|
||||||
|
ADD ./ /desubot/
|
||||||
|
RUN cargo build --release
|
||||||
|
|
||||||
|
FROM ubuntu:latest
|
||||||
|
WORKDIR /storage
|
||||||
|
COPY --from=builder /desubot/target/release/desubot /usr/bin/
|
||||||
|
COPY mystem /usr/bin/
|
||||||
|
RUN apt update && apt install -y fontconfig openssl ca-certificates && rm -rf /var/lib/apt/lists/*
|
||||||
|
ENTRYPOINT desubot
|
||||||
|
|
16
README
16
README
@ -1,16 +0,0 @@
|
|||||||
Desubot
|
|
||||||
Telegram bot with light group statistic and heavy spy features.
|
|
||||||
|
|
||||||
== Features ==
|
|
||||||
* Collect all the messages sent to group.
|
|
||||||
* Collect all the media sent to group including voice, stickers, video, video notes, documents.
|
|
||||||
* /here command to mention all members.
|
|
||||||
* Alongside with saving whole message bot perform blacklist filter and stemming for every word (only Russian). "Красивую собаку мыли негры" -> "красивый собака мыть негр"
|
|
||||||
* Generate sentences using Markov Chains trained on history with /markov_all.
|
|
||||||
|
|
||||||
== TODO ==
|
|
||||||
* Syntax highlighting for code exported to image.
|
|
||||||
|
|
||||||
== 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.
|
|
24
README.md
Normal file
24
README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot?ref=badge_shield)
|
||||||
|
|
||||||
|
Desubot
|
||||||
|
Telegram bot with light group statistic and heavy spy features.
|
||||||
|
|
||||||
|
== Features ==
|
||||||
|
* Collect all the messages sent to group.
|
||||||
|
* Collect all the media sent to group including voice, stickers, video, video notes, documents.
|
||||||
|
* /here command to mention all members.
|
||||||
|
* Alongside with saving whole message bot perform blacklist filter and stemming for every word (only Russian). "Красивую собаку мыли негры" -> "красивый собака мыть негр"
|
||||||
|
* Generate sentences using Markov Chains trained on history with /markov_all.
|
||||||
|
* Syntax highlighting for CODE exported to image.
|
||||||
|
|
||||||
|
== Important ==
|
||||||
|
* Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH.
|
||||||
|
* ubuntu deps: libssl-dev libsqlite3-dev cmake libfreetype-dev
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## License
|
||||||
|
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fhouse-of-vanity%2Fdesubot?ref=badge_large)
|
||||||
|
|
3
assets/README.md
Normal file
3
assets/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Assets
|
||||||
|
|
||||||
|
Silicon uses [bat](https://github.com/sharkdp/bat/tree/master/assets)'s syntax and theme resources.
|
BIN
assets/fonts/Hack-Bold.ttf
Normal file
BIN
assets/fonts/Hack-Bold.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-BoldItalic.ttf
Normal file
BIN
assets/fonts/Hack-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-Italic.ttf
Normal file
BIN
assets/fonts/Hack-Italic.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-Regular.ttf
Normal file
BIN
assets/fonts/Hack-Regular.ttf
Normal file
Binary file not shown.
43
assets/help_text.rs
Normal file
43
assets/help_text.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) static CODE_HELP: &str = "<b>Code highlighter</b>
|
||||||
|
|
||||||
|
<i>Usage</i>
|
||||||
|
<pre>/code
|
||||||
|
<CODE>
|
||||||
|
#<lang - JS by default> #<theme - Dracula by default></pre>
|
||||||
|
|
||||||
|
Language may be defined by both name and extension - Rust, rs...
|
||||||
|
Max length - 4000
|
||||||
|
|
||||||
|
List of themes:
|
||||||
|
1337
|
||||||
|
DarkNeon
|
||||||
|
Dracula
|
||||||
|
GitHub
|
||||||
|
Monokai_Extended
|
||||||
|
Monokai_Extended_Bright
|
||||||
|
Monokai_Extended_Light
|
||||||
|
Monokai_Extended_Origin
|
||||||
|
Nord
|
||||||
|
OneHalfDark
|
||||||
|
OneHalfLight
|
||||||
|
Solarized_(dark)
|
||||||
|
Solarized_(light)
|
||||||
|
Sublime_Snazzy
|
||||||
|
TwoDark
|
||||||
|
ansi-dark
|
||||||
|
ansi-light
|
||||||
|
base16
|
||||||
|
base16-256
|
||||||
|
gruvbox
|
||||||
|
gruvbox-light
|
||||||
|
gruvbox-white
|
||||||
|
zenburn
|
||||||
|
";
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub static SQL_HELP: &str = "<b>Perform an SQL command</b>
|
||||||
|
<i>* Only one sentence per message.
|
||||||
|
* Only SELECT command.
|
||||||
|
* Max result length is 100 lines. Use LIMIT 100.
|
||||||
|
* SQLITE syntax is available only.</i>";
|
431
assets/stop-words.txt
Normal file
431
assets/stop-words.txt
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
а
|
||||||
|
в
|
||||||
|
г
|
||||||
|
е
|
||||||
|
ж
|
||||||
|
и
|
||||||
|
к
|
||||||
|
м
|
||||||
|
о
|
||||||
|
с
|
||||||
|
т
|
||||||
|
у
|
||||||
|
я
|
||||||
|
чо
|
||||||
|
че
|
||||||
|
ща
|
||||||
|
ваще
|
||||||
|
бы
|
||||||
|
stat
|
||||||
|
вообще
|
||||||
|
ThreadTopBot
|
||||||
|
/stat
|
||||||
|
во
|
||||||
|
вы
|
||||||
|
да
|
||||||
|
до
|
||||||
|
ее
|
||||||
|
ей
|
||||||
|
ею
|
||||||
|
её
|
||||||
|
же
|
||||||
|
за
|
||||||
|
из
|
||||||
|
им
|
||||||
|
их
|
||||||
|
ли
|
||||||
|
мы
|
||||||
|
на
|
||||||
|
не
|
||||||
|
ни
|
||||||
|
но
|
||||||
|
ну
|
||||||
|
нх
|
||||||
|
об
|
||||||
|
он
|
||||||
|
от
|
||||||
|
по
|
||||||
|
со
|
||||||
|
та
|
||||||
|
те
|
||||||
|
то
|
||||||
|
ту
|
||||||
|
ты
|
||||||
|
уж
|
||||||
|
без
|
||||||
|
был
|
||||||
|
вам
|
||||||
|
вас
|
||||||
|
ваш
|
||||||
|
вон
|
||||||
|
вот
|
||||||
|
все
|
||||||
|
всю
|
||||||
|
вся
|
||||||
|
всё
|
||||||
|
где
|
||||||
|
год
|
||||||
|
два
|
||||||
|
две
|
||||||
|
дел
|
||||||
|
для
|
||||||
|
его
|
||||||
|
ему
|
||||||
|
еще
|
||||||
|
ещё
|
||||||
|
или
|
||||||
|
ими
|
||||||
|
имя
|
||||||
|
как
|
||||||
|
кем
|
||||||
|
ком
|
||||||
|
кто
|
||||||
|
лет
|
||||||
|
мне
|
||||||
|
мог
|
||||||
|
мож
|
||||||
|
мои
|
||||||
|
мой
|
||||||
|
мор
|
||||||
|
моя
|
||||||
|
моё
|
||||||
|
над
|
||||||
|
нам
|
||||||
|
нас
|
||||||
|
наш
|
||||||
|
нее
|
||||||
|
ней
|
||||||
|
нем
|
||||||
|
нет
|
||||||
|
нею
|
||||||
|
неё
|
||||||
|
них
|
||||||
|
оба
|
||||||
|
она
|
||||||
|
они
|
||||||
|
оно
|
||||||
|
под
|
||||||
|
пор
|
||||||
|
при
|
||||||
|
про
|
||||||
|
раз
|
||||||
|
сам
|
||||||
|
сих
|
||||||
|
так
|
||||||
|
там
|
||||||
|
тем
|
||||||
|
тех
|
||||||
|
том
|
||||||
|
тот
|
||||||
|
тою
|
||||||
|
три
|
||||||
|
тут
|
||||||
|
уже
|
||||||
|
чем
|
||||||
|
что
|
||||||
|
эта
|
||||||
|
эти
|
||||||
|
это
|
||||||
|
эту
|
||||||
|
алло
|
||||||
|
буду
|
||||||
|
будь
|
||||||
|
бывь
|
||||||
|
была
|
||||||
|
были
|
||||||
|
было
|
||||||
|
быть
|
||||||
|
вами
|
||||||
|
ваша
|
||||||
|
ваше
|
||||||
|
ваши
|
||||||
|
ведь
|
||||||
|
весь
|
||||||
|
вниз
|
||||||
|
всем
|
||||||
|
всех
|
||||||
|
всею
|
||||||
|
года
|
||||||
|
году
|
||||||
|
даже
|
||||||
|
двух
|
||||||
|
день
|
||||||
|
если
|
||||||
|
есть
|
||||||
|
зато
|
||||||
|
кого
|
||||||
|
кому
|
||||||
|
куда
|
||||||
|
лишь
|
||||||
|
люди
|
||||||
|
мало
|
||||||
|
меля
|
||||||
|
меня
|
||||||
|
мимо
|
||||||
|
мира
|
||||||
|
мной
|
||||||
|
мною
|
||||||
|
мочь
|
||||||
|
надо
|
||||||
|
нами
|
||||||
|
наша
|
||||||
|
наше
|
||||||
|
наши
|
||||||
|
него
|
||||||
|
нему
|
||||||
|
ниже
|
||||||
|
ними
|
||||||
|
один
|
||||||
|
пока
|
||||||
|
пора
|
||||||
|
пять
|
||||||
|
рано
|
||||||
|
сама
|
||||||
|
сами
|
||||||
|
само
|
||||||
|
саму
|
||||||
|
свое
|
||||||
|
свои
|
||||||
|
свою
|
||||||
|
себе
|
||||||
|
себя
|
||||||
|
семь
|
||||||
|
стал
|
||||||
|
суть
|
||||||
|
твой
|
||||||
|
твоя
|
||||||
|
твоё
|
||||||
|
тебе
|
||||||
|
тебя
|
||||||
|
теми
|
||||||
|
того
|
||||||
|
тоже
|
||||||
|
тому
|
||||||
|
туда
|
||||||
|
хоть
|
||||||
|
хотя
|
||||||
|
чаще
|
||||||
|
чего
|
||||||
|
чему
|
||||||
|
чтоб
|
||||||
|
чуть
|
||||||
|
этим
|
||||||
|
этих
|
||||||
|
этой
|
||||||
|
этом
|
||||||
|
этот
|
||||||
|
более
|
||||||
|
будем
|
||||||
|
будет
|
||||||
|
будто
|
||||||
|
будут
|
||||||
|
вверх
|
||||||
|
вдали
|
||||||
|
вдруг
|
||||||
|
везде
|
||||||
|
внизу
|
||||||
|
время
|
||||||
|
всего
|
||||||
|
всеми
|
||||||
|
всему
|
||||||
|
всюду
|
||||||
|
давно
|
||||||
|
даром
|
||||||
|
долго
|
||||||
|
друго
|
||||||
|
занят
|
||||||
|
затем
|
||||||
|
зачем
|
||||||
|
здесь
|
||||||
|
иметь
|
||||||
|
какая
|
||||||
|
какой
|
||||||
|
когда
|
||||||
|
кроме
|
||||||
|
лучше
|
||||||
|
между
|
||||||
|
менее
|
||||||
|
много
|
||||||
|
могут
|
||||||
|
может
|
||||||
|
можно
|
||||||
|
можхо
|
||||||
|
назад
|
||||||
|
низко
|
||||||
|
нужно
|
||||||
|
одной
|
||||||
|
около
|
||||||
|
опять
|
||||||
|
очень
|
||||||
|
перед
|
||||||
|
позже
|
||||||
|
после
|
||||||
|
потом
|
||||||
|
почти
|
||||||
|
пятый
|
||||||
|
разве
|
||||||
|
рядом
|
||||||
|
самим
|
||||||
|
самих
|
||||||
|
самой
|
||||||
|
самом
|
||||||
|
своей
|
||||||
|
своих
|
||||||
|
сеаой
|
||||||
|
снова
|
||||||
|
собой
|
||||||
|
собою
|
||||||
|
такая
|
||||||
|
также
|
||||||
|
такие
|
||||||
|
такое
|
||||||
|
такой
|
||||||
|
тобой
|
||||||
|
тобою
|
||||||
|
тогда
|
||||||
|
тысяч
|
||||||
|
уметь
|
||||||
|
часто
|
||||||
|
через
|
||||||
|
чтобы
|
||||||
|
шесть
|
||||||
|
этими
|
||||||
|
этого
|
||||||
|
этому
|
||||||
|
близко
|
||||||
|
больше
|
||||||
|
будете
|
||||||
|
будешь
|
||||||
|
бывает
|
||||||
|
важная
|
||||||
|
важное
|
||||||
|
важные
|
||||||
|
важный
|
||||||
|
вокруг
|
||||||
|
восемь
|
||||||
|
всегда
|
||||||
|
второй
|
||||||
|
далеко
|
||||||
|
дальше
|
||||||
|
девять
|
||||||
|
десять
|
||||||
|
должно
|
||||||
|
другая
|
||||||
|
другие
|
||||||
|
других
|
||||||
|
другое
|
||||||
|
другой
|
||||||
|
занята
|
||||||
|
занято
|
||||||
|
заняты
|
||||||
|
значит
|
||||||
|
именно
|
||||||
|
иногда
|
||||||
|
каждая
|
||||||
|
каждое
|
||||||
|
каждые
|
||||||
|
каждый
|
||||||
|
кругом
|
||||||
|
меньше
|
||||||
|
начала
|
||||||
|
нельзя
|
||||||
|
нибудь
|
||||||
|
никуда
|
||||||
|
ничего
|
||||||
|
обычно
|
||||||
|
однако
|
||||||
|
одного
|
||||||
|
отсюда
|
||||||
|
первый
|
||||||
|
потому
|
||||||
|
почему
|
||||||
|
просто
|
||||||
|
против
|
||||||
|
раньше
|
||||||
|
самими
|
||||||
|
самого
|
||||||
|
самому
|
||||||
|
своего
|
||||||
|
сейчас
|
||||||
|
сказал
|
||||||
|
совсем
|
||||||
|
теперь
|
||||||
|
только
|
||||||
|
третий
|
||||||
|
хорошо
|
||||||
|
хотеть
|
||||||
|
хочешь
|
||||||
|
четыре
|
||||||
|
шестой
|
||||||
|
восьмой
|
||||||
|
впрочем
|
||||||
|
времени
|
||||||
|
говорил
|
||||||
|
говорит
|
||||||
|
девятый
|
||||||
|
десятый
|
||||||
|
кажется
|
||||||
|
конечно
|
||||||
|
которая
|
||||||
|
которой
|
||||||
|
которые
|
||||||
|
который
|
||||||
|
которых
|
||||||
|
наверху
|
||||||
|
наконец
|
||||||
|
недавно
|
||||||
|
немного
|
||||||
|
нередко
|
||||||
|
никогда
|
||||||
|
однажды
|
||||||
|
посреди
|
||||||
|
сегодня
|
||||||
|
седьмой
|
||||||
|
сказала
|
||||||
|
сказать
|
||||||
|
сколько
|
||||||
|
слишком
|
||||||
|
сначала
|
||||||
|
спасибо
|
||||||
|
двадцать
|
||||||
|
довольно
|
||||||
|
которого
|
||||||
|
наиболее
|
||||||
|
недалеко
|
||||||
|
особенно
|
||||||
|
отовсюду
|
||||||
|
двадцатый
|
||||||
|
миллионов
|
||||||
|
несколько
|
||||||
|
прекрасно
|
||||||
|
процентов
|
||||||
|
четвертый
|
||||||
|
двенадцать
|
||||||
|
непрерывно
|
||||||
|
пожалуйста
|
||||||
|
пятнадцать
|
||||||
|
семнадцать
|
||||||
|
тринадцать
|
||||||
|
двенадцатый
|
||||||
|
одиннадцать
|
||||||
|
пятнадцатый
|
||||||
|
семнадцатый
|
||||||
|
тринадцатый
|
||||||
|
шестнадцать
|
||||||
|
восемнадцать
|
||||||
|
девятнадцать
|
||||||
|
одиннадцатый
|
||||||
|
четырнадцать
|
||||||
|
шестнадцатый
|
||||||
|
восемнадцатый
|
||||||
|
девятнадцатый
|
||||||
|
действительно
|
||||||
|
четырнадцатый
|
||||||
|
многочисленная
|
||||||
|
многочисленное
|
||||||
|
многочисленные
|
||||||
|
многочисленный
|
||||||
|
ага
|
||||||
|
делать
|
||||||
|
писать
|
||||||
|
бот
|
21
assets/sync_from_bat.py
Normal file
21
assets/sync_from_bat.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Sync themes and syntaxes from [bat](https://github.com/sharkdp/bat/tree/master/assets)
|
||||||
|
|
||||||
|
import os
|
||||||
|
from glob import glob
|
||||||
|
from shutil import copy
|
||||||
|
|
||||||
|
if not os.path.exists('../../bat'):
|
||||||
|
os.system('git clone https://github.com/sharkdp/bat ../../bat')
|
||||||
|
else:
|
||||||
|
os.system('git -C ../../bat pull')
|
||||||
|
|
||||||
|
for syntax_file in glob('../../bat/assets/syntaxes/**/*.sublime-syntax'):
|
||||||
|
copy(syntax_file, './syntaxes/')
|
||||||
|
|
||||||
|
for theme_file in glob('../../bat/assets/themes/**/*.tmTheme'):
|
||||||
|
copy(theme_file, './themes/')
|
||||||
|
|
||||||
|
os.system('bat cache --build --source . --target .')
|
||||||
|
|
||||||
|
print('Finished.')
|
BIN
assets/syntaxes.bin
Normal file
BIN
assets/syntaxes.bin
Normal file
Binary file not shown.
4
assets/syntaxes/.gitignore
vendored
Normal file
4
assets/syntaxes/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
BIN
assets/themes.bin
Normal file
BIN
assets/themes.bin
Normal file
Binary file not shown.
5
assets/themes/.gitignore
vendored
Normal file
5
assets/themes/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
||||||
|
!Dracula.tmTheme
|
940
assets/themes/Dracula.tmTheme
Normal file
940
assets/themes/Dracula.tmTheme
Normal file
@ -0,0 +1,940 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Dracula Theme v1.4.3
|
||||||
|
#
|
||||||
|
# https://github.com/dracula/sublime
|
||||||
|
#
|
||||||
|
# Copyright 2013-present, All rights reserved
|
||||||
|
#
|
||||||
|
# Code licensed under the MIT license
|
||||||
|
#
|
||||||
|
# @author Zeno Rocha <hi@zenorocha.com>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Dracula</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#282a36</string>
|
||||||
|
<key>caret</key>
|
||||||
|
<string>#f8f8f0</string>
|
||||||
|
<key>block_caret</key>
|
||||||
|
<string>#999a9e</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#f8f8f2</string>
|
||||||
|
<key>invisibles</key>
|
||||||
|
<string>#3B3A32</string>
|
||||||
|
<key>lineHighlight</key>
|
||||||
|
<string>#44475a</string>
|
||||||
|
<key>selection</key>
|
||||||
|
<string>#44475a</string>
|
||||||
|
<key>findHighlight</key>
|
||||||
|
<string>#effb7b</string>
|
||||||
|
<key>findHighlightForeground</key>
|
||||||
|
<string>#000000</string>
|
||||||
|
<key>selectionBorder</key>
|
||||||
|
<string>#222218</string>
|
||||||
|
<key>activeGuide</key>
|
||||||
|
<string>#9D550FB0</string>
|
||||||
|
<key>bracketsForeground</key>
|
||||||
|
<string>#F8F8F2A5</string>
|
||||||
|
<key>bracketsOptions</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>bracketContentsForeground</key>
|
||||||
|
<string>#F8F8F2A5</string>
|
||||||
|
<key>bracketContentsOptions</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>tagsOptions</key>
|
||||||
|
<string>stippled_underline</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Comment</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>comment</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272a4</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#f1fa8c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Number</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.numeric</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Built-in constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.language</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>User-defined constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.character, constant.other</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Ruby's @variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.other.readwrite.instance</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffb86c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>String interpolation</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.character.escaped, constant.character.escape, string source, string source.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Ruby Regexp</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.ruby string.regexp.classic.ruby,source.ruby string.regexp.mod-r.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff5555</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Keyword</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage Type Namespace</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type.namespace</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage Type Class</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Class name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Meta Path</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.path</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#66d9ef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Inherited class</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.inherited-class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic underline</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function argument</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.parameter</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffb86c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Tag name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.tag</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Tag attribute</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.attribute-name</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library function</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.constant</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6be5fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library class/type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.type, support.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#66d9ef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.other.variable</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Support Other Namespace</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.other.namespace</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#66d9ef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Invalid</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F8F8F0</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Invalid deprecated</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid.deprecated</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F8F8F0</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.structure.dictionary.json string.quoted.double.json</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#CFCFC2</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>diff.header</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.diff, meta.diff.header</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272a4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>diff.deleted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.deleted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>diff.inserted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.inserted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>diff.changed</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.changed</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#E6DB74</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.numeric.line-number.find-in-files - match</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.filename</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#E6DB74</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>message.error</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F83333</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON Punctuation</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.definition.string.begin.json - meta.structure.dictionary.value.json, punctuation.definition.string.end.json - meta.structure.dictionary.value.json</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#EEEEEE</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON Structure</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.structure.dictionary.json string.quoted.double.json</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.structure.dictionary.value.json string.quoted.double.json</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#f1fa8c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 6 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta meta meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 5 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffb86c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 4 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 3 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 2 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 1 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffb86c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
|
||||||
|
<!-- Markdown Tweaks -->
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: strike</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.strike</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FFB86C</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: bold</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.bold</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>bold</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FFB86C</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: italic</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.italic</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FFB86C</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: heading</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.heading</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8BE9FD</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: List Items Punctuation</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.definition.list_item.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FF79C6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Blockquote</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.quote</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Blockquote Punctuation</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.definition.blockquote.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Separator</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.separator</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: raw inline</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>text.html.markdown markup.raw.inline</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50FA7B</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: underline</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.underline</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#BD93F9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: Raw block</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.raw.block</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#CFCFC2</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Raw Block fenced source</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.raw.block.fenced.markdown source</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F8F8F2</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Fenced Bode Block</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.definition.fenced.markdown, variable.language.fenced.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Fenced Language</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.language.fenced.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Accessor</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.accessor</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FF79C6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Meta Function Return Type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.function.return-type</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FF79C6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Section Block Begin</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.block.begin</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Section Block End</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.block.end</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Section Embedded Begin</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.embedded.begin</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Section Embedded End</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.embedded.end</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Separator Namespace</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.separator.namespace</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable Function</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable Other</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.other</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable Language</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.language</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Entity Name Module Ruby</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.module.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Entity Name Constant Ruby</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.constant.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Support Function Builtin Ruby</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.function.builtin.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage Type Namespace CS</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type.namespace.cs</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Entity Name Namespace CS</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.namespace.cs</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>83091B89-765E-4F0D-9275-0EC6CB084126</string>
|
||||||
|
<key>colorSpaceName</key>
|
||||||
|
<string>sRGB</string>
|
||||||
|
<key>semanticClass</key>
|
||||||
|
<string>theme.dracula</string>
|
||||||
|
<key>author</key>
|
||||||
|
<string>Zeno Rocha</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
43
k8s/k8s-deploy-example.yaml
Normal file
43
k8s/k8s-deploy-example.yaml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: desubot-api-token
|
||||||
|
data:
|
||||||
|
token: 123.... # Base64 encoded token.
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: desubot
|
||||||
|
spec:
|
||||||
|
serviceName: "desubot"
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: desubot
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: desubot
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: desubot
|
||||||
|
image: ultradesu/desubot:latest
|
||||||
|
volumeMounts:
|
||||||
|
- name: storage
|
||||||
|
mountPath: /storage
|
||||||
|
env:
|
||||||
|
- name: TELEGRAM_BOT_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: desubot-api-token
|
||||||
|
key: token
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: storage
|
||||||
|
spec:
|
||||||
|
accessModes: [ "ReadWriteOnce" ]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 50Gi
|
651
src/commands.rs
651
src/commands.rs
@ -1,18 +1,278 @@
|
|||||||
|
#![allow(unused_variables)]
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::errors::Error;
|
use crate::errors::Error;
|
||||||
|
use crate::errors::Error::{CodeHighlightningError, 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::Gender::Feminine;
|
||||||
use mystem::MyStem;
|
use mystem::MyStem;
|
||||||
|
use mystem::Person::First;
|
||||||
use mystem::Tense::{Inpresent, Past};
|
use mystem::Tense::{Inpresent, Past};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use sqlparser::ast::Statement;
|
||||||
|
use sqlparser::dialect::GenericDialect;
|
||||||
|
use sqlparser::parser::Parser;
|
||||||
|
use syntect::easy::HighlightLines;
|
||||||
|
use syntect::highlighting::Theme;
|
||||||
|
use syntect::parsing::SyntaxReference;
|
||||||
|
use syntect::util::LinesWithEndings;
|
||||||
use telegram_bot::prelude::*;
|
use telegram_bot::prelude::*;
|
||||||
use telegram_bot::{Api, Message, ParseMode};
|
use telegram_bot::*;
|
||||||
|
use telegram_bot::{Api, Message, ParseMode, UserId};
|
||||||
|
|
||||||
pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
|
include!("../assets/help_text.rs");
|
||||||
let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap();
|
|
||||||
|
pub struct Here {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct Top {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct ConfTop {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct GlobalTop {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
pub struct Code {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct Scheme {
|
||||||
|
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 Scheme {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
match api
|
||||||
|
.send(
|
||||||
|
message
|
||||||
|
.text_reply(format!(
|
||||||
|
"{}{}{}",
|
||||||
|
"<pre>",
|
||||||
|
include_str!("../assets/scheme.sql").to_string(),
|
||||||
|
"</pre>"
|
||||||
|
))
|
||||||
|
.parse_mode(ParseMode::Html),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => debug!("/scheme command sent to {}", message.chat.id()),
|
||||||
|
Err(_) => warn!("/scheme command sent failed to {}", message.chat.id()),
|
||||||
|
};
|
||||||
|
match {
|
||||||
|
Code {
|
||||||
|
data: format!(
|
||||||
|
"{}{}",
|
||||||
|
include_str!("../assets/scheme.sql").to_string(),
|
||||||
|
"\n#sql"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.exec_with_result(&api, &message)
|
||||||
|
.await
|
||||||
|
} {
|
||||||
|
Ok(path) => {
|
||||||
|
let file = InputFileUpload::with_path(path.clone());
|
||||||
|
// api.send(message.chat.document(&file)).await?;
|
||||||
|
//
|
||||||
|
// // Send an image from disk
|
||||||
|
api.send(message.chat.document(&file)).await?;
|
||||||
|
//debug!("{:#?}", formatter);
|
||||||
|
let _ = std::fs::remove_file(&path);
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
let _ = api
|
||||||
|
.send(message.text_reply(CODE_HELP).parse_mode(ParseMode::Html))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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();
|
||||||
|
debug!("PIZDA - {}", sql);
|
||||||
|
if sql == "/sql" || sql == "/sql-" {
|
||||||
|
return Ok(SQL_HELP.to_string());
|
||||||
|
}
|
||||||
|
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(), 60).unwrap_or(vec![telegram_bot::User {
|
||||||
|
id: UserId::new(124317807),
|
||||||
|
first_name: "Ultradesu".to_string(),
|
||||||
|
last_name: None,
|
||||||
|
username: None,
|
||||||
|
is_bot: false,
|
||||||
|
language_code: None,
|
||||||
|
}]);
|
||||||
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());
|
||||||
}
|
}
|
||||||
@ -36,12 +296,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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn top(api: Api, message: Message) -> Result<(), Error> {
|
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 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;
|
||||||
@ -60,12 +335,105 @@ 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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn markov_all(api: Api, message: Message) -> Result<(), Error> {
|
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 GlobalTop {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
let top = db::get_global_top().await?;
|
||||||
|
let mut msg = "<b>Global top words:</b>\n<pre>".to_string();
|
||||||
|
let mut counter = 1;
|
||||||
|
for word in top.iter() {
|
||||||
|
msg = format!(
|
||||||
|
"{} <b>{}</b> {} - {}\n",
|
||||||
|
msg, counter, word.word, word.count
|
||||||
|
);
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
msg = format!("{}{}", msg, "</pre>");
|
||||||
|
match api
|
||||||
|
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => debug!("/global_top command sent to {}", message.chat.id()),
|
||||||
|
Err(_) => warn!("/global_top command sent failed to {}", message.chat.id()),
|
||||||
|
}
|
||||||
|
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 ConfTop {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
let top = db::get_conf_top(&message).await?;
|
||||||
|
let mut msg = "<b>Conf top words:</b>\n<pre>".to_string();
|
||||||
|
let mut counter = 1;
|
||||||
|
for word in top.iter() {
|
||||||
|
msg = format!(
|
||||||
|
"{} <b>{}</b> {} - {}\n",
|
||||||
|
msg, counter, word.word, word.count
|
||||||
|
);
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
msg = format!("{}{}", msg, "</pre>");
|
||||||
|
match api
|
||||||
|
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => debug!("/conf_top command sent to {}", message.chat.id()),
|
||||||
|
Err(_) => warn!("/conf_top command sent failed to {}", message.chat.id()),
|
||||||
|
}
|
||||||
|
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 MarkovAll {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
let messages = db::get_messages_random_all().await?;
|
let messages = db::get_messages_random_all().await?;
|
||||||
let mut chain = Chain::new();
|
let mut chain = Chain::new();
|
||||||
chain.feed(messages);
|
chain.feed(messages);
|
||||||
@ -86,14 +454,31 @@ pub(crate) async fn markov_all(api: Api, message: Message) -> Result<(), Error>
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn markov(api: Api, message: Message) -> Result<(), Error> {
|
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 Markov {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
let messages = db::get_messages_random_group(&message).await?;
|
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();
|
||||||
let mut msg = String::new();
|
let mut msg = String::new();
|
||||||
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
||||||
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
msg = format!("{} {}", msg, sentences.pop().unwrap_or(" ".into()));
|
||||||
}
|
}
|
||||||
match api
|
match api
|
||||||
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
||||||
@ -107,39 +492,77 @@ pub(crate) async fn markov(api: Api, message: Message) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn omedeto(api: Api, message: Message, mystem: &mut MyStem) -> Result<(), Error> {
|
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 all_msg = db::get_messages_user_all(&message).await?;
|
||||||
let re = Regex::new(r"^[яЯ] [а-яА-Я]+(-[а-яА-Я]+(_[а-яА-Я]+)*)*$").unwrap();
|
let re = Regex::new(r"^[яЯ] [а-яА-Я]+(-[а-яА-Я]+(_[а-яА-Я]+)*)*").unwrap();
|
||||||
let mut nouns: Vec<String> = all_msg
|
let mut nouns: Vec<String> = all_msg
|
||||||
.clone()
|
.iter()
|
||||||
.into_iter()
|
|
||||||
.filter(|m| re.is_match(m))
|
.filter(|m| re.is_match(m))
|
||||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||||
.filter(|m| {
|
.filter(|m| {
|
||||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||||
if stem.is_empty() {
|
if !stem.is_empty() {
|
||||||
false
|
if !stem[0].lex.is_empty() {
|
||||||
} else if stem[0].lex.is_empty() {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
match stem[0].lex[0].grammem.part_of_speech {
|
match stem[0].lex[0].grammem.part_of_speech {
|
||||||
mystem::PartOfSpeech::Noun => true,
|
mystem::PartOfSpeech::Noun => stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Case(Nominative)),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||||
.collect();
|
.collect();
|
||||||
nouns.sort();
|
nouns.sort();
|
||||||
nouns.dedup();
|
nouns.dedup();
|
||||||
nouns.shuffle(&mut rand::thread_rng());
|
nouns.shuffle(&mut rand::thread_rng());
|
||||||
|
//debug!("Found {} nouns. {:#?}", nouns.len(), nouns);
|
||||||
|
|
||||||
let mut verbs_p: Vec<String> = all_msg
|
let mut verbs_p: Vec<String> = all_msg
|
||||||
.clone()
|
.iter()
|
||||||
.into_iter()
|
|
||||||
.filter(|m| re.is_match(m))
|
.filter(|m| re.is_match(m))
|
||||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||||
.filter(|m| {
|
.filter(|m| {
|
||||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||||
|
#[allow(clippy::if_same_then_else)]
|
||||||
if stem.is_empty() {
|
if stem.is_empty() {
|
||||||
false
|
false
|
||||||
} else if stem[0].lex.is_empty() {
|
} else if stem[0].lex.is_empty() {
|
||||||
@ -154,89 +577,123 @@ pub(crate) async fn omedeto(api: Api, message: Message, mystem: &mut MyStem) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||||
.collect();
|
.collect();
|
||||||
verbs_p.sort();
|
verbs_p.sort();
|
||||||
verbs_p.dedup();
|
verbs_p.dedup();
|
||||||
verbs_p.shuffle(&mut rand::thread_rng());
|
verbs_p.shuffle(&mut rand::thread_rng());
|
||||||
|
//debug!("Found {} past verbs. {:#?}", verbs_p.len(), verbs_p);
|
||||||
|
|
||||||
let mut verbs_i: Vec<String> = all_msg
|
let mut verbs_i: Vec<String> = all_msg
|
||||||
.clone()
|
.iter()
|
||||||
.into_iter()
|
|
||||||
.filter(|m| re.is_match(m))
|
.filter(|m| re.is_match(m))
|
||||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||||
.filter(|m| {
|
.filter(|m| {
|
||||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||||
|
#[allow(clippy::if_same_then_else)]
|
||||||
if stem.is_empty() {
|
if stem.is_empty() {
|
||||||
false
|
false
|
||||||
} else if stem[0].lex.is_empty() {
|
} else if stem[0].lex.is_empty() {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
match stem[0].lex[0].grammem.part_of_speech {
|
match stem[0].lex[0].grammem.part_of_speech {
|
||||||
mystem::PartOfSpeech::Verb => stem[0].lex[0]
|
mystem::PartOfSpeech::Verb => {
|
||||||
|
stem[0].lex[0]
|
||||||
.grammem
|
.grammem
|
||||||
.facts
|
.facts
|
||||||
.contains(&mystem::Fact::Tense(Inpresent)),
|
.contains(&mystem::Fact::Tense(Inpresent))
|
||||||
|
&& stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Person(First))
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||||
.collect();
|
.collect();
|
||||||
verbs_i.sort();
|
verbs_i.sort();
|
||||||
verbs_i.dedup();
|
verbs_i.dedup();
|
||||||
verbs_i.shuffle(&mut rand::thread_rng());
|
verbs_i.shuffle(&mut rand::thread_rng());
|
||||||
|
//debug!("Found {} inpresent verbs. {:#?}", verbs_i.len(), verbs_i);
|
||||||
|
|
||||||
if nouns.is_empty() {
|
if nouns.is_empty() {
|
||||||
nouns.push(message.from.first_name.to_string());
|
nouns.push(message.from.first_name.to_string());
|
||||||
}
|
}
|
||||||
let start: Vec<String> = vec![
|
let start: Vec<String> = vec![
|
||||||
"С новыйм годом.".into(),
|
"С новым годом".into(),
|
||||||
"С НГ тебя".into(),
|
"С НГ тебя".into(),
|
||||||
"Поздравляю".into(),
|
"Поздравляю".into(),
|
||||||
"Поздравляю с НГ".into(),
|
"Поздравляю с НГ".into(),
|
||||||
];
|
];
|
||||||
|
let placeholders: Vec<String> = vec![
|
||||||
|
"[ДАННЫЕ УДАЛЕНЫ]".into(),
|
||||||
|
"[СЕКРЕТНО]".into(),
|
||||||
|
"[НЕТ ДАННЫХ]".into(),
|
||||||
|
"[ОШИБКА ДОСТУПА]".into(),
|
||||||
|
];
|
||||||
//debug!("Nouns: {:#?}", nouns);
|
//debug!("Nouns: {:#?}", nouns);
|
||||||
//debug!("Verbs: {:#?}", verbs);
|
//debug!("Verbs: {:#?}", verbs);
|
||||||
|
|
||||||
let fem = {
|
let fem = {
|
||||||
let z = mystem
|
let mut fm = 0;
|
||||||
.stemming(message.from.first_name.to_string())
|
let mut mu = 0;
|
||||||
.unwrap();
|
all_msg
|
||||||
|
.clone()
|
||||||
if z.is_empty() {
|
.into_iter()
|
||||||
false
|
.filter(|m| re.is_match(m))
|
||||||
} else if z[0].lex.is_empty() {
|
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||||
false
|
.map(|m| {
|
||||||
|
let stem = mystem.stemming(m).unwrap_or_default();
|
||||||
|
#[allow(clippy::if_same_then_else)]
|
||||||
|
if stem.is_empty() {
|
||||||
|
} else if stem[0].lex.is_empty() {
|
||||||
} else {
|
} else {
|
||||||
if z[0].lex[0]
|
if let mystem::PartOfSpeech::Verb = stem[0].lex[0].grammem.part_of_speech {
|
||||||
|
match stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Tense(Past))
|
||||||
|
{
|
||||||
|
true => {
|
||||||
|
if stem[0].lex[0]
|
||||||
.grammem
|
.grammem
|
||||||
.facts
|
.facts
|
||||||
.contains(&mystem::Fact::Gender(Feminine))
|
.contains(&mystem::Fact::Gender(Feminine))
|
||||||
{
|
{
|
||||||
true
|
fm += 1;
|
||||||
} else {
|
} else {
|
||||||
false
|
mu += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
false => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.for_each(drop);
|
||||||
|
//debug!("fm - {}, mu - {}", fm, mu);
|
||||||
|
fm >= mu
|
||||||
};
|
};
|
||||||
|
//debug!("Is Feminine - {}", fem);
|
||||||
let result = format!(
|
let result = format!(
|
||||||
"{} {} известн{} как {}, {}, а так же конечно {}. В прошедшем году ты часто давал{} нам знать, что ты {}, {} и {}. Нередко ты говорил{} я {}, я {} или даже я {}. =*",
|
"{} {} известн{} как {}, {}, а так же конечно {}. В прошедшем году ты часто давал{} нам знать, что ты {}, {} и {}. Нередко ты говорил{} я {}, я {} или даже я {}. =*",
|
||||||
start.choose(&mut rand::thread_rng()).unwrap(),
|
start.choose(&mut rand::thread_rng()).unwrap(),
|
||||||
message.from.first_name.to_string(),
|
message.from.first_name.to_string(),
|
||||||
{ if fem { "ая" } else { "ый" } },
|
{ if fem { "ая" } else { "ый" } },
|
||||||
nouns.pop().unwrap_or("=(".to_string()),
|
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
nouns.pop().unwrap_or("=(".to_string()),
|
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
nouns.pop().unwrap_or("=(".to_string()),
|
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
{ if fem { "а" } else { "" } },
|
{ if fem { "а" } else { "" } },
|
||||||
verbs_p.pop().unwrap_or("=(".to_string()),
|
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
verbs_p.pop().unwrap_or("=(".to_string()),
|
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
verbs_p.pop().unwrap_or("=(".to_string()),
|
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
{ if fem { "а" } else { "" } },
|
{ if fem { "а" } else { "" } },
|
||||||
verbs_i.pop().unwrap_or("=(".to_string()),
|
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
verbs_i.pop().unwrap_or("=(".to_string()),
|
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
verbs_i.pop().unwrap_or("=(".to_string()),
|
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
|
||||||
);
|
);
|
||||||
debug!("{:?}", result);
|
|
||||||
match api
|
match api
|
||||||
.send(
|
.send(
|
||||||
message
|
message
|
||||||
@ -248,7 +705,97 @@ pub(crate) async fn omedeto(api: Api, message: Message, mystem: &mut MyStem) ->
|
|||||||
Ok(_) => debug!("/omedeto command sent to {}", message.chat.id()),
|
Ok(_) => debug!("/omedeto command sent to {}", message.chat.id()),
|
||||||
Err(_) => warn!("/omedeto command sent failed to {}", message.chat.id()),
|
Err(_) => warn!("/omedeto command sent failed to {}", message.chat.id()),
|
||||||
}
|
}
|
||||||
|
|
||||||
// '^я [а-яА-Я]+(-[а-яА-Я]+(_[а-яА-Я]+)*)*$'
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Execute for Code {
|
||||||
|
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 lines: Vec<String> = self
|
||||||
|
.data
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect();
|
||||||
|
let last_line = &lines[lines.len() - 1];
|
||||||
|
|
||||||
|
let tags = last_line
|
||||||
|
.trim()
|
||||||
|
.split(|s| s == ' ' || s == '\n')
|
||||||
|
.filter(|s| s.starts_with("#"))
|
||||||
|
.map(|s| s.to_string().replace("#", ""))
|
||||||
|
.map(|s| s.to_string().replace("_", " "))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let code = if tags.is_empty() {
|
||||||
|
self.data.trim().to_string()
|
||||||
|
} else {
|
||||||
|
let _ = lines.pop();
|
||||||
|
lines.join("\n")
|
||||||
|
};
|
||||||
|
if code.is_empty() {
|
||||||
|
return Err(CodeHighlightningError);
|
||||||
|
}
|
||||||
|
let (ps, ts) = silicon::utils::init_syntect();
|
||||||
|
let syntax: Vec<&SyntaxReference> = tags
|
||||||
|
.iter()
|
||||||
|
.map(|s| ps.find_syntax_by_token(s))
|
||||||
|
.filter(|s| s.is_some())
|
||||||
|
.map(|s| s.unwrap())
|
||||||
|
.collect();
|
||||||
|
let syntax = if syntax.len() != 1 {
|
||||||
|
ps.find_syntax_by_token("js").unwrap()
|
||||||
|
} else {
|
||||||
|
syntax[0]
|
||||||
|
};
|
||||||
|
let theme: Vec<&Theme> = tags
|
||||||
|
.iter()
|
||||||
|
.map(|s| ts.themes.get(s))
|
||||||
|
.filter(|s| s.is_some())
|
||||||
|
.map(|s| s.unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let theme = if theme.len() != 1 {
|
||||||
|
ts.themes.get("gruvbox").unwrap()
|
||||||
|
} else {
|
||||||
|
theme[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut h = HighlightLines::new(syntax, theme);
|
||||||
|
let highlight = LinesWithEndings::from(&code)
|
||||||
|
.map(|line| h.highlight(line, &ps))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let formatter = silicon::formatter::ImageFormatterBuilder::<String>::new()
|
||||||
|
.window_controls(false)
|
||||||
|
.line_offset(1)
|
||||||
|
.round_corner(false);
|
||||||
|
let mut formatter = formatter.build().unwrap();
|
||||||
|
let image = formatter.format(&highlight, &theme);
|
||||||
|
let path = "code.png";
|
||||||
|
image
|
||||||
|
.save(&path)
|
||||||
|
.map_err(|e| error!("Failed to save image to {}: {}", path, e))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// let file = InputFileUpload::with_path("CODE.png");
|
||||||
|
// api.send(message.chat.document(&file)).await?;
|
||||||
|
//
|
||||||
|
// // Send an image from disk
|
||||||
|
// api.send( message.chat.photo(&file)).await?;
|
||||||
|
//debug!("{:#?}", formatter);
|
||||||
|
Ok(path.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
140
src/db.rs
140
src/db.rs
@ -1,6 +1,7 @@
|
|||||||
|
#[allow(unused_mut)]
|
||||||
|
#[allow(dead_code)]
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use futures::StreamExt;
|
|
||||||
use rusqlite::{named_params, params, Connection, Error, Result};
|
use rusqlite::{named_params, params, Connection, Error, Result};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use telegram_bot::*;
|
use telegram_bot::*;
|
||||||
@ -35,6 +36,30 @@ pub(crate) fn update_scheme() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn load_stopwords() -> Result<()> {
|
||||||
|
info!("Populating stop words wait please.");
|
||||||
|
let conn = open()?;
|
||||||
|
for table in include_str!("../assets/stop-words.txt")
|
||||||
|
.split('\n')
|
||||||
|
.into_iter()
|
||||||
|
{
|
||||||
|
let word = table.trim();
|
||||||
|
if word != "" {
|
||||||
|
let mut _stmt = conn
|
||||||
|
.prepare_cached(
|
||||||
|
"
|
||||||
|
INSERT OR IGNORE INTO
|
||||||
|
stop_words('word')
|
||||||
|
VALUES (:word)
|
||||||
|
",
|
||||||
|
)?
|
||||||
|
.insert(params![word]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("Stop words updated.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_user(id: telegram_bot::UserId) -> Result<telegram_bot::User, errors::Error> {
|
pub(crate) fn get_user(id: telegram_bot::UserId) -> Result<telegram_bot::User, errors::Error> {
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let mut stmt = conn.prepare_cached(
|
let mut stmt = conn.prepare_cached(
|
||||||
@ -55,7 +80,7 @@ pub(crate) fn get_user(id: telegram_bot::UserId) -> Result<telegram_bot::User, e
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if users.len() == 0 {
|
if users.is_empty() {
|
||||||
Err(errors::Error::UserNotFound)
|
Err(errors::Error::UserNotFound)
|
||||||
} else {
|
} else {
|
||||||
Ok(users[0].clone())
|
Ok(users[0].clone())
|
||||||
@ -75,14 +100,14 @@ pub(crate) fn get_conf(id: telegram_bot::ChatId) -> Result<Conf, errors::Error>
|
|||||||
date: row.get(2)?,
|
date: row.get(2)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if confs.len() == 0 {
|
if confs.is_empty() {
|
||||||
Err(errors::Error::ConfNotFound)
|
Err(errors::Error::ConfNotFound)
|
||||||
} else {
|
} else {
|
||||||
Ok(confs[0].clone())
|
Ok(confs[0].clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#[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,7 +126,7 @@ pub(crate) fn get_confs() -> Result<Vec<Conf>> {
|
|||||||
|
|
||||||
Ok(confs)
|
Ok(confs)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
pub(crate) async fn get_messages_random_all() -> 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")?;
|
||||||
@ -136,6 +161,7 @@ pub(crate) async fn get_messages_random_group(
|
|||||||
Ok(messages)
|
Ok(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) async fn get_messages_user_group(
|
pub(crate) async fn get_messages_user_group(
|
||||||
message: &telegram_bot::Message,
|
message: &telegram_bot::Message,
|
||||||
) -> Result<Vec<String>, Error> {
|
) -> Result<Vec<String>, Error> {
|
||||||
@ -180,18 +206,29 @@ pub(crate) async fn get_messages_user_all(
|
|||||||
Ok(messages)
|
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, limit: u32) -> Result<Vec<telegram_bot::User>> {
|
||||||
|
let where_statement = if limit > 0 {
|
||||||
|
format!("and days_seen <= {}", limit)
|
||||||
|
} else {
|
||||||
|
"".into()
|
||||||
|
};
|
||||||
|
debug!("{}", where_statement);
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let mut stmt = conn.prepare_cached(
|
let mut stmt = conn.prepare_cached(&format!(
|
||||||
"
|
"
|
||||||
SELECT DISTINCT(u.username), u.id, u.first_name, u.last_name, u.date
|
SELECT DISTINCT(u.username), u.id, u.first_name, u.last_name, u.date,
|
||||||
|
(strftime('%s','now')-r.date)/60/60/24 as days_seen
|
||||||
FROM relations r
|
FROM relations r
|
||||||
JOIN user u
|
JOIN user u
|
||||||
ON u.id = r.user_id
|
ON u.id = r.user_id
|
||||||
LEFT JOIN conf c
|
LEFT JOIN conf c
|
||||||
ON r.conf_id = c.id
|
ON r.conf_id = c.id
|
||||||
WHERE c.id = :id",
|
WHERE c.id = :id
|
||||||
)?;
|
{}
|
||||||
|
GROUP BY u.id
|
||||||
|
ORDER BY r.date DESC",
|
||||||
|
where_statement
|
||||||
|
))?;
|
||||||
let mut rows = stmt.query_named(&[(":id", &id.to_string())])?;
|
let mut rows = stmt.query_named(&[(":id", &id.to_string())])?;
|
||||||
let mut users = Vec::new();
|
let mut users = Vec::new();
|
||||||
|
|
||||||
@ -214,7 +251,7 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
|||||||
|
|
||||||
match get_conf(message.chat.id()) {
|
match get_conf(message.chat.id()) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
//info!("Group found: {:?}", message.chat.id());
|
debug!("Group found: {:?}", message.chat.id());
|
||||||
let update = Conf {
|
let update = Conf {
|
||||||
id: message.chat.id(),
|
id: message.chat.id(),
|
||||||
title,
|
title,
|
||||||
@ -228,10 +265,10 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
|||||||
id = :id",
|
id = :id",
|
||||||
)?;
|
)?;
|
||||||
stmt.execute_named(&[(":id", &update.id.to_string()), (":title", &update.title)])?;
|
stmt.execute_named(&[(":id", &update.id.to_string()), (":title", &update.title)])?;
|
||||||
//info!("Conf {:?} updated: {:?}", update.title, get_conf(update.id));
|
debug!("Conf {:?} updated: {:?}", update.title, get_conf(update.id));
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
//info!("Group didn't found: {:?}", message.chat.id());
|
debug!("Group didn't found: {:?}", message.chat.id());
|
||||||
|
|
||||||
let update = Conf {
|
let update = Conf {
|
||||||
id: message.chat.id(),
|
id: message.chat.id(),
|
||||||
@ -250,7 +287,7 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
|||||||
(":title", &update.title),
|
(":title", &update.title),
|
||||||
(":date", &unix_time),
|
(":date", &unix_time),
|
||||||
])?;
|
])?;
|
||||||
//info!("Conf {:?} added: {:?}", update.title, get_conf(update.id));
|
debug!("Conf {:?} added: {:?}", update.title, get_conf(update.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -283,7 +320,11 @@ pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
|
|||||||
(":first_name", &update.first_name),
|
(":first_name", &update.first_name),
|
||||||
(":last_name", &update.last_name),
|
(":last_name", &update.last_name),
|
||||||
])?;
|
])?;
|
||||||
//println!("User {} updated: {:?}", update.first_name, get_user(user.id));
|
debug!(
|
||||||
|
"User {} updated: {:?}",
|
||||||
|
update.first_name,
|
||||||
|
get_user(update.id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let unix_time = SystemTime::now()
|
let unix_time = SystemTime::now()
|
||||||
@ -310,7 +351,7 @@ pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
|
|||||||
(":last_name", &user.last_name),
|
(":last_name", &user.last_name),
|
||||||
(":date", &unix_time),
|
(":date", &unix_time),
|
||||||
])?;
|
])?;
|
||||||
//println!("User added: {:?}", user);
|
debug!("User added: {:?}", user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -345,14 +386,12 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_word(word: &String) -> Result<i64, errors::Error> {
|
async fn add_word(word: &str) -> Result<i64, errors::Error> {
|
||||||
match get_stop_word(&word).await {
|
if get_stop_word(&word).await.is_err() {
|
||||||
Err(_) => return Err(errors::Error::WordInStopList),
|
return Err(errors::Error::WordInStopList);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let word_rowid =
|
let word_rowid =
|
||||||
@ -366,7 +405,7 @@ async fn add_word(word: &String) -> Result<i64, errors::Error> {
|
|||||||
Ok(word_rowid)
|
Ok(word_rowid)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_stop_word(stop_word: &String) -> Result<(), errors::Error> {
|
async fn get_stop_word(stop_word: &str) -> Result<(), errors::Error> {
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
match conn.execute_named(
|
match conn.execute_named(
|
||||||
"SELECT rowid FROM stop_words WHERE word = (:stop_word)",
|
"SELECT rowid FROM stop_words WHERE word = (:stop_word)",
|
||||||
@ -400,6 +439,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,
|
||||||
@ -418,6 +458,7 @@ pub(crate) async fn add_sentence(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Save stemmed words
|
// Save stemmed words
|
||||||
|
debug!("Going to stem: {}", text);
|
||||||
let words = mystem.stemming(text)?;
|
let words = mystem.stemming(text)?;
|
||||||
conn.execute("BEGIN TRANSACTION", params![]);
|
conn.execute("BEGIN TRANSACTION", params![]);
|
||||||
for word in words {
|
for word in words {
|
||||||
@ -432,7 +473,7 @@ pub(crate) async fn add_sentence(
|
|||||||
Err(e) => panic!("SQLITE3 Error: Relations failed: {:?}", e),
|
Err(e) => panic!("SQLITE3 Error: Relations failed: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => debug!("Word {} is in stop list.", &word.lex[0].lex),
|
Err(_) => debug!("Word {} is in a stop list.", &word.lex[0].lex),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn.execute("END TRANSACTION", params![]);
|
conn.execute("END TRANSACTION", params![]);
|
||||||
@ -471,3 +512,56 @@ pub(crate) async fn get_top(
|
|||||||
}
|
}
|
||||||
Ok(top)
|
Ok(top)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn get_global_top() -> Result<Vec<TopWord>, errors::Error> {
|
||||||
|
let conn = open()?;
|
||||||
|
let mut stmt = conn.prepare_cached(
|
||||||
|
"
|
||||||
|
SELECT w.word, COUNT(*) as count FROM relations r
|
||||||
|
LEFT JOIN word w ON w.id = r.word_id
|
||||||
|
GROUP BY w.word
|
||||||
|
ORDER BY count DESC
|
||||||
|
LIMIT 50
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut rows = stmt.query_named(named_params! {})?;
|
||||||
|
let mut top = Vec::new();
|
||||||
|
|
||||||
|
while let Some(row) = rows.next()? {
|
||||||
|
top.push(TopWord {
|
||||||
|
word: row.get(0)?,
|
||||||
|
count: row.get(1)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(top)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn get_conf_top(
|
||||||
|
message: &telegram_bot::Message,
|
||||||
|
) -> Result<Vec<TopWord>, errors::Error> {
|
||||||
|
let conf_id = i64::from(message.chat.id());
|
||||||
|
|
||||||
|
let conn = open()?;
|
||||||
|
let mut stmt = conn.prepare_cached(
|
||||||
|
"
|
||||||
|
SELECT w.word, COUNT(*) as count FROM relations r
|
||||||
|
LEFT JOIN word w ON w.id = r.word_id
|
||||||
|
WHERE r.conf_id = :conf_id
|
||||||
|
GROUP BY w.word
|
||||||
|
ORDER BY count DESC
|
||||||
|
LIMIT 10
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut rows = stmt.query_named(named_params! {":conf_id": conf_id})?;
|
||||||
|
let mut top = Vec::new();
|
||||||
|
|
||||||
|
while let Some(row) = rows.next()? {
|
||||||
|
top.push(TopWord {
|
||||||
|
word: row.get(0)?,
|
||||||
|
count: row.get(1)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(top)
|
||||||
|
}
|
||||||
|
@ -20,51 +20,83 @@ pub enum Error {
|
|||||||
JsonParseError(serde_error),
|
JsonParseError(serde_error),
|
||||||
PopenError(popen_error),
|
PopenError(popen_error),
|
||||||
MystemError(mystem_error),
|
MystemError(mystem_error),
|
||||||
|
SQLBannedCommand(String),
|
||||||
|
SQLInvalidCommand,
|
||||||
|
SQLResultTooLong(String),
|
||||||
|
CodeHighlightningError,
|
||||||
}
|
}
|
||||||
|
|
||||||
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.")
|
||||||
|
// match self {
|
||||||
|
// _ => write!(f, "An error occurred."),
|
||||||
|
// // Error::UserNotFound => {}
|
||||||
|
// // Error::SQLITE3Error(_) => {}
|
||||||
|
// // Error::TelegramError(_) => {}
|
||||||
|
// // Error::ReqwestError(_) => {}
|
||||||
|
// // Error::ConfNotFound => {}
|
||||||
|
// // Error::WordNotFound => {}
|
||||||
|
// // Error::WordInStopList => {}
|
||||||
|
// // Error::IOError(_) => {}
|
||||||
|
// // Error::FileNotFound => {}
|
||||||
|
// // Error::JsonParseError(_) => {}
|
||||||
|
// // Error::PopenError(_) => {}
|
||||||
|
// // Error::MystemError(_) => {}
|
||||||
|
// // Error::SQLBannedCommand(_) => {}
|
||||||
|
// // Error::SQLInvalidCommand => {}
|
||||||
|
// // Error::SQLResultTooLong(_) => {}
|
||||||
|
// // Error::CodeHighlightningError(Help) => write!(f, "Code highlighter.\
|
||||||
|
// // <b>Usage</b><pre>/CODE\
|
||||||
|
// // #<theme>\
|
||||||
|
// // <CODE>\
|
||||||
|
// // #<lang></pre>\
|
||||||
|
// // \
|
||||||
|
// // List of themes:\
|
||||||
|
// // .")
|
||||||
|
// Error::CodeHighlightningError(help) => write!(f, "{}", help.description)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<sqlite_error> for Error {
|
impl From<sqlite_error> for Error {
|
||||||
fn from(e: sqlite_error) -> Error {
|
fn from(e: sqlite_error) -> Error {
|
||||||
return Error::SQLITE3Error(e);
|
Error::SQLITE3Error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<tg_error> for Error {
|
impl From<tg_error> for Error {
|
||||||
fn from(e: tg_error) -> Error {
|
fn from(e: tg_error) -> Error {
|
||||||
return Error::TelegramError(e);
|
Error::TelegramError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<reqwest_error> for Error {
|
impl From<reqwest_error> for Error {
|
||||||
fn from(e: reqwest_error) -> Error {
|
fn from(e: reqwest_error) -> Error {
|
||||||
return Error::ReqwestError(e);
|
Error::ReqwestError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io_error> for Error {
|
impl From<io_error> for Error {
|
||||||
fn from(e: io_error) -> Error {
|
fn from(e: io_error) -> Error {
|
||||||
return Error::IOError(e);
|
Error::IOError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<serde_error> for Error {
|
impl From<serde_error> for Error {
|
||||||
fn from(e: serde_error) -> Error {
|
fn from(e: serde_error) -> Error {
|
||||||
return Error::JsonParseError(e);
|
Error::JsonParseError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<popen_error> for Error {
|
impl From<popen_error> for Error {
|
||||||
fn from(e: popen_error) -> Error {
|
fn from(e: popen_error) -> Error {
|
||||||
return Error::PopenError(e);
|
Error::PopenError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<mystem_error> for Error {
|
impl From<mystem_error> for Error {
|
||||||
fn from(e: mystem_error) -> Error {
|
fn from(e: mystem_error) -> Error {
|
||||||
return Error::MystemError(e);
|
Error::MystemError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
153
src/handlers.rs
153
src/handlers.rs
@ -1,10 +1,15 @@
|
|||||||
use crate::commands;
|
//use crate::commands::Command;
|
||||||
|
use crate::commands::{
|
||||||
|
Code, ConfTop, Execute, GlobalTop, Here, Markov, MarkovAll, Omedeto, Scheme, Sql, Top,
|
||||||
|
};
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use mystem::MyStem;
|
use mystem::MyStem;
|
||||||
use telegram_bot::*;
|
use telegram_bot::*;
|
||||||
|
|
||||||
|
include!("../assets/help_text.rs");
|
||||||
|
|
||||||
pub async fn handler(
|
pub async fn handler(
|
||||||
api: Api,
|
api: Api,
|
||||||
message: Message,
|
message: Message,
|
||||||
@ -21,17 +26,141 @@ pub async fn handler(
|
|||||||
title,
|
title,
|
||||||
&message.from.id,
|
&message.from.id,
|
||||||
&message.from.first_name,
|
&message.from.first_name,
|
||||||
data
|
data.replace("\n", " ")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let cleaned_message = data.replace(&format!("@{}", me.clone().username.unwrap()), "");
|
||||||
|
match cleaned_message.as_str() {
|
||||||
|
s if s.to_string().starts_with("/code") => {
|
||||||
|
match {
|
||||||
|
Code {
|
||||||
|
data: s.replace("/code", ""),
|
||||||
|
}
|
||||||
|
.exec_with_result(&api, &message)
|
||||||
|
.await
|
||||||
|
} {
|
||||||
|
Ok(path) => {
|
||||||
|
let mut cnt_lines = 0;
|
||||||
|
for _ in s.lines() {
|
||||||
|
cnt_lines = cnt_lines + 1;
|
||||||
|
}
|
||||||
|
let mut cnt_chars = 0;
|
||||||
|
for _ in s.chars() {
|
||||||
|
cnt_chars = cnt_chars + 1;
|
||||||
|
}
|
||||||
|
let file = InputFileUpload::with_path(path.clone());
|
||||||
|
info!("lines: {}, chars: {}", cnt_lines, cnt_chars);
|
||||||
|
// api.send(message.chat.document(&file)).await?;
|
||||||
|
//
|
||||||
|
// // Send an image from disk
|
||||||
|
if cnt_chars > 4000 {
|
||||||
|
let _ = api
|
||||||
|
.send(message.text_reply(CODE_HELP).parse_mode(ParseMode::Html))
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if cnt_lines < 81 {
|
||||||
|
api.send(message.chat.photo(&file)).await?;
|
||||||
|
} else {
|
||||||
|
api.send(message.chat.document(&file)).await?;
|
||||||
|
}
|
||||||
|
//debug!("{:#?}", formatter);
|
||||||
|
let _ = std::fs::remove_file(&path);
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
let _ = api
|
||||||
|
.send(message.text_reply(CODE_HELP).parse_mode(ParseMode::Html))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s if s.contains("/here")
|
||||||
|
|| s.contains("@here")
|
||||||
|
|| s.contains("/хере")
|
||||||
|
|| s.contains("@хере")
|
||||||
|
|| s.contains("@all")
|
||||||
|
|| s.contains("\"руку")
|
||||||
|
|| s.contains("\"хере") =>
|
||||||
|
{
|
||||||
db::add_sentence(&message, mystem).await?;
|
db::add_sentence(&message, mystem).await?;
|
||||||
match data.as_str() {
|
Here {
|
||||||
"/here" => commands::here(api, message).await?,
|
data: "".to_string(),
|
||||||
"/top" => commands::top(api, message).await?,
|
}
|
||||||
"/stat" => commands::top(api, message).await?,
|
.exec(&api, &message)
|
||||||
"/markov_all" => commands::markov_all(api, message).await?,
|
.await?
|
||||||
"/markov" => commands::markov(api, message).await?,
|
}
|
||||||
"/omedeto" => commands::omedeto(api, message, mystem).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" | "/stat" => {
|
||||||
|
Top {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec(&api, &message)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
"/global_top" | "/global_stat" => {
|
||||||
|
GlobalTop {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec(&api, &message)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
"/conf_stat" | "/conf_top" => {
|
||||||
|
ConfTop {
|
||||||
|
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?
|
||||||
|
}
|
||||||
|
s if s == "/scheme" || s == "/schema" => {
|
||||||
|
Scheme {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec(&api, &message)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
"/omedeto" => {
|
||||||
|
Omedeto {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec_mystem(&api, &message, mystem)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
_ => db::add_sentence(&message, mystem).await?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessageKind::Photo { ref caption, .. } => {
|
MessageKind::Photo { ref caption, .. } => {
|
||||||
@ -42,7 +171,7 @@ pub async fn handler(
|
|||||||
title,
|
title,
|
||||||
&message.from.id,
|
&message.from.id,
|
||||||
&message.from.first_name,
|
&message.from.first_name,
|
||||||
caption.clone().unwrap_or("NO_TITLE".to_string())
|
caption.clone().unwrap_or_else(|| "NO_TITLE".to_string())
|
||||||
);
|
);
|
||||||
utils::get_files(api, message, token).await?;
|
utils::get_files(api, message, token).await?;
|
||||||
}
|
}
|
||||||
@ -55,7 +184,7 @@ pub async fn handler(
|
|||||||
title,
|
title,
|
||||||
&message.from.id,
|
&message.from.id,
|
||||||
&message.from.first_name,
|
&message.from.first_name,
|
||||||
caption.clone().unwrap_or("NO_TITLE".to_string())
|
caption.clone().unwrap_or_else(|| "NO_TITLE".to_string())
|
||||||
);
|
);
|
||||||
utils::get_files(api, message, token).await?;
|
utils::get_files(api, message, token).await?;
|
||||||
}
|
}
|
||||||
|
34
src/main.rs
34
src/main.rs
@ -1,4 +1,6 @@
|
|||||||
|
#![allow(unreachable_code)]
|
||||||
use std::{env, process};
|
use std::{env, process};
|
||||||
|
use tokio::time::{delay_for, Duration};
|
||||||
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use telegram_bot::*;
|
use telegram_bot::*;
|
||||||
@ -16,7 +18,7 @@ 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::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||||
let mut mystem = match MyStem::new() {
|
let mut mystem = match MyStem::new() {
|
||||||
Ok(mystem) => mystem,
|
Ok(mystem) => mystem,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -28,6 +30,10 @@ async fn main() -> Result<(), errors::Error> {
|
|||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => panic!("Database error: {:?}", e),
|
Err(e) => panic!("Database error: {:?}", e),
|
||||||
}
|
}
|
||||||
|
match db::load_stopwords() {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => panic!("Database error: {:?}", e),
|
||||||
|
}
|
||||||
let token = match env::var("TELEGRAM_BOT_TOKEN") {
|
let token = match env::var("TELEGRAM_BOT_TOKEN") {
|
||||||
Ok(token) => token,
|
Ok(token) => token,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@ -44,13 +50,33 @@ async fn main() -> Result<(), errors::Error> {
|
|||||||
me.first_name,
|
me.first_name,
|
||||||
me.id
|
me.id
|
||||||
);
|
);
|
||||||
|
loop {
|
||||||
while let Some(update) = stream.next().await {
|
while let Some(update) = stream.next().await {
|
||||||
let update = update?;
|
match update {
|
||||||
if let UpdateKind::Message(message) = update.kind {
|
Ok(u) => {
|
||||||
|
if let UpdateKind::Message(message) = u.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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Telegram API Error: {:?}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
delay_for(Duration::from_secs(2)).await;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -13,15 +13,14 @@ pub(crate) fn get_title(message: &Message) -> String {
|
|||||||
match &message.chat {
|
match &message.chat {
|
||||||
MessageChat::Supergroup(chat) => chat.title.clone(),
|
MessageChat::Supergroup(chat) => chat.title.clone(),
|
||||||
MessageChat::Group(chat) => chat.title.clone(),
|
MessageChat::Group(chat) => chat.title.clone(),
|
||||||
MessageChat::Private(_) => format!("PRIVATE"),
|
MessageChat::Private(_) => "PRIVATE".to_string(),
|
||||||
_ => "PRIVATE".to_string(),
|
_ => "PRIVATE".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn create_dir(dir: &String) -> () {
|
pub(crate) async fn create_dir(dir: &str) {
|
||||||
match fs_create_dir(dir) {
|
if fs_create_dir(dir).is_ok() {
|
||||||
Ok(_) => info!("Dir {} created.", dir),
|
info!("Dir {} created.", dir)
|
||||||
Err(_) => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user