Files
telegram-gateway/config.go
Gabriel Radureau 8001460f14
All checks were successful
Docker Build / build-and-push-image (push) Successful in 53s
Phase 2a — add 'http' handler (sync forwarder)
The http handler POSTs the Telegram Update JSON to a configurable
internal URL and expects a JSON {text} reply, which it sends back via
sendMessage. Sync : the webhook ack waits for the upstream answer
(timeout default 5s, capped at 30s — Telegram itself closes around 60s).

For slow / unreliable backends use the Phase 3 async handlers once the
queue is in place.

YAML config :

  bots:
    webappbot:
      handler: http
      http:
        url: http://webapp.webapp.svc.cluster.local:8080/telegram/update
        timeout: 5s

Refs ~/.claude/plans/pour-les-notifications-on-inherited-seal.md § Phase 2.
2026-05-09 14:27:58 +02:00

62 lines
1.8 KiB
Go

package main
import (
"fmt"
"os"
"strings"
"time"
"gopkg.in/yaml.v3"
)
type Config struct {
Bots map[string]BotConfig `yaml:"bots"`
}
type BotConfig struct {
Handler string `yaml:"handler"`
// RequireAuth is *bool so "absent" is distinct from "false". When unset
// (nil) the registry treats it as true — secure by default. Explicit
// `requireAuth: false` is required to expose a bot publicly.
// Forced to false for handler=auth (chicken-and-egg).
RequireAuth *bool `yaml:"requireAuth,omitempty"`
// HTTP is the per-bot config for the `http` handler. Required when
// handler=http. See handler_http.go.
HTTP *HTTPConfig `yaml:"http,omitempty"`
Token string `yaml:"-"`
Secret string `yaml:"-"`
}
// HTTPConfig drives the `http` handler : the gateway POSTs the Telegram
// Update JSON to URL, awaits a JSON `{text}` response within Timeout,
// then sends Text back to the user via sendMessage.
type HTTPConfig struct {
URL string `yaml:"url"`
Timeout time.Duration `yaml:"timeout,omitempty"`
}
// LoadConfig reads the YAML routing config and merges per-bot secrets pulled
// from the process environment. Per-bot env keys are derived from the bot
// slug uppercased: BOT_<UPPER_SLUG>_TOKEN, BOT_<UPPER_SLUG>_SECRET.
func LoadConfig(path string) (*Config, error) {
raw, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read config %s: %w", path, err)
}
var cfg Config
if err := yaml.Unmarshal(raw, &cfg); err != nil {
return nil, fmt.Errorf("parse yaml: %w", err)
}
if len(cfg.Bots) == 0 {
return nil, fmt.Errorf("no bots in %s", path)
}
for slug, b := range cfg.Bots {
envSlug := strings.ToUpper(strings.ReplaceAll(slug, "-", "_"))
b.Token = os.Getenv("BOT_" + envSlug + "_TOKEN")
b.Secret = os.Getenv("BOT_" + envSlug + "_SECRET")
cfg.Bots[slug] = b
}
return &cfg, nil
}