Files
chat-deploy/internal/api/chat/start.go
kim.dev.6789 e018f742ad
All checks were successful
itom-platform auto build image / build (push) Successful in 3m17s
feat: 支持环境变量控制 Prometheus metrics
2026-01-16 23:21:11 +08:00

218 lines
8.4 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 chat
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
chatmw "git.imall.cloud/openim/chat/internal/api/mw"
"git.imall.cloud/openim/chat/internal/api/util"
"git.imall.cloud/openim/chat/pkg/common/config"
"git.imall.cloud/openim/chat/pkg/common/imapi"
"git.imall.cloud/openim/chat/pkg/common/kdisc"
disetcd "git.imall.cloud/openim/chat/pkg/common/kdisc/etcd"
adminclient "git.imall.cloud/openim/chat/pkg/protocol/admin"
chatclient "git.imall.cloud/openim/chat/pkg/protocol/chat"
"github.com/gin-gonic/gin"
"github.com/openimsdk/tools/discovery/etcd"
"github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/mw"
"github.com/openimsdk/tools/system/program"
"github.com/openimsdk/tools/utils/datautil"
"github.com/openimsdk/tools/utils/runtimeenv"
"github.com/prometheus/client_golang/prometheus/promhttp"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
type Config struct {
ApiConfig config.API
Discovery config.Discovery
Share config.Share
Redis config.Redis
RuntimeEnv string
}
func Start(ctx context.Context, index int, cfg *Config) error {
cfg.RuntimeEnv = runtimeenv.PrintRuntimeEnvironment()
if len(cfg.Share.ChatAdmin) == 0 {
return errs.New("share chat admin not configured")
}
apiPort, err := datautil.GetElemByIndex(cfg.ApiConfig.Api.Ports, index)
if err != nil {
return err
}
client, err := kdisc.NewDiscoveryRegister(&cfg.Discovery, cfg.RuntimeEnv, nil)
if err != nil {
return err
}
chatConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Chat, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient())
if err != nil {
return err
}
adminConn, err := client.GetConn(ctx, cfg.Discovery.RpcService.Admin, grpc.WithTransportCredentials(insecure.NewCredentials()), mw.GrpcClient())
if err != nil {
return err
}
chatClient := chatclient.NewChatClient(chatConn)
adminClient := adminclient.NewAdminClient(adminConn)
im := imapi.New(cfg.Share.OpenIM.ApiURL, cfg.Share.OpenIM.Secret, cfg.Share.OpenIM.AdminUserID)
base := util.Api{
ImUserID: cfg.Share.OpenIM.AdminUserID,
ProxyHeader: cfg.Share.ProxyHeader,
ChatAdminUserID: cfg.Share.ChatAdmin[0],
}
adminApi := New(chatClient, adminClient, im, &base)
mwApi := chatmw.New(adminClient)
gin.SetMode(gin.ReleaseMode)
engine := gin.New()
engine.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID())
// 可选的 Prometheus metrics 端点
// 支持配置文件或环境变量控制(环境变量优先)
prometheusEnable := cfg.ApiConfig.Prometheus.Enable
if envEnable := os.Getenv("PROMETHEUS_ENABLE"); envEnable != "" {
prometheusEnable = strings.ToLower(envEnable) == "true" || envEnable == "1"
}
if prometheusEnable {
metricsPath := cfg.ApiConfig.Prometheus.Path
if envPath := os.Getenv("PROMETHEUS_PATH"); envPath != "" {
metricsPath = envPath
}
if metricsPath == "" {
metricsPath = "/metrics"
}
engine.GET(metricsPath, gin.WrapH(promhttp.Handler()))
}
SetChatRoute(engine, adminApi, mwApi)
var (
netDone = make(chan struct{}, 1)
netErr error
)
server := http.Server{Addr: fmt.Sprintf(":%d", apiPort), Handler: engine}
go func() {
err = server.ListenAndServe()
if err != nil && !errors.Is(err, http.ErrServerClosed) {
netErr = errs.WrapMsg(err, fmt.Sprintf("api start err: %s", server.Addr))
netDone <- struct{}{}
}
}()
if cfg.Discovery.Enable == kdisc.ETCDCONST {
cm := disetcd.NewConfigManager(client.(*etcd.SvcDiscoveryRegistryImpl).GetClient(),
[]string{
config.ChatAPIChatCfgFileName,
config.DiscoveryConfigFileName,
config.ShareFileName,
config.LogConfigFileName,
},
)
cm.Watch(ctx)
}
shutdown := func() error {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
err := server.Shutdown(ctx)
if err != nil {
return errs.WrapMsg(err, "shutdown err")
}
return nil
}
disetcd.RegisterShutDown(shutdown)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGTERM)
select {
case <-sigs:
program.SIGTERMExit()
if err := shutdown(); err != nil {
return err
}
case <-netDone:
close(netDone)
return netErr
}
return nil
}
func SetChatRoute(router gin.IRouter, chat *Api, mw *chatmw.MW) {
account := router.Group("/account")
account.GET("/captcha", chat.GetCaptchaImage) // Get captcha image
account.POST("/code/send", chat.SendVerifyCode) // Send verification code
account.POST("/code/verify", chat.VerifyCode) // Verify the verification code
account.POST("/register", mw.CheckAdminOrNil, chat.RegisterUser) // Register
account.POST("/login", chat.Login) // Login
account.POST("/password/reset", chat.ResetPassword) // Forgot password
account.POST("/password/change", mw.CheckToken, chat.ChangePassword) // Change password
user := router.Group("/user", mw.CheckToken)
user.POST("/update", chat.UpdateUserInfo) // Edit personal information
user.POST("/find/public", chat.FindUserPublicInfo) // Get user's public information
user.POST("/find/full", chat.FindUserFullInfo) // Get all information of the user
user.POST("/search/full", chat.SearchUserFullInfo) // Search user's public information
user.POST("/search/public", chat.SearchUserPublicInfo) // Search all information of the user
user.POST("/rtc/get_token", chat.GetTokenForVideoMeeting) // Get token for video meeting for the user
router.POST("/friend/search", mw.CheckToken, chat.SearchFriend)
router.POST("/friend/add", mw.CheckToken, chat.AddFriend)
router.Group("/applet").POST("/find", mw.CheckToken, chat.FindApplet) // Applet list
router.Group("/client_config").POST("/get", chat.GetClientConfig) // Get client initialization configuration
applicationGroup := router.Group("application")
applicationGroup.POST("/latest_version", chat.LatestApplicationVersion)
applicationGroup.POST("/page_versions", chat.PageApplicationVersion)
router.Group("/callback").POST("/open_im", chat.OpenIMCallback) // Callback
// 系统配置相关接口(客户端)
systemConfig := router.Group("/system_config")
systemConfig.POST("/get_app_configs", chat.GetAppSystemConfigs) // 获取APP端配置show_in_app=true 且 enabled=true
// 钱包相关接口(客户端)
wallet := router.Group("/wallet", mw.CheckToken)
wallet.POST("/balance", chat.GetWalletBalance) // 获取钱包余额
wallet.POST("/info", chat.GetWalletInfo) // 获取钱包详细信息
wallet.POST("/balance_records", chat.GetWalletBalanceRecords) // 获取余额明细
wallet.POST("/payment_password/set", chat.SetPaymentPassword) // 设置支付密码(首次设置或修改)
wallet.POST("/withdraw_account/set", chat.SetWithdrawAccount) // 设置提现账号
wallet.POST("/withdraw/apply", chat.CreateWithdrawApplication) // 申请提现
wallet.POST("/withdraw/list", chat.GetWithdrawApplications) // 获取提现申请列表
wallet.POST("/real_name_auth", chat.RealNameAuth) // 实名认证
// 敏感词相关接口(客户端)
sensitive := router.Group("/sensitive_word", mw.CheckToken)
sensitive.POST("/get", chat.GetSensitiveWords) // 获取敏感词列表
sensitive.POST("/check", chat.CheckSensitiveWords) // 检测敏感词
// 收藏相关接口
favorite := router.Group("/favorite", mw.CheckToken)
favorite.POST("/create", chat.CreateFavorite) // 创建收藏
favorite.POST("/get", chat.GetFavorite) // 获取收藏详情
favorite.POST("/list", chat.GetFavorites) // 获取收藏列表
favorite.POST("/search", chat.SearchFavorites) // 搜索收藏
favorite.POST("/update", chat.UpdateFavorite) // 更新收藏
favorite.POST("/delete", chat.DeleteFavorite) // 删除收藏
favorite.POST("/tags", chat.GetFavoritesByTags) // 根据标签获取收藏
favorite.POST("/count", chat.GetFavoriteCount) // 获取收藏数量
// 定时任务相关接口
scheduledTask := router.Group("/scheduled_task", mw.CheckToken)
scheduledTask.POST("/create", chat.CreateScheduledTask) // 创建定时任务
scheduledTask.POST("/get", chat.GetScheduledTask) // 获取定时任务详情
scheduledTask.POST("/list", chat.GetScheduledTasks) // 获取定时任务列表
scheduledTask.POST("/update", chat.UpdateScheduledTask) // 更新定时任务
scheduledTask.POST("/delete", chat.DeleteScheduledTask) // 删除定时任务
}