Added docker building.

This commit is contained in:
2023-02-21 19:56:36 +00:00
parent f5b43573c8
commit b6ab9c8888
31 changed files with 1476 additions and 75 deletions

View File

@ -7,6 +7,8 @@
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence # See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
stages: stages:
- test - test
- build
- deploy
.test-template: .test-template:
tags: tags:
@ -39,14 +41,50 @@ fmt:
- pre-commit run fmt -av - pre-commit run fmt -av
build_img: build_img:
stage: build
tags: tags:
- kube - kube
only: only:
- master refs:
- master
changes:
- "src/**/*"
- "Cargo.toml"
- "Cargo.lock"
image: image:
name: r.j3ss.co/img name: r.j3ss.co/img
entrypoint: [""] entrypoint: [""]
script: script:
- img login --password "${DOCKER_PASSWORD}" --username "${DOCKER_USER}" "${DOCKER_REGISTRY}" - img login --password "${DOCKER_PASSWORD}" --username "${DOCKER_USER}" "${DOCKER_REGISTRY}"
- img build --no-console -t docker.le-memese.com/bots/s3bot:latest . - img build --no-console -t docker.le-memese.com/bots/s3bot:latest .
- img push docker.le-memese.com/bots/s3bot:latest - img push docker.le-memese.com/bots/s3bot:latest
deploy:
stage: deploy
tags:
- kube
only:
refs:
- master
needs:
- build_img
image:
name: alpine/helm:3.7.1
entrypoint: ["/bin/sh", "-c"]
environment:
name: prod
action: start
url: "https://s3bot.le-memese.com"
script:
- helm
upgrade
s3bot
./deploy/helm
--install
--wait
--create-namespace
--atomic
--timeout 2m
--namespace "$NAMESPACE"
-f "$HELM_CONFIG"

665
Cargo.lock generated
View File

