Files
iotlcm/main.go
T
2026-10-29 14:17:14 +08:00

129 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"database/sql"
"errors"
"log"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"time"
_ "github.com/go-sql-driver/mysql"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"git.5iot.com/iotlcm-public/iotlcm-sms/api/pb"
"git.5iot.com/iotlcm-public/iotlcm-sms/internal/grpcapi"
"git.5iot.com/iotlcm-public/iotlcm-sms/internal/httpapi"
"git.5iot.com/iotlcm-public/iotlcm-sms/internal/sms"
"git.5iot.com/iotlcm-public/iotlcm-sms/internal/sms/aliyun"
"git.5iot.com/iotlcm-public/iotlcm-sms/internal/sms/tencent"
)
// 构建时通过 -ldflags 注入。
var (
BuildVersion = "0.0"
BuildTime = ""
CommitID = ""
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
log.Printf("iotlcm-sms starting, version=%s buildTime=%s commit=%s", BuildVersion, BuildTime, CommitID)
// 默认全局配置:config.yaml 提供默认值,SMS_* 环境变量可覆盖。
defaultConfig, source, err := sms.LoadDefaultConfig()
if err != nil {
log.Fatalf("load sms default config: %v", err)
}
log.Printf("sms default config loaded: %s", source.Describe())
// 场景模板配置来自数据库(表 t_sms_template_config):改库即生效,无需改代码或重启。
// 连接参数与凭证同源于 config.yaml(SMS_DB_DSN 等环境变量可覆盖);DSN 为空时能力关闭。
var scenes sms.SceneProvider
var sceneStore *sms.SceneStore
sceneDb, sceneDbSrc, err := sms.LoadSceneDbConfig()
if err != nil {
log.Printf("load scene db config: %v(场景模板能力关闭)", err)
} else if sceneDb.DSN == "" {
log.Printf("scene db DSN not set, scene-based template config disabled")
} else {
db, err := sql.Open("mysql", sceneDb.DSN)
if err != nil {
log.Fatalf("open sms config database: %v", err)
}
db.SetMaxOpenConns(4)
db.SetMaxIdleConns(2)
db.SetConnMaxLifetime(time.Hour)
ttl := sceneDb.TTL()
sceneStore = sms.NewSceneStore(db, ttl)
defer func() { _ = sceneStore.Close() }()
scenes = sceneStore
log.Printf("sms scene config store enabled (source: %s), cache ttl=%s", sceneDbSrc.Describe(), ttl)
}
providers := sms.NewRegistryWithDefault(defaultConfig, scenes)
providers.Register(sms.ServiceAliyun, aliyun.New())
providers.Register(sms.ServiceTencent, tencent.New())
httpAddr := envOrDefault("HTTP_ADDR", ":8080")
httpServer := &http.Server{
Addr: httpAddr,
Handler: httpapi.NewHandler(providers),
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 10 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 60 * time.Second,
}
grpcAddr := envOrDefault("GRPC_ADDR", ":11200")
grpcListener, err := net.Listen("tcp", grpcAddr)
if err != nil {
log.Fatalf("listen on gRPC address %s: %v", grpcAddr, err)
}
grpcServer := grpc.NewServer()
pb.RegisterNoticeServer(grpcServer, grpcapi.NewServer(providers))
reflection.Register(grpcServer)
errCh := make(chan error, 2)
go func() {
log.Printf("sms http server listening on %s", httpAddr)
if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
errCh <- err
}
}()
go func() {
log.Printf("sms gRPC server listening on %s", grpcAddr)
if err := grpcServer.Serve(grpcListener); err != nil {
errCh <- err
}
}()
select {
case err := <-errCh:
log.Printf("server stopped unexpectedly: %v", err)
stop()
case <-ctx.Done():
}
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := httpServer.Shutdown(shutdownCtx); err != nil {
log.Printf("shutdown HTTP server: %v", err)
}
grpcServer.GracefulStop()
}
func envOrDefault(name, fallback string) string {
if value := os.Getenv(name); value != "" {
return value
}
return fallback
}