initial commit: Go version of SMS Receiver with fixed template rendering

- Implemented all core features from Python version
- Fixed int64/int type compatibility in template functions
- Added login authentication, SMS receiving, statistics, logs
- Independent database: sms_receiver_go.db
- Fixed frontend display issues for message list and statistics
This commit is contained in:
OpenClaw Agent
2026-02-08 17:15:22 +08:00
commit 4a31cd1115
23 changed files with 3493 additions and 0 deletions

142
config/config.go Normal file
View File

@@ -0,0 +1,142 @@
package config
import (
"fmt"
"os"
"time"
"github.com/spf13/viper"
)
type Config struct {
App AppConfig `mapstructure:"app"`
Server ServerConfig `mapstructure:"server"`
Security SecurityConfig `mapstructure:"security"`
SMS SMSConfig `mapstructure:"sms"`
Database DatabaseConfig `mapstructure:"database"`
Timezone string `mapstructure:"timezone"`
APITokens []APIToken `mapstructure:"api_tokens"`
}
type AppConfig struct {
Name string `mapstructure:"name"`
Version string `mapstructure:"version"`
}
type ServerConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Debug bool `mapstructure:"debug"`
}
type SecurityConfig struct {
Enabled bool `mapstructure:"enabled"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
SessionLifetime int `mapstructure:"session_lifetime"`
SecretKey string `mapstructure:"secret_key"`
SignVerify bool `mapstructure:"sign_verify"`
SignMaxAge int64 `mapstructure:"sign_max_age"`
}
type SMSConfig struct {
MaxMessages int `mapstructure:"max_messages"`
AutoCleanup bool `mapstructure:"auto_cleanup"`
CleanupDays int `mapstructure:"cleanup_days"`
}
type DatabaseConfig struct {
Path string `mapstructure:"path"`
}
type APIToken struct {
Name string `mapstructure:"name"`
Token string `mapstructure:"token"`
Secret string `mapstructure:"secret"`
Enabled bool `mapstructure:"enabled"`
}
var cfg *Config
func Load(configPath string) (*Config, error) {
viper.SetConfigFile(configPath)
viper.SetConfigType("yaml")
// 允许环境变量覆盖
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
cfg = &Config{}
if err := viper.Unmarshal(cfg); err != nil {
return nil, fmt.Errorf("解析配置文件失败: %w", err)
}
return cfg, nil
}
func Get() *Config {
return cfg
}
// GetSessionLifetimeDuration 返回会话 lifetime 为 duration
func (c *Config) GetSessionLifetimeDuration() time.Duration {
return time.Duration(c.Security.SessionLifetime) * time.Second
}
// GetSignMaxAgeDuration 返回签名最大有效期
func (c *Config) GetSignMaxAgeDuration() time.Duration {
return time.Duration(c.Security.SignMaxAge) * time.Millisecond
}
// GetServerAddress 返回服务器地址
func (c *Config) GetServerAddress() string {
return fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port)
}
// GetTokenByName 根据名称获取 Token 配置
func (c *Config) GetTokenByName(name string) *APIToken {
for i := range c.APITokens {
if c.APITokens[i].Name == name && c.APITokens[i].Enabled {
return &c.APITokens[i]
}
}
return nil
}
// GetTokenByValue 根据 token 值获取配置
func (c *Config) GetTokenByValue(token string) *APIToken {
for i := range c.APITokens {
if c.APITokens[i].Token == token && c.APITokens[i].Enabled {
return &c.APITokens[i]
}
}
return nil
}
// Save 保存配置到文件
func (c *Config) Save(path string) error {
viper.Set("app", c.App)
viper.Set("server", c.Server)
viper.Set("security", c.Security)
viper.Set("sms", c.SMS)
viper.Set("database", c.Database)
viper.Set("timezone", c.Timezone)
viper.Set("api_tokens", c.APITokens)
return viper.WriteConfigAs(path)
}
// LoadDefault 加载默认配置文件
func LoadDefault() (*Config, error) {
configPath := "config.yaml"
if _, err := os.Stat(configPath); os.IsNotExist(err) {
// 尝试查找上层目录
if _, err := os.Stat("../config.yaml"); err == nil {
configPath = "../config.yaml"
}
}
return Load(configPath)
}