Add configuration options for link generation in .env.example, docker-compose.yml, and main.go; update README.md with new environment variable descriptions.
Publish telemt-bot Docker image / build-and-push (push) Successful in 52s

This commit is contained in:
Denozordec
2026-03-09 17:57:34 +07:00
parent 5b5d99f7b1
commit d8ddc53640
4 changed files with 96 additions and 8 deletions
+3
View File
@@ -4,3 +4,6 @@ TELEMT_API_BASE_URL=http://host.docker.internal:9091
TELEMT_API_AUTH_HEADER=Bearer replace_me
TELEGRAM_HTTP_TIMEOUT_SECONDS=60
TELEMT_HTTP_TIMEOUT_SECONDS=5
TELEMT_LINK_HOST=127.0.0.1
TELEMT_LINK_PORT=9443
TELEMT_TLS_DOMAIN=
+12
View File
@@ -19,6 +19,9 @@
- `TELEMT_API_AUTH_HEADER` - значение заголовка `Authorization` для Telemt API (если включён `auth_header`).
- `TELEGRAM_HTTP_TIMEOUT_SECONDS` - timeout запросов к Telegram (по умолчанию `60`).
- `TELEMT_HTTP_TIMEOUT_SECONDS` - timeout запросов к Telemt API (по умолчанию `5`).
- `TELEMT_LINK_HOST` - хост для генерации `tg://proxy` ссылок, если API их не вернуло.
- `TELEMT_LINK_PORT` - порт для ссылок (по умолчанию `9443`).
- `TELEMT_TLS_DOMAIN` - TLS-домен для генерации `EE-TLS` ссылки (опционально).
## Быстрый старт (локально, Linux/bash)
@@ -47,6 +50,9 @@ services:
TELEMT_API_AUTH_HEADER: ${TELEMT_API_AUTH_HEADER}
TELEGRAM_HTTP_TIMEOUT_SECONDS: ${TELEGRAM_HTTP_TIMEOUT_SECONDS:-60}
TELEMT_HTTP_TIMEOUT_SECONDS: ${TELEMT_HTTP_TIMEOUT_SECONDS:-5}
TELEMT_LINK_HOST: ${TELEMT_LINK_HOST}
TELEMT_LINK_PORT: ${TELEMT_LINK_PORT:-9443}
TELEMT_TLS_DOMAIN: ${TELEMT_TLS_DOMAIN:-}
```
Запуск (Linux/bash):
@@ -56,6 +62,9 @@ export TELEGRAM_BOT_TOKEN="xxx:telegram_bot_token"
export TELEGRAM_ADMIN_CHAT_ID="123456789"
export TELEMT_API_BASE_URL="http://host.docker.internal:9091"
export TELEMT_API_AUTH_HEADER="Bearer secret"
export TELEMT_LINK_HOST="172.20.0.3"
export TELEMT_LINK_PORT="9443"
export TELEMT_TLS_DOMAIN="tf.ivx.su"
docker compose up -d
docker compose logs -f
@@ -73,6 +82,9 @@ docker run -d \
-e TELEMT_API_AUTH_HEADER="Bearer secret" \
-e TELEGRAM_HTTP_TIMEOUT_SECONDS="60" \
-e TELEMT_HTTP_TIMEOUT_SECONDS="5" \
-e TELEMT_LINK_HOST="172.20.0.3" \
-e TELEMT_LINK_PORT="9443" \
-e TELEMT_TLS_DOMAIN="tf.ivx.su" \
git.shts.su/denozord/telemt-bot:latest
```
+3
View File
@@ -12,3 +12,6 @@ services:
TELEMT_API_AUTH_HEADER: ${TELEMT_API_AUTH_HEADER}
TELEGRAM_HTTP_TIMEOUT_SECONDS: ${TELEGRAM_HTTP_TIMEOUT_SECONDS:-60}
TELEMT_HTTP_TIMEOUT_SECONDS: ${TELEMT_HTTP_TIMEOUT_SECONDS:-5}
TELEMT_LINK_HOST: ${TELEMT_LINK_HOST}
TELEMT_LINK_PORT: ${TELEMT_LINK_PORT:-9443}
TELEMT_TLS_DOMAIN: ${TELEMT_TLS_DOMAIN:-}
+78 -8
View File
@@ -3,6 +3,7 @@ package main
import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
@@ -32,6 +33,10 @@ type config struct {
TelemtTimeout time.Duration
TelegramTimeout time.Duration
TelemtLinkHost string
TelemtLinkPort int
TelemtLinkTLSDomain string
}
type bot struct {
@@ -168,6 +173,9 @@ func loadConfig() (config, error) {
cfg.TelemtAPIAuth = strings.TrimSpace(os.Getenv("TELEMT_API_AUTH_HEADER"))
cfg.TelemtTimeout = parseSecondsEnv("TELEMT_HTTP_TIMEOUT_SECONDS", defaultTelemtTimeoutSeconds)
cfg.TelegramTimeout = parseSecondsEnv("TELEGRAM_HTTP_TIMEOUT_SECONDS", defaultTelegramTimeoutSeconds)
cfg.TelemtLinkHost = strings.TrimSpace(os.Getenv("TELEMT_LINK_HOST"))
cfg.TelemtLinkPort = parseIntEnv("TELEMT_LINK_PORT", 9443)
cfg.TelemtLinkTLSDomain = strings.TrimSpace(os.Getenv("TELEMT_TLS_DOMAIN"))
return cfg, nil
}
@@ -184,6 +192,18 @@ func parseSecondsEnv(key string, fallback int) time.Duration {
return time.Duration(v) * time.Second
}
func parseIntEnv(key string, fallback int) int {
raw := strings.TrimSpace(os.Getenv(key))
if raw == "" {
return fallback
}
v, err := strconv.Atoi(raw)
if err != nil || v <= 0 {
return fallback
}
return v
}
func (b *bot) run(ctx context.Context) error {
for {
select {
@@ -350,14 +370,7 @@ func (b *bot) handleCreateUser(ctx context.Context, chatID int64, text string) e
return b.sendMessage(ctx, chatID, "Ошибка создания пользователя: "+err.Error())
}
links := created.User.Links
if len(links.Classic) == 0 && len(links.Secure) == 0 && len(links.TLS) == 0 {
var fetched userInfo
path := "/v1/users/" + url.PathEscape(created.User.Username)
if err := b.callTelemt(ctx, path, &fetched); err == nil {
links = fetched.Links
}
}
links := b.resolveUserLinks(ctx, created.User.Username, created.Secret, created.User.Links)
msg := fmt.Sprintf("Пользователь создан: %s\nsecret: %s", created.User.Username, created.Secret)
if linksText := formatUserLinks(links); linksText != "" {
@@ -368,6 +381,63 @@ func (b *bot) handleCreateUser(ctx context.Context, chatID int64, text string) e
return b.sendMessage(ctx, chatID, msg)
}
func hasAnyLinks(links userLinks) bool {
return len(links.Classic) > 0 || len(links.Secure) > 0 || len(links.TLS) > 0
}
func (b *bot) resolveUserLinks(ctx context.Context, username, secret string, initial userLinks) userLinks {
if hasAnyLinks(initial) {
return initial
}
var fetched userInfo
path := "/v1/users/" + url.PathEscape(username)
if err := b.callTelemt(ctx, path, &fetched); err == nil && hasAnyLinks(fetched.Links) {
return fetched.Links
}
var users []userInfo
if err := b.callTelemt(ctx, "/v1/users", &users); err == nil {
for i := range users {
if users[i].Username == username && hasAnyLinks(users[i].Links) {
return users[i].Links
}
}
}
users = nil
if err := b.callTelemt(ctx, "/v1/stats/users", &users); err == nil {
for i := range users {
if users[i].Username == username && hasAnyLinks(users[i].Links) {
return users[i].Links
}
}
}
return b.generateLinksFromSecret(secret)
}
func (b *bot) generateLinksFromSecret(secret string) userLinks {
host := strings.TrimSpace(b.cfg.TelemtLinkHost)
if host == "" || secret == "" {
return userLinks{}
}
port := b.cfg.TelemtLinkPort
classic := fmt.Sprintf("tg://proxy?server=%s&port=%d&secret=%s", host, port, secret)
dd := fmt.Sprintf("tg://proxy?server=%s&port=%d&secret=dd%s", host, port, secret)
out := userLinks{
Classic: []string{classic},
Secure: []string{dd},
}
if b.cfg.TelemtLinkTLSDomain != "" {
hexDomain := hex.EncodeToString([]byte(b.cfg.TelemtLinkTLSDomain))
tls := fmt.Sprintf("tg://proxy?server=%s&port=%d&secret=ee%s%s", host, port, secret, hexDomain)
out.TLS = []string{tls}
}
return out
}
func formatUserLinks(links userLinks) string {
var sb strings.Builder
appendLinks := func(title string, items []string) {