Files
funstat-mcp-go/internal/app/config.go
你的用户名 8d1ce4598d Initial commit: FunStat MCP Server Go implementation
- Telegram integration for customer statistics
- MCP server implementation with rate limiting
- Cache system for performance optimization
- Multi-language support
- RESTful API endpoints

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 15:28:06 +08:00

159 lines
4.0 KiB
Go

package app
import (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"
tgconfig "funstatmcp/internal/telegram"
)
type Config struct {
Telegram tgconfig.Config
Host string
Port int
RequireSession bool
}
func FromEnv() (Config, error) {
var cfg Config
telegramCfg, err := loadTelegramConfig()
if err != nil {
return cfg, err
}
cfg.Telegram = telegramCfg
cfg.Host = getEnvDefault("FUNSTAT_HOST", "127.0.0.1")
portStr := getEnvDefault("FUNSTAT_PORT", "8091")
port, err := strconv.Atoi(portStr)
if err != nil {
return cfg, fmt.Errorf("invalid FUNSTAT_PORT: %w", err)
}
cfg.Port = port
cfg.RequireSession = parseBool(getEnvDefault("FUNSTAT_REQUIRE_SESSION", "false"))
return cfg, nil
}
func loadTelegramConfig() (tgconfig.Config, error) {
var cfg tgconfig.Config
apiIDStr := os.Getenv("TELEGRAM_API_ID")
if apiIDStr == "" {
return cfg, fmt.Errorf("TELEGRAM_API_ID is required")
}
apiID, err := strconv.Atoi(apiIDStr)
if err != nil {
return cfg, fmt.Errorf("invalid TELEGRAM_API_ID: %w", err)
}
cfg.APIID = apiID
cfg.APIHash = strings.TrimSpace(os.Getenv("TELEGRAM_API_HASH"))
if cfg.APIHash == "" {
return cfg, fmt.Errorf("TELEGRAM_API_HASH is required")
}
cfg.BotUsername = getEnvDefault("FUNSTAT_BOT_USERNAME", "@openaiw_bot")
cfg.SessionString = strings.TrimSpace(os.Getenv("TELEGRAM_SESSION_STRING"))
sessionStringFile := strings.TrimSpace(os.Getenv("TELEGRAM_SESSION_STRING_FILE"))
if cfg.SessionString == "" && sessionStringFile != "" {
data, err := os.ReadFile(expandPath(sessionStringFile))
if err != nil {
return cfg, fmt.Errorf("read TELEGRAM_SESSION_STRING_FILE: %w", err)
}
cfg.SessionString = strings.TrimSpace(string(data))
}
sessionPath := strings.TrimSpace(os.Getenv("TELEGRAM_SESSION_PATH"))
if sessionPath != "" {
if !strings.HasSuffix(sessionPath, ".session") {
sessionPath = sessionPath + ".session"
}
cfg.SessionStorage = expandPath(sessionPath)
} else {
cfg.SessionStorage = defaultSessionPath()
}
if value := strings.TrimSpace(os.Getenv("FUNSTAT_RATE_LIMIT_PER_SECOND")); value != "" {
parsed, err := strconv.Atoi(value)
if err != nil {
return cfg, fmt.Errorf("invalid FUNSTAT_RATE_LIMIT_PER_SECOND: %w", err)
}
cfg.RateLimit = parsed
}
if value := strings.TrimSpace(os.Getenv("FUNSTAT_RATE_LIMIT_WINDOW")); value != "" {
duration, err := time.ParseDuration(value)
if err != nil {
return cfg, fmt.Errorf("invalid FUNSTAT_RATE_LIMIT_WINDOW: %w", err)
}
cfg.RateLimitWindow = duration
}
if value := strings.TrimSpace(os.Getenv("FUNSTAT_CACHE_TTL")); value != "" {
duration, err := time.ParseDuration(value)
if err != nil {
return cfg, fmt.Errorf("invalid FUNSTAT_CACHE_TTL: %w", err)
}
cfg.CacheTTL = duration
}
proxyHost := strings.TrimSpace(os.Getenv("FUNSTAT_PROXY_HOST"))
proxyPort := strings.TrimSpace(os.Getenv("FUNSTAT_PROXY_PORT"))
if proxyHost != "" && proxyPort != "" {
port, err := strconv.Atoi(proxyPort)
if err != nil {
return cfg, fmt.Errorf("invalid FUNSTAT_PROXY_PORT: %w", err)
}
cfg.Proxy = &tgconfig.ProxyConfig{
Type: getEnvDefault("FUNSTAT_PROXY_TYPE", "socks5"),
Host: proxyHost,
Port: port,
Username: strings.TrimSpace(os.Getenv("FUNSTAT_PROXY_USERNAME")),
Password: strings.TrimSpace(os.Getenv("FUNSTAT_PROXY_PASSWORD")),
}
}
return cfg, nil
}
func getEnvDefault(key, fallback string) string {
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
return value
}
return fallback
}
func parseBool(value string) bool {
switch strings.ToLower(strings.TrimSpace(value)) {
case "1", "true", "yes", "on":
return true
default:
return false
}
}
func defaultSessionPath() string {
home, err := os.UserHomeDir()
if err != nil {
return filepath.Join(os.TempDir(), "funstatmcp", "session.json")
}
return filepath.Join(home, ".funstatmcp", "session.json")
}
func expandPath(path string) string {
if strings.HasPrefix(path, "~") {
home, err := os.UserHomeDir()
if err == nil {
return filepath.Join(home, strings.TrimPrefix(path, "~"))
}
}
return path
}