package chat import ( "context" "errors" "fmt" "net/http" "os" "os/signal" "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" "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()) 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) // 删除定时任务 }