@ -72,7 +72,7 @@ dependencies = [
"mime", "mime",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"rand", "rand 0.8.5",
"sha1 0.10.5", "sha1 0.10.5",
"smallvec", "smallvec",
"tokio", "tokio",
@ -230,7 +230,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [ dependencies = [
"getrandom", "getrandom 0.2.8",
"once_cell", "once_cell",
"version_check", "version_check",
] ]
@ -333,6 +333,19 @@ dependencies = [
"toml", "toml",
] ]
[[package]]
name = "async-compression"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a"
dependencies = [
"flate2",
"futures-core",
"memchr",
"pin-project-lite",
"tokio",
]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.64" version = "0.1.64"
@ -554,6 +567,16 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.3" version = "0.8.3"
@ -774,6 +797,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "fastrand"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
[[package]] [[package]]
name = "fern" name = "fern"
version = "0.6.1" version = "0.6.1"
@ -801,6 +833,21 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.1.0" version = "1.1.0"
@ -810,6 +857,16 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "futf"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
dependencies = [
"mac",
"new_debug_unreachable",
]
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.26" version = "0.3.26"
@ -909,6 +966,17 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.8" version = "0.2.8"
@ -931,7 +999,7 @@ dependencies = [
"num-bigint", "num-bigint",
"num-integer", "num-integer",
"num-traits", "num-traits",
"rand", "rand 0.8.5",
] ]
[[package]] [[package]]
@ -947,6 +1015,7 @@ dependencies = [
"grammers-mtsender", "grammers-mtsender",
"grammers-session", "grammers-session",
"grammers-tl-types", "grammers-tl-types",
"html5ever",
"locate-locale", "locate-locale",
"log", "log",
"md5", "md5",
@ -964,7 +1033,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "573508524fd529ced63fe827fb89629a186414541fd9e645fef9ba499fc69c63" checksum = "573508524fd529ced63fe827fb89629a186414541fd9e645fef9ba499fc69c63"
dependencies = [ dependencies = [
"aes", "aes",
"getrandom", "getrandom 0.2.8",
"glass_pumpkin", "glass_pumpkin",
"hmac", "hmac",
"num-bigint", "num-bigint",
@ -982,7 +1051,7 @@ dependencies = [
"bytes", "bytes",
"crc32fast", "crc32fast",
"flate2", "flate2",
"getrandom", "getrandom 0.2.8",
"grammers-crypto", "grammers-crypto",
"grammers-tl-types", "grammers-tl-types",
"log", "log",
@ -1108,6 +1177,20 @@ dependencies = [
"digest 0.9.0", "digest 0.9.0",
] ]
[[package]]
name = "html5ever"
version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148"
dependencies = [
"log",
"mac",
"markup5ever",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.8" version = "0.2.8"
@ -1119,6 +1202,17 @@ dependencies = [
"itoa", "itoa",
] ]
[[package]]
name = "http-body"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]] [[package]]
name = "http-range" name = "http-range"
version = "0.1.5" version = "0.1.5"
@ -1143,6 +1237,43 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026"
[[package]]
name = "hyper"
version = "0.14.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.53" version = "0.1.53"
@ -1187,6 +1318,15 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "io-lifetimes" name = "io-lifetimes"
version = "1.0.5" version = "1.0.5"
@ -1197,6 +1337,12 @@ dependencies = [
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
[[package]]
name = "ipnet"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
[[package]] [[package]]
name = "is-terminal" name = "is-terminal"
version = "0.4.3" version = "0.4.3"
@ -1322,6 +1468,26 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "mac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "markup5ever"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd"
dependencies = [
"log",
"phf",
"phf_codegen",
"string_cache",
"string_cache_codegen",
"tendril",
]
[[package]] [[package]]
name = "md5" name = "md5"
version = "0.7.0" version = "0.7.0"
@ -1386,6 +1552,30 @@ dependencies = [
"windows-sys 0.42.0", "windows-sys 0.42.0",
] ]
[[package]]
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]] [[package]]
name = "nom" name = "nom"
version = "7.1.3" version = "7.1.3"
@ -1405,7 +1595,7 @@ dependencies = [
"autocfg", "autocfg",
"num-integer", "num-integer",
"num-traits", "num-traits",
"rand", "rand 0.8.5",
] ]
[[package]] [[package]]
@ -1449,6 +1639,51 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
version = "0.10.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7"
dependencies = [
"autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "os_info" name = "os_info"
version = "3.6.0" version = "3.6.0"
@ -1495,7 +1730,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7" checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7"
dependencies = [ dependencies = [
"base64ct", "base64ct",
"rand_core", "rand_core 0.6.4",
"subtle", "subtle",
] ]
@ -1524,6 +1759,63 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "phf"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [
"phf_shared 0.8.0",
]
[[package]]
name = "phf_codegen"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
dependencies = [
"phf_generator 0.8.0",
"phf_shared 0.8.0",
]
[[package]]
name = "phf_generator"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
dependencies = [
"phf_shared 0.8.0",
"rand 0.7.3",
]
[[package]]
name = "phf_generator"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
"phf_shared 0.10.0",
"rand 0.8.5",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
dependencies = [
"siphasher",
]
[[package]]
name = "phf_shared"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
dependencies = [
"siphasher",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.9"
@ -1548,6 +1840,12 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "1.0.4" version = "1.0.4"
@ -1601,6 +1899,20 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc",
"rand_pcg",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.8.5" version = "0.8.5"
@ -1608,8 +1920,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [ dependencies = [
"libc", "libc",
"rand_chacha", "rand_chacha 0.3.1",
"rand_core", "rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core 0.5.1",
] ]
[[package]] [[package]]
@ -1619,7 +1941,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [ dependencies = [
"ppv-lite86", "ppv-lite86",
"rand_core", "rand_core 0.6.4",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.16",
] ]
[[package]] [[package]]
@ -1628,7 +1959,25 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [ dependencies = [
"getrandom", "getrandom 0.2.8",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_pcg"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
dependencies = [
"rand_core 0.5.1",
] ]
[[package]] [[package]]
@ -1679,6 +2028,70 @@ version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "reqwest"
version = "0.11.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9"
dependencies = [
"async-compression",
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
"tokio-rustls",
"tokio-util",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.4.0" version = "0.4.0"
@ -1702,6 +2115,18 @@ dependencies = [
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
[[package]]
name = "rustls"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
dependencies = [
"log",
"ring",
"sct",
"webpki",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.12" version = "1.0.12"
@ -1726,14 +2151,26 @@ dependencies = [
"futures", "futures",
"grammers-client", "grammers-client",
"grammers-session", "grammers-session",
"lazy_static",
"log", "log",
"rand", "rand 0.8.5",
"rayon", "rayon",
"regex",
"reqwest",
"serde", "serde",
"serde_json", "serde_json",
"tokio", "tokio",
] ]
[[package]]
name = "schannel"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
dependencies = [
"windows-sys 0.42.0",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -1746,6 +2183,39 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.16" version = "1.0.16"
@ -1843,6 +2313,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "siphasher"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.7" version = "0.4.7"
@ -1868,6 +2344,38 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "string_cache"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08"
dependencies = [
"new_debug_unreachable",
"once_cell",
"parking_lot",
"phf_shared 0.10.0",
"precomputed-hash",
"serde",
]
[[package]]
name = "string_cache_codegen"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988"
dependencies = [
"phf_generator 0.10.0",
"phf_shared 0.10.0",
"proc-macro2",
"quote",
]
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.10.0"
@ -1891,6 +2399,31 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi 0.3.9",
]
[[package]]
name = "tendril"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
dependencies = [
"futf",
"mac",
"utf-8",
]
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.2.0" version = "1.2.0"
@ -1984,6 +2517,27 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
"rustls",
"tokio",
"webpki",
]
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.7" version = "0.7.7"
@ -2007,6 +2561,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "tower-service"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.37" version = "0.1.37"
@ -2028,6 +2588,12 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "try-lock"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.16.0" version = "1.16.0"
@ -2070,6 +2636,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]] [[package]]
name = "url" name = "url"
version = "2.3.1" version = "2.3.1"
@ -2081,12 +2653,40 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "want"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
dependencies = [
"log",
"try-lock",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.10.0+wasi-snapshot-preview1" version = "0.10.0+wasi-snapshot-preview1"
@ -2124,6 +2724,18 @@ dependencies = [
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.84" version = "0.2.84"
@ -2153,6 +2765,26 @@ version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "web-sys"
version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.2.8" version = "0.2.8"
@ -2277,6 +2909,15 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi 0.3.9",
]
[[package]] [[package]]
name = "zstd" name = "zstd"
version = "0.12.3+zstd.1.5.2" version = "0.12.3+zstd.1.5.2"

View File

@ -18,11 +18,14 @@ dotenvy = "^0.15.6"
dyn-clone = "1.0.10" dyn-clone = "1.0.10"
fern = { version = "0.6.1", features = ["chrono", "colored"] } fern = { version = "0.6.1", features = ["chrono", "colored"] }
futures = "0.3.26" futures = "0.3.26"
grammers-client = { version = "0.4.0", features = ["markdown"] } grammers-client = { version = "0.4.0", features = ["markdown", "html"] }
grammers-session = "0.4.0" grammers-session = "0.4.0"
lazy_static = "1.4.0"
log = "0.4.17" log = "0.4.17"
rand = "0.8.5" rand = "0.8.5"
rayon = "1.6.1" rayon = "1.6.1"
regex = "1.7.1"
reqwest = { version = "0.11.14", features = ["gzip", "json", "tokio-rustls"] }
serde = { version = "1.0.152", features = ["derive"] } serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.93" serde_json = "1.0.93"
tokio = { version = "1.25.0", features = [ tokio = { version = "1.25.0", features = [

View File

@ -4,6 +4,7 @@ WORKDIR /app
COPY Cargo.toml Cargo.lock askama.toml ./ COPY Cargo.toml Cargo.lock askama.toml ./
COPY src ./src COPY src ./src
COPY static ./static COPY static ./static
# Build binary in release mode.
RUN cargo build --release --all-features RUN cargo build --release --all-features
FROM debian:bullseye-20230109-slim as base FROM debian:bullseye-20230109-slim as base
@ -16,12 +17,16 @@ RUN apt-get update \
COPY static ./static COPY static ./static
# Copy built binary to a new image.
COPY --from=builder /app/target/release/s3bot /usr/local/bin/ COPY --from=builder /app/target/release/s3bot /usr/local/bin/
ENTRYPOINT ["/usr/local/bin/s3bot"] ENTRYPOINT ["/usr/local/bin/s3bot"]
FROM base as rootless FROM base as rootless
# Create a user and make the image rootless. So no one
# can escalate privileges even if they have access to
# container.
RUN useradd --create-home -u 1000 --user-group s3bot RUN useradd --create-home -u 1000 --user-group s3bot
WORKDIR /home/s3bot WORKDIR /home/s3bot
RUN mv /static ./static RUN mv /static ./static

38
README.md Normal file
View File

@ -0,0 +1,38 @@
<div align="center">
<img src="./logo.png" width="300">
<h1 align="center">
Automated telegram account
</h1>
</div>
This project is an attempt to add some utillities to your account.
This app uses telegram API and connects to it as a user, not as a bot. To use it, you need to register a new application, and obtain `api hash token` and `application id` from official telegram website. You can do it [here](https://core.telegram.org/api/obtaining_api_id).
## How to
First of all, you need to install [Rust](http://rust-lang.org/). Personally I recommend to use [rustup](https://rustup.rs/).
Make sure everything is fine by running `cargo --version`.
1. Compile the app.
```bash
cargo build --release
```
After that command you'll find a compiled binary in `target/release/s3bot`.
2. Run the compiled binary.
## Configuration
You can configure this app by either command line arguments or with environment variables.
If you place .env file in current working directory, contents will be loaded as environment variables.
For additional help please use:
```bash
s3bot --help
```

23
helm/.helmignore Normal file
View File

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

24
helm/Chart.yaml Normal file
View File

@ -0,0 +1,24 @@
apiVersion: v2
name: s3bot
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "latest"

22
helm/templates/NOTES.txt Normal file
View File

@ -0,0 +1,22 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "s3bot.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "s3bot.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "s3bot.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "s3bot.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

View File

@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "s3bot.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "s3bot.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "s3bot.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "s3bot.labels" -}}
helm.sh/chart: {{ include "s3bot.chart" . }}
{{ include "s3bot.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "s3bot.selectorLabels" -}}
app.kubernetes.io/name: {{ include "s3bot.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "s3bot.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "s3bot.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,68 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "s3bot.fullname" . }}
labels:
{{- include "s3bot.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: 1
{{- end }}
selector:
matchLabels:
{{- include "s3bot.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "s3bot.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "s3bot.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ default 8000 .Values.env.BOT_SERVER_PORT }}
protocol: TCP
livenessProbe:
httpGet:
path: /health
port: http
readinessProbe:
httpGet:
path: /health
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.env }}
env:
{{- range $key, $val := . }}
- name: {{ $key | quote }}
value: {{ $val | quote }}
{{- end }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@ -0,0 +1,61 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "s3bot.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "s3bot.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "s3bot.fullname" . }}
labels:
{{- include "s3bot.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "s3bot.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "s3bot.serviceAccountName" . }}
labels:
{{- include "s3bot.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "s3bot.fullname" . }}-test-connection"
labels:
{{- include "s3bot.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "s3bot.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

89
helm/values.yaml Normal file
View File

@ -0,0 +1,89 @@
# Default values for s3bot.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
image:
repository: docker.le-memese.com/bots/s3bot
pullPolicy: Always
# Overrides the image tag whose default is the chart appVersion.
tag: ""
env:
BOT_SERVER_HOST: "0.0.0.0"
BOT_SERVER_PORT: 8000
BOT_SERVER_USERNAME: "s3rius_san"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext:
{}
# fsGroup: 2000
securityContext:
{}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
ingress:
enabled: false
className: ""
annotations:
{}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources:
{}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

View File

@ -77,8 +77,21 @@ pub struct BotConfig {
)] )]
pub session_file: String, pub session_file: String,
#[arg(name = "bot-excluded-chats", long, env = "BOT_EXCLUDED_CHATS")] #[arg(
name = "bot-excluded-chats",
long,
env = "BOT_EXCLUDED_CHATS",
value_delimiter = ','
)]
pub excluded_chats: Vec<i64>, pub excluded_chats: Vec<i64>,
#[arg(
name = "bot-currency-excluded-chats",
long,
env = "BOT_CURRENCY_EXCLUDED_CHATS",
value_delimiter = ','
)]
pub currency_excluded_chats: Vec<i64>,
} }
#[derive(Clone, Parser, Debug)] #[derive(Clone, Parser, Debug)]

View File

@ -4,6 +4,11 @@ use crate::bot::handlers::Handler;
use super::base::Filter; use super::base::Filter;
/// This is a structure to match
/// handlers with corresponding filters.
///
/// It's handy, because for different messages
/// we have different set of rules.
#[derive(Clone)] #[derive(Clone)]
pub struct FilteredHandler { pub struct FilteredHandler {
filters: Vec<Box<dyn Filter>>, filters: Vec<Box<dyn Filter>>,
@ -23,6 +28,8 @@ impl FilteredHandler {
self self
} }
/// This method performs checks for all filters we have.
/// We run it not in parralel for fast fail strategy.
pub fn check(&self, update: &Update) -> bool { pub fn check(&self, update: &Update) -> bool {
for filter in &self.filters { for filter in &self.filters {
match filter.filter(update) { match filter.filter(update) {

View File

@ -1 +0,0 @@

View File

@ -1,5 +1,7 @@
use grammers_client::Update; use grammers_client::Update;
use crate::utils::messages::get_message;
use super::base::Filter; use super::base::Filter;
#[allow(dead_code)] #[allow(dead_code)]
@ -15,9 +17,17 @@ pub enum TextMatchMethod {
IMatches, IMatches,
} }
/// This filter is used to filter out
/// that marked as silent.
#[derive(Clone)]
pub struct SilentFilter;
/// This filter checks that current
/// chat is not one of excluded chats.
#[derive(Clone)] #[derive(Clone)]
pub struct ExcludedChatsFilter(pub Vec<i64>); pub struct ExcludedChatsFilter(pub Vec<i64>);
/// This filter checks for message directions.
#[derive(Clone)] #[derive(Clone)]
pub struct MessageDirectionFilter(pub MessageDirection); pub struct MessageDirectionFilter(pub MessageDirection);
@ -31,10 +41,8 @@ impl Filter for ExcludedChatsFilter {
Update::CallbackQuery(query) => query.chat().clone(), Update::CallbackQuery(query) => query.chat().clone(),
_ => return Ok(false), _ => return Ok(false),
}; };
if self.0.contains(&a.id()) { // Check that list of excluded chats doesn't contain our chat.
return Ok(false); Ok(!self.0.contains(&a.id()))
}
Ok(true)
} }
} }
@ -44,6 +52,7 @@ impl Filter for MessageDirectionFilter {
let res = matches!( let res = matches!(
(self.0, message.outgoing()), (self.0, message.outgoing()),
// Here we check that message's direction matches the direction we want.
(MessageDirection::Outgoing, true) | (MessageDirection::Incoming, false) (MessageDirection::Outgoing, true) | (MessageDirection::Incoming, false)
); );
Ok(res) Ok(res)
@ -72,3 +81,11 @@ impl<'a> Filter for TextFilter<'a> {
Ok(false) Ok(false)
} }
} }
impl Filter for SilentFilter {
fn filter(&self, update: &Update) -> anyhow::Result<bool> {
let Some(message) = get_message(update) else {return Ok(false)};
// Check that message is not silent.
Ok(!message.silent())
}
}

View File

@ -1,3 +1,3 @@
mod base; pub mod base;
pub mod chain; pub mod filtered_handler;
pub mod message_fitlers; pub mod message_fitlers;

View File

@ -0,0 +1,176 @@
use std::{collections::HashMap, time::Duration};
use grammers_client::{Client, InputMessage, Update};
use regex::Regex;
use crate::{
bot::{filters::base::Filter, handlers::Handler},
utils::messages::get_message,
};
lazy_static::lazy_static! {
static ref SUPPORTED_CURS: Vec<&'static str> = vec![
"GBP",
"HUF",
"USD",
"EUR",
"CNY",
"NOK",
"UAH",
"SEK",
"CHF",
"KRW",
"JPY",
"KZT",
"PLN",
"TRY",
"AMD",
"RSD",
];
static ref CONVERTION_ALIASES: HashMap<&'static str, &'static str> = HashMap::from(
[
// GBP
("фунт", "GBP"),
// USD
("бакс", "USD"),
("доллар", "USD"),
// EUR
("евро", "EUR"),
// JPY
("иен", "JPY"),
("йен", "JPY"),
// KRW
("вон", "KRW"),
// CHF
("франк", "CHF"),
// SEK
("крон", "CHF"),
// CNY
("юан", "CNY"),
// UAH
("гривна", "UAH"),
("гривны", "UAH"),
("гривен", "UAH"),
("грен", "UAH"),
// KZT
("тенге", "KZT"),
("тэнге", "KZT"),
// PLN
("злот", "PLN"),
// TRY
("лир", "TRY"),
// AMD
("драм", "AMD"),
// RSD
("динар", "RSD"),
]
);
static ref CUR_REGEX: Regex = {
#[allow(clippy::clone_double_ref)]
let a = CONVERTION_ALIASES.keys()
.copied()
.chain(SUPPORTED_CURS.iter().copied())
.collect::<Vec<_>>()
.join("|");
Regex::new(format!(r"\s*(?P<cur_value>\d+([\.,]\d+)?)\s+(?P<cur_name>{a})").as_str()).unwrap()
};
}
#[derive(Clone)]
pub struct CurrencyTextFilter;
#[derive(Clone)]
pub struct CurrencyConverter {
client: reqwest::Client,
}
impl CurrencyConverter {
pub fn new() -> anyhow::Result<Self> {
let client = reqwest::ClientBuilder::new()
.timeout(Duration::from_secs(2))
.gzip(true)
.build()?;
Ok(Self { client })
}
}
/// This filter check if the message matches regex for currencies.
impl Filter for CurrencyTextFilter {
fn filter(&self, update: &Update) -> anyhow::Result<bool> {
let Some(message) = get_message(update) else {
return Ok(false);
};
Ok(CUR_REGEX.is_match(message.text()))
}
}
#[async_trait::async_trait]
impl Handler for CurrencyConverter {
async fn react(&self, _: &Client, update: &Update) -> anyhow::Result<()> {
let Some(message) = get_message(update) else{ return Ok(())};
let response = self
.client
.get("https://www.cbr-xml-daily.ru/daily_json.js")
.send()
.await?
.error_for_status()?
.json::<serde_json::Value>()
.await?;
let Some(valutes) = response
.get("Valute")
.and_then(serde_json::Value::as_object) else{
log::warn!("Can't get valutes fom response.");
return Ok(());
};
let mut calucates = Vec::new();
for capture in CUR_REGEX.captures_iter(message.text()) {
// We parse supplied value from message
let Some(num_value) = capture
.name("cur_value")
// Convert match to string.
.map(|mtch| mtch.as_str())
// Parse it.
.and_then(|val| val.parse::<f64>().ok()) else{
continue;
};
let cur_name = capture.name("cur_name").map(|mtch| mtch.as_str());
let Some(cur_name) = cur_name
// We check if the value is an alias.
.and_then(|val| CONVERTION_ALIASES.get(val).copied())
// get previous value if not.
.or(cur_name) else{
continue;
};
let calculated = valutes
.get(cur_name)
.and_then(|info| info.get("Value"))
.map(ToString::to_string)
.and_then(|value| value.as_str().parse::<f64>().ok())
.map(|multiplier| multiplier * num_value);
if let Some(value) = calculated {
calucates.push(format!(
"<pre>{num_value} {cur_name} = {value:.2} RUB</pre><br>"
));
}
}
if !calucates.is_empty() {
let mut bot_response =
String::from("<b>Полагаясь на текущий курс валют могу сказать следующее:</b>\n\n");
for calc in calucates {
bot_response.push_str(calc.as_str());
}
message
// We send it as silent, so we can filter this message later.
.reply(InputMessage::html(bot_response).silent(true))
.await?;
}
Ok(())
}
}

View File

@ -10,7 +10,7 @@ impl Handler for Help {
async fn react(&self, _: &Client, update: &Update) -> anyhow::Result<()> { async fn react(&self, _: &Client, update: &Update) -> anyhow::Result<()> {
let Update::NewMessage(message) = update else {return Ok(())}; let Update::NewMessage(message) = update else {return Ok(())};
message.reply("Хелпа").await?; message.reply("Я больше не рассказываю что я умею.").await?;
Ok(()) Ok(())
} }

View File

@ -1,2 +1,3 @@
pub mod currency_converter;
pub mod get_chat_id; pub mod get_chat_id;
pub mod help; pub mod help;

View File

@ -6,6 +6,7 @@ use grammers_client::{Client, Update};
const BLYA_WORDS: &[&str] = &[", бля,", ", сука,", ", ёбаный рот,", ", охуеть конечно,"]; const BLYA_WORDS: &[&str] = &[", бля,", ", сука,", ", ёбаный рот,", ", охуеть конечно,"];
/// It's time to add some бляs.
#[derive(Clone)] #[derive(Clone)]
pub struct Blyaficator; pub struct Blyaficator;

View File

@ -4,6 +4,17 @@ use rand::seq::IteratorRandom;
use crate::bot::handlers::base::Handler; use crate::bot::handlers::base::Handler;
lazy_static::lazy_static! {
static ref GREETINGS: &'static [&'static str] = &[
"Привет!",
"Добрый день!",
"Здравствуйте.",
"Приетствую.",
"Доброго времени суток.",
];
}
/// Greeter just replies to greeting messages.
#[derive(Clone)] #[derive(Clone)]
pub struct Greeter; pub struct Greeter;
@ -18,9 +29,8 @@ impl Handler for Greeter {
return Ok(()); return Ok(());
} }
let reply_text = ["Привет!", "Добрый день!", "Здравствуйте.", "Приетствую"] // Choose random greeting from the list of greetings.
.into_iter() let reply_text = GREETINGS.iter().choose(&mut rand::thread_rng()).copied();
.choose(&mut rand::thread_rng());
if let Some(text) = reply_text { if let Some(text) = reply_text {
message.reply(text).await?; message.reply(text).await?;

View File

@ -8,19 +8,30 @@ use tokio::sync::RwLock;
use super::{ use super::{
filters::{ filters::{
chain::FilteredHandler, filtered_handler::FilteredHandler,
message_fitlers::{ message_fitlers::{
ExcludedChatsFilter, MessageDirection, MessageDirectionFilter, TextFilter, ExcludedChatsFilter, MessageDirection, MessageDirectionFilter, SilentFilter,
TextMatchMethod, TextFilter, TextMatchMethod,
}, },
}, },
handlers::{ handlers::{
basic::{get_chat_id::GetChatId, help::Help}, basic::{
currency_converter::{CurrencyConverter, CurrencyTextFilter},
get_chat_id::GetChatId,
help::Help,
},
fun::{blyaficator::Blyaficator, greeter::Greeter}, fun::{blyaficator::Blyaficator, greeter::Greeter},
Handler, Handler,
}, },
}; };
/// Authorization function.
///
/// This function asks for login code and
/// waits for it to become available.
///
/// Also it validates two-factor authentication
/// password if it was supplied.
async fn authorize( async fn authorize(
args: &BotConfig, args: &BotConfig,
client: &Client, client: &Client,
@ -32,18 +43,19 @@ async fn authorize(
.await?; .await?;
let mut code = None; let mut code = None;
// Check for code to becom available every second.
while code.is_none() { while code.is_none() {
tokio::time::sleep(Duration::from_secs(1)).await; tokio::time::sleep(Duration::from_secs(1)).await;
{ {
code = web_code.read().await.clone(); code = web_code.read().await.clone();
} }
} }
// Acutal signing in.
let signed_in = client.sign_in(&token, &code.unwrap()).await; let signed_in = client.sign_in(&token, &code.unwrap()).await;
match signed_in { match signed_in {
// If signing i
Err(SignInError::PasswordRequired(password_token)) => { Err(SignInError::PasswordRequired(password_token)) => {
// Note: this `prompt` method will echo the password in the console. // If the password was not supplied, we use the hint in panic.
// Real code might want to use a better way to handle this.
let hint = password_token.hint().unwrap_or("None"); let hint = password_token.hint().unwrap_or("None");
let password = args let password = args
.tfa_password .tfa_password
@ -60,48 +72,82 @@ async fn authorize(
Ok(()) Ok(())
} }
/// This little function is used to execute handlers on updates and print errors
/// if something bad happens.
///
/// The reason, I created a separate function is simple. I spawn every handler as a
/// separate task and I don't care if fails.
async fn handle_with_log(handler: Box<dyn Handler>, client: Client, update_data: Update) { async fn handle_with_log(handler: Box<dyn Handler>, client: Client, update_data: Update) {
if let Err(err) = handler.react(&client, &update_data).await { if let Err(err) = handler.react(&client, &update_data).await {
log::error!("{err}"); log::error!("{err}");
} }
} }
async fn run(args: BotConfig, client: Client) { /// Acutal logic on handling updates.
///
/// This function handles every update we get from telegram
/// and spawns correcsponding handlers.
///
/// Also, every available handler is defined here.
async fn run(args: BotConfig, client: Client) -> anyhow::Result<()> {
let handlers: Vec<FilteredHandler> = vec![ let handlers: Vec<FilteredHandler> = vec![
// Printing help.
FilteredHandler::new(Help).add_filter(TextFilter(&[".h"], TextMatchMethod::IMatches)),
// Greeting my fellow humans.
FilteredHandler::new(Greeter) FilteredHandler::new(Greeter)
.add_filter(SilentFilter)
.add_filter(MessageDirectionFilter(MessageDirection::Incoming)) .add_filter(MessageDirectionFilter(MessageDirection::Incoming))
.add_filter(TextFilter(&["привет"], TextMatchMethod::IStartsWith)) .add_filter(TextFilter(&["привет"], TextMatchMethod::IStartsWith))
.add_filter(ExcludedChatsFilter(args.excluded_chats)), .add_filter(ExcludedChatsFilter(args.excluded_chats)),
FilteredHandler::new(Help).add_filter(TextFilter(&[".h"], TextMatchMethod::IMatches)), // Getting chat id.
FilteredHandler::new(GetChatId) FilteredHandler::new(GetChatId)
.add_filter(TextFilter(&[".cid"], TextMatchMethod::IMatches)), .add_filter(TextFilter(&[".cid"], TextMatchMethod::IMatches)),
// Make бля fun again.
FilteredHandler::new(Blyaficator) FilteredHandler::new(Blyaficator)
.add_filter(TextFilter(&[".bl"], TextMatchMethod::IStartsWith)), .add_filter(TextFilter(&[".bl"], TextMatchMethod::IStartsWith)),
// Handler for converting currecies.
FilteredHandler::new(CurrencyConverter::new()?)
.add_filter(SilentFilter)
.add_filter(ExcludedChatsFilter(args.currency_excluded_chats))
.add_filter(CurrencyTextFilter),
]; ];
loop { loop {
// Get new update
let update = client.next_update().await; let update = client.next_update().await;
if update.is_err() { if update.is_err() {
log::error!("{}", update.unwrap_err()); log::error!("{}", update.unwrap_err());
break; break;
} }
if let Some(update_data) = update.unwrap() { // We get update if there's no error
let update_ref = &update_data; let Some(update_data) = update.ok().and_then(|inner|inner) else{
let matched_handlers = handlers log::warn!("Empty update is found.");
.par_iter() continue;
.filter(move |val| val.check(update_ref)) };
.collect::<Vec<_>>(); // A reference to update, so we can easily move it.
for handler in matched_handlers { let update_ref = &update_data;
tokio::spawn(handle_with_log( let filtered = handlers
handler.handler.clone(), // A parralel iterator over matchers.
client.clone(), .par_iter()
update_data.clone(), // Here we get all handlers that match filters.
)); .filter(move |val| val.check(update_ref))
} // For each matched handler we spawn a new task.
.collect::<Vec<_>>();
for handler in filtered {
tokio::spawn(handle_with_log(
handler.handler.clone(),
client.clone(),
update_data.clone(),
));
} }
} }
Ok(())
} }
/// The main entrypoint for bot.
///
/// This function starts bot, performs login and
/// starts endless loop.
pub async fn start(args: BotConfig, web_code: Arc<RwLock<Option<String>>>) -> anyhow::Result<()> { pub async fn start(args: BotConfig, web_code: Arc<RwLock<Option<String>>>) -> anyhow::Result<()> {
log::info!("Connecting to Telegram..."); log::info!("Connecting to Telegram...");
let client = Client::connect(Config { let client = Client::connect(Config {
@ -115,17 +161,20 @@ pub async fn start(args: BotConfig, web_code: Arc<RwLock<Option<String>>>) -> an
}, },
}) })
.await?; .await?;
log::info!("Connected!"); log::info!("Connected!");
if client.is_authorized().await? { if client.is_authorized().await? {
// If we already authrized, we write random token, so web won't update it. // If we already authrized, we write random token, so web won't update it.
let mut code_writer = web_code.write().await; let mut code_writer = web_code.write().await;
*code_writer = Some(String::new()); *code_writer = Some(String::new());
} else { } else {
// If we don't have token, wait for it.
authorize(&args, &client, web_code).await?; authorize(&args, &client, web_code).await?;
client.session().save_to_file(args.session_file.as_str())?; client.session().save_to_file(args.session_file.as_str())?;
} }
run(args.clone(), client).await; run(args.clone(), client).await?;
Ok(()) Ok(())
} }

View File

@ -25,27 +25,27 @@ async fn main() -> anyhow::Result<()> {
let token_lock = Arc::new(RwLock::new(None)); let token_lock = Arc::new(RwLock::new(None));
let bot_token = token_lock.clone(); [
let server_token = token_lock.clone(); // Spawining bot task
tokio::task::spawn(bot::start(args.bot.clone(), token_lock.clone())),
// Spawning server task.
tokio::task::spawn(error_wrap(server::create(
args.server.clone(),
token_lock.clone(),
)?)),
]
.into_iter()
// Turning all tasks in unirdered futures set.
.collect::<FuturesUnordered<_>>()
// Grab first completed future
.take(1)
// Take the value
.next()
// Await for it to complete
.await
// Unwrap (since we can guarantee that it's not empty).
// Throw all errors by using ??. First for joining task, second from the task itself.
.unwrap()??;
let web_server = server::create(args.server.clone(), server_token)?; Ok(())
let bot_future = bot::start(args.bot.clone(), bot_token);
let tasks = [
tokio::task::spawn(bot_future),
tokio::task::spawn(error_wrap(web_server)),
];
let completed = tasks
.into_iter()
.collect::<FuturesUnordered<_>>()
.take(1)
.collect::<Vec<_>>()
.await;
if let Some(fut) = completed.into_iter().next() {
fut?
} else {
Ok(())
}
} }

View File

@ -11,9 +11,10 @@ pub fn create(args: ServerConfig, token: Arc<RwLock<Option<String>>>) -> anyhow:
let addr = (args.host.clone(), args.port); let addr = (args.host.clone(), args.port);
let server = HttpServer::new(move || { let server = HttpServer::new(move || {
App::new() App::new()
.wrap(actix_web::middleware::Logger::new( .wrap(
"\"%r\" \"-\" \"%s\" \"%a\" \"%D\"", actix_web::middleware::Logger::new("\"%r\" \"-\" \"%s\" \"%a\" \"%D\"")
)) .exclude("/health"),
)
.app_data(Data::new(token.clone())) .app_data(Data::new(token.clone()))
.app_data(Data::new(args.clone())) .app_data(Data::new(args.clone()))
.service(login) .service(login)

View File

@ -1,5 +1,16 @@
use askama::Template; use askama::Template;
/// Index pages.
///
/// This page is used to authenticate users.
/// It has two states: activated or not.
///
/// It the activated is false, we
/// render two input fields, with telegram code
/// and server's password.
///
/// If the user is authenticated, we just render
/// some random information.
#[derive(Template)] #[derive(Template)]
#[template(path = "index.html")] #[template(path = "index.html")]
pub struct Index { pub struct Index {