Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
bb06d2678c | ||
|
f5a83a0c90 | ||
|
064565ff00 | ||
|
90fdef4363 | ||
|
df99275455 | ||
|
325c0b8207 | ||
|
23bcdf63c8 | ||
|
c80c2a08a3 | ||
|
6cbb55ed89 | ||
|
3bc14ce343 | ||
|
e02bca8ad2 | ||
|
fe13b65016 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
target
|
target
|
||||||
.direnv
|
.direnv
|
||||||
*.db
|
*.db
|
||||||
|
deploy/**/config
|
140
Cargo.lock
generated
140
Cargo.lock
generated
@ -502,6 +502,7 @@ version = "1.0.83"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -587,6 +588,32 @@ version = "0.9.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const_fn"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const_format"
|
||||||
|
version = "0.2.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673"
|
||||||
|
dependencies = [
|
||||||
|
"const_format_proc_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const_format_proc_macros"
|
||||||
|
version = "0.2.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -1040,6 +1067,19 @@ version = "0.28.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "git2"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.1",
|
||||||
|
"libc",
|
||||||
|
"libgit2-sys",
|
||||||
|
"log",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -1086,8 +1126,10 @@ dependencies = [
|
|||||||
"migration",
|
"migration",
|
||||||
"models",
|
"models",
|
||||||
"rand",
|
"rand",
|
||||||
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"sea-orm",
|
"sea-orm",
|
||||||
|
"shadow-rs",
|
||||||
"strfmt",
|
"strfmt",
|
||||||
"teloxide",
|
"teloxide",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -1346,6 +1388,12 @@ version = "2.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_debug"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06d198e9919d9822d5f7083ba8530e04de87841eaf21ead9af8f2304efd57c89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@ -1370,6 +1418,15 @@ version = "1.0.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.65"
|
version = "0.3.65"
|
||||||
@ -1403,6 +1460,18 @@ version = "0.2.149"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libgit2-sys"
|
||||||
|
version = "0.16.1+1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2a2bb3680b094add03bb3732ec520ece34da31a8cd2d633d1389d0f0fb60d0c"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"libz-sys",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@ -1420,6 +1489,18 @@ dependencies = [
|
|||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libz-sys"
|
||||||
|
version = "1.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "295c17e837573c8c821dbaeb3cceb3d745ad082f7572191409e69cbc1b3fd050"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@ -1648,6 +1729,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.32.1"
|
version = "0.32.1"
|
||||||
@ -2559,6 +2649,19 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shadow-rs"
|
||||||
|
version = "0.26.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "878cb1e3162d98ee1016b832efbb683ad6302b462a2894c54f488dc0bd96f11c"
|
||||||
|
dependencies = [
|
||||||
|
"const_format",
|
||||||
|
"git2",
|
||||||
|
"is_debug",
|
||||||
|
"time",
|
||||||
|
"tzdb",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@ -3105,6 +3208,8 @@ checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
"libc",
|
||||||
|
"num_threads",
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde",
|
"serde",
|
||||||
"time-core",
|
"time-core",
|
||||||
@ -3280,6 +3385,35 @@ version = "1.17.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tz-rs"
|
||||||
|
version = "0.6.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33851b15c848fad2cf4b105c6bb66eb9512b6f6c44a4b13f57c53c73c707e2b4"
|
||||||
|
dependencies = [
|
||||||
|
"const_fn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzdb"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b580f6b365fa89f5767cdb619a55d534d04a4e14c2d7e5b9a31e94598687fb1"
|
||||||
|
dependencies = [
|
||||||
|
"iana-time-zone",
|
||||||
|
"tz-rs",
|
||||||
|
"tzdb_data",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzdb_data"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "629555d2921f3f0dc0de98699415a8b2b61dfcd3a0b082a327f7ed748bbb2b76"
|
||||||
|
dependencies = [
|
||||||
|
"tz-rs",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
@ -3316,6 +3450,12 @@ version = "1.10.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode_categories"
|
name = "unicode_categories"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -4,15 +4,20 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A boring bot for hanging your boss up."
|
description = "A boring bot for hanging your boss up."
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[build-dependencies]
|
||||||
|
shadow-rs = "^0.26.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
shadow-rs = "^0.26.0"
|
||||||
wd_log = "0.2.0"
|
wd_log = "0.2.0"
|
||||||
futures = "0.3.29"
|
futures = "0.3.29"
|
||||||
strfmt = "^0.2.4"
|
strfmt = "^0.2.4"
|
||||||
reqwest= "^0.11"
|
reqwest= "^0.11"
|
||||||
rand="^0.8.5"
|
rand="^0.8.5"
|
||||||
|
regex = "^1.10.2"
|
||||||
#lazy_static="^1.4.0"
|
#lazy_static="^1.4.0"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
|
@ -4,7 +4,7 @@ ENV RUSTFLAGS="-C target-feature=-crt-static"
|
|||||||
WORKDIR /usr/src/saysthbot
|
WORKDIR /usr/src/saysthbot
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN apk add --no-cache rustup openssl-dev build-base && \
|
RUN apk add --no-cache rustup openssl-dev build-base && \
|
||||||
rustup-init -y --default-toolchain nightly && \
|
rustup-init -y --default-toolchain nightly-2024-02-04 && \
|
||||||
source ${HOME}/.cargo/env && cargo build --release
|
source ${HOME}/.cargo/env && cargo build --release
|
||||||
|
|
||||||
FROM alpine
|
FROM alpine
|
||||||
|
3
build.rs
Normal file
3
build.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() -> shadow_rs::SdResult<()> {
|
||||||
|
shadow_rs::new()
|
||||||
|
}
|
27
deploy/k8s/deployment.yaml
Normal file
27
deploy/k8s/deployment.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: hangitbot
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: hangitbot
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: hangitbot
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: hangitbot
|
||||||
|
image: <Image>
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: "64Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: hangitbot
|
||||||
|
env:
|
||||||
|
- name: API_URL
|
||||||
|
value: https://tgapi.sense-t.eu.org/
|
||||||
|
|
14
deploy/k8s/kustomization.yaml
Normal file
14
deploy/k8s/kustomization.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# yaml-language-server: $schema=https://json.schemastore.org/kustomization.json
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- deployment.yaml
|
||||||
|
secretGenerator:
|
||||||
|
- name: hangitbot
|
||||||
|
files:
|
||||||
|
- config/DATABASE_URI
|
||||||
|
- config/TGBOT_TOKEN
|
||||||
|
- config/GROUP_BANNED
|
||||||
|
images:
|
||||||
|
- name: <Image>
|
||||||
|
newName: ghcr.io/senseab/hangitbot
|
||||||
|
newTag: v0.1.2
|
24
flake.lock
generated
24
flake.lock
generated
@ -5,11 +5,11 @@
|
|||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1698420672,
|
"lastModified": 1721727458,
|
||||||
"narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=",
|
"narHash": "sha256-r/xppY958gmZ4oTfLiHN0ZGuQ+RSTijDblVgVLFi1mw=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "naersk",
|
"repo": "naersk",
|
||||||
"rev": "aeb58d5e8faead8980a807c840232697982d47b9",
|
"rev": "3fb418eaf352498f6b6c30592e3beb63df42ef11",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -21,11 +21,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1699186365,
|
"lastModified": 1728538411,
|
||||||
"narHash": "sha256-Pxrw5U8mBsL3NlrJ6q1KK1crzvSUcdfwb9083sKDrcU=",
|
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a0b3b06b7a82c965ae0bb1d59f6e386fe755001d",
|
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -35,11 +35,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1699186365,
|
"lastModified": 1728538411,
|
||||||
"narHash": "sha256-Pxrw5U8mBsL3NlrJ6q1KK1crzvSUcdfwb9083sKDrcU=",
|
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a0b3b06b7a82c965ae0bb1d59f6e386fe755001d",
|
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -76,11 +76,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1694529238,
|
"lastModified": 1726560853,
|
||||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -75,14 +75,21 @@
|
|||||||
description = lib.mdDoc "Custom telegram api URI";
|
description = lib.mdDoc "Custom telegram api URI";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
groupBanned = mkOption {
|
||||||
|
type = types.listOf types.int;
|
||||||
|
default = [];
|
||||||
|
description = lib.mdDoc "GroupID blacklisted";
|
||||||
|
};
|
||||||
|
|
||||||
extraOptions = mkOption {
|
extraOptions = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = lib.mdDoc "Extra option for bot.";
|
description = lib.mdDoc "Extra option for bot.";
|
||||||
|
default = "";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = let
|
config = let
|
||||||
args = "${cfg.extraOptions} ${if isString cfg.tgUri then "--api-uri ${escapeShellArg cfg.tgUri}" else ""}";
|
args = "${cfg.extraOptions} ${if cfg?tgUri then "--api-uri ${escapeShellArg cfg.tgUri}" else ""} ${if cfg?groupBanned then concatStringsSep " " (lists.concatMap (group: ["-b ${group}"]) cfg.groupBanned) else ""}";
|
||||||
in mkIf cfg.enable {
|
in mkIf cfg.enable {
|
||||||
systemd.services.hangitbot = {
|
systemd.services.hangitbot = {
|
||||||
wantedBy = ["multi-uesr.target"];
|
wantedBy = ["multi-uesr.target"];
|
||||||
|
207
src/commands.rs
207
src/commands.rs
@ -1,25 +1,23 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rand::{rngs::OsRng, Rng};
|
|
||||||
use sea_orm::DbErr;
|
|
||||||
use strfmt::Format;
|
use strfmt::Format;
|
||||||
use teloxide::{
|
use teloxide::{
|
||||||
payloads::SendMessageSetters,
|
payloads::SendMessageSetters,
|
||||||
prelude::Bot,
|
prelude::Bot,
|
||||||
requests::Requester,
|
requests::Requester,
|
||||||
types::{Message, ParseMode},
|
types::{Message, ParseMode},
|
||||||
utils::command::BotCommands,
|
utils::{command::BotCommands, markdown::escape},
|
||||||
RequestError,
|
RequestError,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Args,
|
|
||||||
db_controller::Controller,
|
db_controller::Controller,
|
||||||
messages::{
|
messages::{
|
||||||
BOT_ABOUT, BOT_TEXT_HANGED, BOT_TEXT_HANGED_SELF, BOT_TEXT_IS_CHANNEL, BOT_TEXT_NO_TARGET,
|
BOT_ABOUT, BOT_TEXT_HANG_ANONYMOUS, BOT_TEXT_HANG_BOT, BOT_TEXT_HANG_CHANNEL,
|
||||||
BOT_TEXT_TOP_GLOBAL, BOT_TEXT_TOP_GROUP, BOT_TEXT_TOP_NONE, BOT_TEXT_TOP_TEMPLATE,
|
BOT_TEXT_IS_CHANNEL, BOT_TEXT_NO_TARGET, BOT_TEXT_TOP_GLOBAL, BOT_TEXT_TOP_GROUP,
|
||||||
BOT_TEXT_TOP_TITLE,
|
BOT_TEXT_TOP_NONE, BOT_TEXT_TOP_TEMPLATE, BOT_TEXT_TOP_TITLE,
|
||||||
},
|
},
|
||||||
|
utils::hangit_text,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(BotCommands, PartialEq, Debug, Clone)]
|
#[derive(BotCommands, PartialEq, Debug, Clone)]
|
||||||
@ -44,133 +42,96 @@ impl Default for Commands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
async fn send_text_reply(bot: &Bot, message: &Message, text: String) -> Result<(), RequestError> {
|
||||||
pub struct CommandHandler {
|
bot.send_message(message.chat.id, text)
|
||||||
pub controller: Controller,
|
.reply_to_message_id(message.id)
|
||||||
|
.parse_mode(ParseMode::MarkdownV2)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandHandler {
|
pub async fn help_handler(bot: &Bot, message: &Message) -> Result<(), RequestError> {
|
||||||
pub async fn new(config: &Args) -> Result<Self, DbErr> {
|
send_text_reply(bot, message, Commands::descriptions().to_string()).await
|
||||||
Ok(Self {
|
}
|
||||||
controller: Controller::new(config.database_uri.to_owned()).await?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn init(&self) -> Result<(), DbErr> {
|
pub async fn about_handler(bot: &Bot, message: &Message) -> Result<(), RequestError> {
|
||||||
self.controller.migrate().await
|
send_text_reply(bot, message, BOT_ABOUT.to_string()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_text_reply(
|
pub async fn hangit_handler(
|
||||||
&self,
|
db: &Controller,
|
||||||
bot: &Bot,
|
bot: &Bot,
|
||||||
message: &Message,
|
message: &Message,
|
||||||
text: String,
|
) -> Result<(), RequestError> {
|
||||||
) -> Result<Message, RequestError> {
|
let reply = match message.reply_to_message() {
|
||||||
bot.send_message(message.chat.id, text)
|
Some(reply) => reply,
|
||||||
.reply_to_message_id(message.id)
|
None => {
|
||||||
.parse_mode(ParseMode::MarkdownV2)
|
return send_text_reply(bot, message, BOT_TEXT_NO_TARGET.to_string()).await;
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn help_handler(
|
|
||||||
&self,
|
|
||||||
bot: &Bot,
|
|
||||||
message: &Message,
|
|
||||||
) -> Result<Message, RequestError> {
|
|
||||||
self.send_text_reply(bot, message, Commands::descriptions().to_string())
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn about_handler(
|
|
||||||
&self,
|
|
||||||
bot: &Bot,
|
|
||||||
message: &Message,
|
|
||||||
) -> Result<Message, RequestError> {
|
|
||||||
self.send_text_reply(bot, message, BOT_ABOUT.to_string())
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn hangit_handler(
|
|
||||||
&self,
|
|
||||||
bot: &Bot,
|
|
||||||
message: &Message,
|
|
||||||
) -> Result<Message, RequestError> {
|
|
||||||
let reply = match message.reply_to_message() {
|
|
||||||
Some(reply) => reply,
|
|
||||||
None => {
|
|
||||||
return self
|
|
||||||
.send_text_reply(bot, message, BOT_TEXT_NO_TARGET.to_string())
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match reply.from() {
|
|
||||||
Some(user) => {
|
|
||||||
let is_self = match message.from() {
|
|
||||||
Some(f) => f.first_name == user.first_name,
|
|
||||||
None => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut vars = HashMap::new();
|
|
||||||
|
|
||||||
let index = if is_self {
|
|
||||||
OsRng.gen::<usize>() % BOT_TEXT_HANGED_SELF.len()
|
|
||||||
} else {
|
|
||||||
OsRng.gen::<usize>() % BOT_TEXT_HANGED.len()
|
|
||||||
};
|
|
||||||
|
|
||||||
let text = if is_self {
|
|
||||||
BOT_TEXT_HANGED_SELF[index]
|
|
||||||
} else {
|
|
||||||
BOT_TEXT_HANGED[index]
|
|
||||||
};
|
|
||||||
|
|
||||||
vars.insert("name".to_string(), user.first_name.as_str());
|
|
||||||
|
|
||||||
let _ = self
|
|
||||||
.controller
|
|
||||||
.hangit(&user.full_name(), message.chat.id)
|
|
||||||
.await;
|
|
||||||
self.send_text_reply(bot, reply, text.format(&vars).unwrap())
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
self.send_text_reply(bot, message, BOT_TEXT_IS_CHANNEL.to_string())
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
pub async fn top_handler(&self, bot: &Bot, message: &Message) -> Result<Message, RequestError> {
|
match reply.from() {
|
||||||
let chat = &message.chat;
|
Some(user) => {
|
||||||
let scope = match chat.is_group() || chat.is_supergroup() {
|
if user.is_bot {
|
||||||
true => BOT_TEXT_TOP_GROUP,
|
return send_text_reply(bot, message, BOT_TEXT_HANG_BOT.to_string()).await;
|
||||||
false => BOT_TEXT_TOP_GLOBAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut index = 1;
|
|
||||||
let mut text = format!("{}\\-{}\n\n", BOT_TEXT_TOP_TITLE, scope);
|
|
||||||
let results = match self.controller.top(chat).await {
|
|
||||||
Some(result) => result,
|
|
||||||
None => {
|
|
||||||
return self
|
|
||||||
.send_text_reply(bot, message, BOT_TEXT_TOP_NONE.to_string())
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
for result in results {
|
if user.is_anonymous() {
|
||||||
let mut vars: HashMap<String, String> = HashMap::new();
|
return send_text_reply(bot, message, BOT_TEXT_HANG_ANONYMOUS.to_string()).await;
|
||||||
|
}
|
||||||
|
|
||||||
vars.insert("name".to_string(), result.name);
|
if user.is_channel() {
|
||||||
vars.insert("count".to_string(), result.counts.to_string());
|
return send_text_reply(bot, message, BOT_TEXT_HANG_CHANNEL.to_string()).await;
|
||||||
|
}
|
||||||
|
|
||||||
let record = BOT_TEXT_TOP_TEMPLATE.format(&vars).unwrap();
|
let is_self = match message.from() {
|
||||||
|
Some(f) => f.first_name == user.first_name,
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
|
||||||
text = format!("{}{}\\. {}\n", text, index, record);
|
let _ = db.hangit(&user.full_name(), message.chat.id).await;
|
||||||
index += 1;
|
send_text_reply(
|
||||||
|
bot,
|
||||||
|
reply,
|
||||||
|
hangit_text(user.first_name.to_string(), is_self, true),
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
None => send_text_reply(bot, message, BOT_TEXT_IS_CHANNEL.to_string()).await,
|
||||||
self.send_text_reply(bot, message, text).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn top_handler(
|
||||||
|
db: &Controller,
|
||||||
|
bot: &Bot,
|
||||||
|
message: &Message,
|
||||||
|
) -> Result<(), RequestError> {
|
||||||
|
let chat = &message.chat;
|
||||||
|
let scope = match chat.is_group() || chat.is_supergroup() {
|
||||||
|
true => BOT_TEXT_TOP_GROUP,
|
||||||
|
false => BOT_TEXT_TOP_GLOBAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut index = 1;
|
||||||
|
let mut text = format!("{}\\-{}\n\n", BOT_TEXT_TOP_TITLE, scope);
|
||||||
|
let results = match db.top(chat).await {
|
||||||
|
Some(result) => result,
|
||||||
|
None => {
|
||||||
|
return send_text_reply(bot, message, BOT_TEXT_TOP_NONE.to_string()).await;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for result in results {
|
||||||
|
let mut vars: HashMap<String, String> = HashMap::new();
|
||||||
|
|
||||||
|
vars.insert("name".to_string(), escape(result.name.as_str()));
|
||||||
|
vars.insert("count".to_string(), result.counts.to_string());
|
||||||
|
|
||||||
|
let record = BOT_TEXT_TOP_TEMPLATE.format(&vars).unwrap();
|
||||||
|
|
||||||
|
text = format!("{}{}\\. {}\n", text, index, record);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_text_reply(bot, message, text).await
|
||||||
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use shadow_rs::shadow;
|
||||||
|
|
||||||
const DEFAULT_DATABASE: &'static str = "sqlite:///hangitbot.db";
|
const DEFAULT_DATABASE: &'static str = "sqlite:///hangitbot.db";
|
||||||
const DEFAULT_API_URL: &'static str = "https://api.telegram.org";
|
const DEFAULT_API_URL: &'static str = "https://api.telegram.org";
|
||||||
|
|
||||||
|
shadow!(build);
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version=build::TAG, about, long_about = None)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Enable debug mode
|
/// Enable debug mode
|
||||||
#[clap(short = 'D', long, value_parser, default_value_t = false)]
|
#[clap(short = 'D', long, value_parser, default_value_t = false)]
|
||||||
@ -21,4 +24,8 @@ pub struct Args {
|
|||||||
/// Api Server URL
|
/// Api Server URL
|
||||||
#[clap(long, value_parser, env = "API_URL", default_value=DEFAULT_API_URL)]
|
#[clap(long, value_parser, env = "API_URL", default_value=DEFAULT_API_URL)]
|
||||||
pub api_url: String,
|
pub api_url: String,
|
||||||
|
|
||||||
|
/// GroupID blacklisted
|
||||||
|
#[clap(short = 'b', long, value_parser, env = "GROUP_BANNED", value_delimiter = ',', num_args = 1..)]
|
||||||
|
pub group_banned: Vec<i64>
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
use migration::{Migrator, MigratorTrait};
|
use migration::{Migrator, MigratorTrait};
|
||||||
use models::prelude::*;
|
use models::prelude::*;
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
ActiveModelTrait, ColumnTrait, ConnectionTrait, Database, DatabaseConnection,
|
prelude::BigDecimal, ActiveModelTrait, ColumnTrait, ConnectionTrait, Database,
|
||||||
DbErr, EntityTrait, QueryFilter, QueryOrder, QuerySelect, QueryTrait, Set, TransactionTrait, FromQueryResult, prelude::BigDecimal,
|
DatabaseConnection, DbErr, EntityTrait, FromQueryResult, QueryFilter, QueryOrder, QuerySelect,
|
||||||
|
QueryTrait, Set, TransactionTrait,
|
||||||
};
|
};
|
||||||
use teloxide::types::{Chat, ChatId};
|
use teloxide::types::{Chat, ChatId};
|
||||||
use wd_log::{log_debug_ln, log_error_ln, log_info_ln, log_warn_ln};
|
use wd_log::{log_debug_ln, log_error_ln, log_info_ln};
|
||||||
|
|
||||||
|
const LIMIT: u64 = 10;
|
||||||
|
|
||||||
#[derive(Debug, FromQueryResult)]
|
#[derive(Debug, FromQueryResult)]
|
||||||
pub struct TopData {
|
pub struct TopData {
|
||||||
@ -14,7 +16,6 @@ pub struct TopData {
|
|||||||
pub counts: BigDecimal,
|
pub counts: BigDecimal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Controller {
|
pub struct Controller {
|
||||||
db: DatabaseConnection,
|
db: DatabaseConnection,
|
||||||
@ -31,8 +32,9 @@ impl Controller {
|
|||||||
/// Do migrate
|
/// Do migrate
|
||||||
pub async fn migrate(&self) -> Result<(), DbErr> {
|
pub async fn migrate(&self) -> Result<(), DbErr> {
|
||||||
if let Err(err) = Migrator::install(&self.db).await {
|
if let Err(err) = Migrator::install(&self.db).await {
|
||||||
log_warn_ln!("{}", err)
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = Migrator::up(&self.db, None).await {
|
if let Err(err) = Migrator::up(&self.db, None).await {
|
||||||
Err(err)
|
Err(err)
|
||||||
} else {
|
} else {
|
||||||
@ -70,9 +72,23 @@ impl Controller {
|
|||||||
transcation.commit().await
|
transcation.commit().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn update_group(&self, name: String, group_id: ChatId) -> Result<(), DbErr> {
|
||||||
|
log_debug_ln!("name={:?}", name);
|
||||||
|
|
||||||
|
let transcation = self.db.begin().await?;
|
||||||
|
match Stats::find().filter(StatsColumn::GroupId.eq(0)).filter(StatsColumn::Name.eq(name)).one(&transcation).await? {
|
||||||
|
Some(one) => {
|
||||||
|
let mut one: StatsActiveModel = one.into();
|
||||||
|
one.group_id = Set(group_id.0);
|
||||||
|
one.save(&transcation).await?;
|
||||||
|
},
|
||||||
|
None => {},
|
||||||
|
}
|
||||||
|
transcation.commit().await
|
||||||
|
}
|
||||||
|
|
||||||
/// stats
|
/// stats
|
||||||
pub async fn top(&self, chat: &Chat) -> Option<Vec<TopData>> {
|
pub async fn top(&self, chat: &Chat) -> Option<Vec<TopData>> {
|
||||||
const LIMIT: u64 = 10;
|
|
||||||
let transcation = match self.db.begin().await {
|
let transcation = match self.db.begin().await {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
@ -81,35 +97,51 @@ impl Controller {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let query = match chat.is_group() || chat.is_supergroup() {
|
let query = Stats::find()
|
||||||
true => {
|
.select_only()
|
||||||
Stats::find()
|
.column(StatsColumn::Name)
|
||||||
.filter(StatsColumn::GroupId.eq(chat.id.0))
|
.column_as(StatsColumn::Counts.sum(), "counts")
|
||||||
.order_by_desc(StatsColumn::Counts)
|
.group_by(StatsColumn::Name)
|
||||||
.limit(LIMIT).into_model()
|
.order_by_desc(StatsColumn::Counts.sum())
|
||||||
.all(&transcation)
|
.limit(LIMIT);
|
||||||
.await
|
|
||||||
|
let query = if chat.is_group() || chat.is_supergroup() {
|
||||||
|
query.filter(StatsColumn::GroupId.eq(chat.id.0))
|
||||||
|
} else {
|
||||||
|
query
|
||||||
|
};
|
||||||
|
|
||||||
|
log_debug_ln!(
|
||||||
|
"SQL: {:?}",
|
||||||
|
query.build(transcation.get_database_backend()).to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = query.into_model().all(&transcation).await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(result) => Some(result),
|
||||||
|
Err(error) => {
|
||||||
|
log_error_ln!("{}", error);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
false => {
|
}
|
||||||
let query = Stats::find()
|
}
|
||||||
.select_only()
|
|
||||||
.column(StatsColumn::Name)
|
|
||||||
.column_as(StatsColumn::Counts.sum(), "counts")
|
|
||||||
.group_by(StatsColumn::Name)
|
|
||||||
.order_by_desc(StatsColumn::Counts.sum())
|
|
||||||
.limit(LIMIT);
|
|
||||||
|
|
||||||
log_debug_ln!(
|
pub async fn find_by_name(&self, name: &String) -> Option<Vec<StatsModel>> {
|
||||||
"SQL: {:?}",
|
let transcation = match self.db.begin().await {
|
||||||
query.build(transcation.get_database_backend()).to_string()
|
Ok(t) => t,
|
||||||
);
|
Err(error) => {
|
||||||
|
log_error_ln!("{}", error);
|
||||||
query.into_model().all(&transcation).await
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match query {
|
let result = Stats::find()
|
||||||
Ok(query) => Some(query),
|
.filter(StatsColumn::Name.contains(name))
|
||||||
|
.limit(LIMIT).all(&transcation).await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(result) => Some(result),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log_error_ln!("{}", error);
|
log_error_ln!("{}", error);
|
||||||
None
|
None
|
||||||
|
78
src/inline_query.rs
Normal file
78
src/inline_query.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
use teloxide::{
|
||||||
|
prelude::Bot,
|
||||||
|
requests::{Request, Requester},
|
||||||
|
types::{
|
||||||
|
ChatId, ChosenInlineResult, InlineQuery, InlineQueryResult, InlineQueryResultArticle,
|
||||||
|
InputMessageContent, InputMessageContentText,
|
||||||
|
},
|
||||||
|
RequestError,
|
||||||
|
};
|
||||||
|
use wd_log::{log_debug_ln, log_error_ln};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
db_controller::Controller,
|
||||||
|
messages::BOT_TEXT_INLINE_HANG,
|
||||||
|
utils::{hangit_text, IS_SELF, NEED_ESCAPE},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn inline_menu(db: &Controller, bot: &Bot, q: InlineQuery) -> Result<(), RequestError> {
|
||||||
|
let name = q.query;
|
||||||
|
|
||||||
|
let mut results = match db.find_by_name(&name).await {
|
||||||
|
Some(list) => list
|
||||||
|
.iter()
|
||||||
|
.map(|n| {
|
||||||
|
InlineQueryResult::Article(InlineQueryResultArticle::new(
|
||||||
|
format!("{},{}", n.id, n.name),
|
||||||
|
format!("{} {}", BOT_TEXT_INLINE_HANG, n.name),
|
||||||
|
InputMessageContent::Text(InputMessageContentText::new(hangit_text(
|
||||||
|
n.name.clone(),
|
||||||
|
q.from.first_name == n.name,
|
||||||
|
!NEED_ESCAPE,
|
||||||
|
))),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
|
||||||
|
None => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
log_debug_ln!("{:?}", results);
|
||||||
|
|
||||||
|
if results.is_empty() {
|
||||||
|
results.push(InlineQueryResult::Article(InlineQueryResultArticle::new(
|
||||||
|
format!("{},{}", 0, name),
|
||||||
|
format!("{} {}", BOT_TEXT_INLINE_HANG, name.clone()),
|
||||||
|
InputMessageContent::Text(InputMessageContentText::new(hangit_text(
|
||||||
|
name.clone(),
|
||||||
|
!IS_SELF,
|
||||||
|
!NEED_ESCAPE,
|
||||||
|
))),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if name.starts_with("@") {
|
||||||
|
results = vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.answer_inline_query(&q.id, results).send().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn inline_anwser(db: &Controller, a: ChosenInlineResult) -> Result<(), RequestError> {
|
||||||
|
log_debug_ln!("{:#?}", a);
|
||||||
|
|
||||||
|
let mut c: Vec<&str> = a.result_id.split(",").collect();
|
||||||
|
c.remove(0);
|
||||||
|
let result_id = c.concat();
|
||||||
|
|
||||||
|
if result_id == "@" {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(err) = db.hangit(&result_id, ChatId(0)).await {
|
||||||
|
log_error_ln!("{:?}", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
123
src/main.rs
123
src/main.rs
@ -1,19 +1,25 @@
|
|||||||
mod commands;
|
mod commands;
|
||||||
mod config;
|
mod config;
|
||||||
mod db_controller;
|
mod db_controller;
|
||||||
|
mod inline_query;
|
||||||
mod messages;
|
mod messages;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use commands::{CommandHandler, Commands};
|
use commands::{about_handler, hangit_handler, help_handler, top_handler, Commands};
|
||||||
use config::Args;
|
use config::Args;
|
||||||
|
|
||||||
|
use db_controller::Controller;
|
||||||
|
use inline_query::{inline_anwser, inline_menu};
|
||||||
use teloxide::{
|
use teloxide::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
requests::{Request, Requester},
|
requests::{Request, Requester},
|
||||||
|
types::{Me, Update},
|
||||||
utils::command::BotCommands,
|
utils::command::BotCommands,
|
||||||
};
|
};
|
||||||
|
use utils::message_handler;
|
||||||
use wd_log::{
|
use wd_log::{
|
||||||
log_debug_ln, log_error_ln, log_info_ln, log_panic, set_level, set_prefix, DEBUG, INFO,
|
log_debug_ln, log_error_ln, log_info_ln, log_panic, set_level, set_prefix, DEBUG, INFO, log_warn_ln,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@ -28,43 +34,85 @@ async fn main() {
|
|||||||
} else {
|
} else {
|
||||||
set_level(INFO);
|
set_level(INFO);
|
||||||
}
|
}
|
||||||
let command_handler = match CommandHandler::new(&args).await {
|
|
||||||
Err(err) => log_panic!("{}", err),
|
let db_controller = match db_controller::Controller::new(args.database_uri.to_owned()).await {
|
||||||
Ok(c) => c,
|
Ok(db) => db,
|
||||||
|
Err(err) => {
|
||||||
|
log_panic!("{:?}", err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
command_handler.init().await.unwrap();
|
if let Err(err) = db_controller.migrate().await {
|
||||||
|
log_panic!("{:?}", err);
|
||||||
|
}
|
||||||
|
|
||||||
let bot = Bot::new(args.tgbot_token.to_owned())
|
let bot = Bot::new(args.tgbot_token.to_owned())
|
||||||
.set_api_url(reqwest::Url::parse(&args.api_url.as_str()).unwrap());
|
.set_api_url(reqwest::Url::parse(&args.api_url.as_str()).unwrap());
|
||||||
|
|
||||||
get_me(&bot).await;
|
let me = get_me(&bot).await;
|
||||||
register_commands(&bot).await;
|
register_commands(&bot).await;
|
||||||
|
|
||||||
Commands::repl(bot, move |bot: Bot, message: Message, cmd: Commands| {
|
let handler = dptree::entry()
|
||||||
let command_handler = command_handler.clone();
|
.branch(
|
||||||
|
Update::filter_message()
|
||||||
|
.branch(dptree::entry().filter_command::<Commands>().endpoint(
|
||||||
|
|db: Controller, black_list: Vec<i64>, bot: Bot, message: Message, cmd: Commands| async move {
|
||||||
|
if black_list.contains(&message.chat.id.0) {
|
||||||
|
log_warn_ln!("banned group dectected: {:?}", message.chat.id);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let r = match cmd {
|
||||||
|
Commands::Help => help_handler(&bot, &message).await,
|
||||||
|
Commands::About => about_handler(&bot, &message).await,
|
||||||
|
Commands::Top => top_handler(&db, &bot, &message).await,
|
||||||
|
Commands::HangIt => hangit_handler(&db, &bot, &message).await,
|
||||||
|
};
|
||||||
|
|
||||||
async move {
|
match r {
|
||||||
let r = match cmd {
|
Ok(_) => Ok(()),
|
||||||
Commands::Help => command_handler.help_handler(&bot, &message).await,
|
Err(err) => {
|
||||||
Commands::About => command_handler.about_handler(&bot, &message).await,
|
log_error_ln!("{:?}", err);
|
||||||
Commands::Top => command_handler.top_handler(&bot, &message).await,
|
Err(err)
|
||||||
Commands::HangIt => command_handler.hangit_handler(&bot, &message).await,
|
}
|
||||||
};
|
}
|
||||||
|
},
|
||||||
match r {
|
))
|
||||||
Ok(_r) => {
|
.branch(
|
||||||
log_debug_ln!("will send: {:?}", _r.text());
|
dptree::filter(|msg: Message| msg.chat.is_group() || msg.chat.is_supergroup())
|
||||||
Ok(())
|
.endpoint(|db: Controller, message: Message, me: Me, black_list: Vec<i64>| async move {
|
||||||
|
if black_list.contains(&message.chat.id.0) {
|
||||||
|
log_warn_ln!("banned group dectected: {:?}", message.chat.id);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let r = message_handler(&db, message, &me).await;
|
||||||
|
match r {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => {
|
||||||
|
log_error_ln!("{:?}", err);
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.branch(
|
||||||
|
Update::filter_inline_query().endpoint(
|
||||||
|
|db: Controller, bot: Bot, q: InlineQuery| async move {
|
||||||
|
inline_menu(&db, &bot, q).await
|
||||||
},
|
},
|
||||||
Err(err) => {
|
),
|
||||||
log_error_ln!("{:?}", err);
|
)
|
||||||
Err(err)
|
.branch(Update::filter_chosen_inline_result().endpoint(
|
||||||
}
|
|db: Controller, a: ChosenInlineResult| async move { inline_anwser(&db, a).await },
|
||||||
}
|
));
|
||||||
}
|
|
||||||
})
|
Dispatcher::builder(bot, handler)
|
||||||
.await;
|
.dependencies(dptree::deps![db_controller, me, args.group_banned])
|
||||||
|
.default_handler(|upd| async move { log_debug_ln!("unhandled update: {:?}", upd) })
|
||||||
|
.enable_ctrlc_handler()
|
||||||
|
.build()
|
||||||
|
.dispatch()
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn register_commands(bot: &Bot) {
|
async fn register_commands(bot: &Bot) {
|
||||||
@ -75,13 +123,16 @@ async fn register_commands(bot: &Bot) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_me(bot: &Bot) {
|
async fn get_me(bot: &Bot) -> Me {
|
||||||
match bot.get_me().send().await {
|
match bot.get_me().send().await {
|
||||||
Ok(result) => log_info_ln!(
|
Ok(result) => {
|
||||||
"connect succeed: id={}, botname=\"{}\"",
|
log_info_ln!(
|
||||||
result.id,
|
"connect succeed: id={}, botname=\"{}\"",
|
||||||
result.username()
|
result.id,
|
||||||
),
|
result.username()
|
||||||
|
);
|
||||||
|
result
|
||||||
|
}
|
||||||
Err(error) => log_panic!("{}", error),
|
Err(error) => log_panic!("{}", error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ const BOT_TEXT_HANGED_2: &'static str = "因为 {name} 太过逆天,我们把
|
|||||||
const BOT_TEXT_HANGED_3: &'static str = "{name} 吊在了路灯上,TA 兴风作浪的时代结束了……";
|
const BOT_TEXT_HANGED_3: &'static str = "{name} 吊在了路灯上,TA 兴风作浪的时代结束了……";
|
||||||
const BOT_TEXT_HANGED_4: &'static str = "吊在路灯上的 {name} 正在接受大家的鄙视……";
|
const BOT_TEXT_HANGED_4: &'static str = "吊在路灯上的 {name} 正在接受大家的鄙视……";
|
||||||
const BOT_TEXT_HANGED_5: &'static str = "对 {name} 来说,绳命来得快去得也快,只有路灯是永恒的……";
|
const BOT_TEXT_HANGED_5: &'static str = "对 {name} 来说,绳命来得快去得也快,只有路灯是永恒的……";
|
||||||
const BOT_TEXT_HANGED_6: &'static str = "被套上麻袋的 {name} 在经历了一顿胖揍之后,最后还是成了路灯的挂件……";
|
const BOT_TEXT_HANGED_6: &'static str =
|
||||||
|
"被套上麻袋的 {name} 在经历了一顿胖揍之后,最后还是成了路灯的挂件……";
|
||||||
|
|
||||||
pub const BOT_TEXT_HANGED: [&str; 6] = [
|
pub const BOT_TEXT_HANGED: [&str; 6] = [
|
||||||
BOT_TEXT_HANGED_1,
|
BOT_TEXT_HANGED_1,
|
||||||
@ -26,11 +27,17 @@ pub const BOT_TEXT_HANGED: [&str; 6] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const BOT_TEXT_HANGED_SELF_1: &'static str = "{name} 承受不了自己所做的一切,选择了自行了断……";
|
const BOT_TEXT_HANGED_SELF_1: &'static str = "{name} 承受不了自己所做的一切,选择了自行了断……";
|
||||||
const BOT_TEXT_HANGED_SELF_2: &'static str = "对于 {name} 来说,把自己吊在路灯上可能是最好的选择了……";
|
const BOT_TEXT_HANGED_SELF_2: &'static str =
|
||||||
|
"对于 {name} 来说,把自己吊在路灯上可能是最好的选择了……";
|
||||||
const BOT_TEXT_HANGED_SELF_3: &'static str = "{name} 最终还是选择了逃避……";
|
const BOT_TEXT_HANGED_SELF_3: &'static str = "{name} 最终还是选择了逃避……";
|
||||||
|
|
||||||
pub const BOT_TEXT_HANGED_SELF: [&str; 3] = [
|
pub const BOT_TEXT_HANGED_SELF: [&str; 3] = [
|
||||||
BOT_TEXT_HANGED_SELF_1,
|
BOT_TEXT_HANGED_SELF_1,
|
||||||
BOT_TEXT_HANGED_SELF_2,
|
BOT_TEXT_HANGED_SELF_2,
|
||||||
BOT_TEXT_HANGED_SELF_3,
|
BOT_TEXT_HANGED_SELF_3,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub const BOT_TEXT_HANG_BOT: &'static str = "机器人是无法被吊死的……";
|
||||||
|
pub const BOT_TEXT_HANG_CHANNEL: &'static str = "这是个频道……";
|
||||||
|
pub const BOT_TEXT_HANG_ANONYMOUS: &'static str = "这是个幽灵……";
|
||||||
|
pub const BOT_TEXT_INLINE_HANG: &'static str = "吊死";
|
||||||
|
84
src/utils.rs
Normal file
84
src/utils.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use rand::{rngs::OsRng, Rng};
|
||||||
|
use regex::Regex;
|
||||||
|
use strfmt::Format;
|
||||||
|
use teloxide::{
|
||||||
|
types::{Me, Message},
|
||||||
|
utils::markdown::escape,
|
||||||
|
RequestError,
|
||||||
|
};
|
||||||
|
use wd_log::{log_debug_ln, log_error_ln};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
db_controller::Controller,
|
||||||
|
messages::{BOT_TEXT_HANGED, BOT_TEXT_HANGED_SELF},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const IS_SELF: bool = true;
|
||||||
|
pub const NEED_ESCAPE: bool = true;
|
||||||
|
|
||||||
|
pub fn hangit_text(name: String, is_self: bool, need_escape: bool) -> String {
|
||||||
|
let mut vars = HashMap::new();
|
||||||
|
let index = if is_self {
|
||||||
|
OsRng.gen::<usize>() % BOT_TEXT_HANGED_SELF.len()
|
||||||
|
} else {
|
||||||
|
OsRng.gen::<usize>() % BOT_TEXT_HANGED.len()
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = if is_self {
|
||||||
|
BOT_TEXT_HANGED_SELF[index]
|
||||||
|
} else {
|
||||||
|
BOT_TEXT_HANGED[index]
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = if need_escape {
|
||||||
|
escape(name.as_str())
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
};
|
||||||
|
vars.insert("name".to_string(), name.as_str());
|
||||||
|
|
||||||
|
text.format(&vars).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn message_handler(db: &Controller, msg: Message, me: &Me) -> Result<(), RequestError> {
|
||||||
|
let text = match msg.text() {
|
||||||
|
Some(t) => t.to_owned(),
|
||||||
|
None => {
|
||||||
|
log_debug_ln!("{:?}", msg);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let formats = vec![BOT_TEXT_HANGED.to_vec(), BOT_TEXT_HANGED_SELF.to_vec()]
|
||||||
|
.concat()
|
||||||
|
.iter()
|
||||||
|
.map(|i| Regex::new(&format!("^{}$", i.replace("{name}", "(.+)"))).unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if let Some(via_bot) = msg.via_bot {
|
||||||
|
if via_bot.is_bot && via_bot.id == me.id {
|
||||||
|
for f in formats {
|
||||||
|
log_debug_ln!("Regexp {:?}", f);
|
||||||
|
if !f.is_match(text.as_str()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cap) = f.captures(text.as_str()) {
|
||||||
|
if let Some(name) = cap.get(1) {
|
||||||
|
log_debug_ln!("got username: {:?}", name.as_str());
|
||||||
|
if let Err(error) = db
|
||||||
|
.update_group(name.as_str().to_string(), msg.chat.id)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log_error_ln!("{:?}", error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user