复制项目

This commit is contained in:
kim.dev.6789
2026-01-14 22:35:45 +08:00
parent 305d526110
commit b7f8db7d08
297 changed files with 81784 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
package cmd
import (
"context"
"git.imall.cloud/openim/chat/internal/api/admin"
"git.imall.cloud/openim/chat/pkg/common/config"
"github.com/openimsdk/tools/system/program"
"github.com/spf13/cobra"
)
type AdminApiCmd struct {
*RootCmd
ctx context.Context
configMap map[string]any
apiConfig admin.Config
}
func NewAdminApiCmd() *AdminApiCmd {
ret := AdminApiCmd{apiConfig: admin.Config{
AllConfig: &config.AllConfig{},
}}
ret.configMap = map[string]any{
config.DiscoveryConfigFileName: &ret.apiConfig.Discovery,
config.LogConfigFileName: &ret.apiConfig.Log,
config.MongodbConfigFileName: &ret.apiConfig.Mongo,
config.ChatAPIAdminCfgFileName: &ret.apiConfig.AdminAPI,
config.ChatAPIChatCfgFileName: &ret.apiConfig.ChatAPI,
config.ChatRPCAdminCfgFileName: &ret.apiConfig.Admin,
config.ChatRPCChatCfgFileName: &ret.apiConfig.Chat,
config.RedisConfigFileName: &ret.apiConfig.Redis,
config.ShareFileName: &ret.apiConfig.Share,
}
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
ret.apiConfig.ConfigPath = ret.configPath
return ret.runE()
}
return &ret
}
func (a *AdminApiCmd) Exec() error {
return a.Execute()
}
func (a *AdminApiCmd) runE() error {
return admin.Start(a.ctx, a.Index(), &a.apiConfig)
}

View File

@@ -0,0 +1,68 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"context"
"git.imall.cloud/openim/chat/internal/rpc/admin"
"git.imall.cloud/openim/chat/pkg/common/config"
"git.imall.cloud/openim/chat/pkg/common/startrpc"
"github.com/openimsdk/tools/system/program"
"github.com/spf13/cobra"
)
type AdminRpcCmd struct {
*RootCmd
ctx context.Context
configMap map[string]any
adminConfig admin.Config
}
func NewAdminRpcCmd() *AdminRpcCmd {
var ret AdminRpcCmd
ret.configMap = map[string]any{
config.ChatRPCAdminCfgFileName: &ret.adminConfig.RpcConfig,
config.RedisConfigFileName: &ret.adminConfig.RedisConfig,
config.DiscoveryConfigFileName: &ret.adminConfig.Discovery,
config.MongodbConfigFileName: &ret.adminConfig.MongodbConfig,
config.ShareFileName: &ret.adminConfig.Share,
}
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
return ret.runE()
}
return &ret
}
func (a *AdminRpcCmd) Exec() error {
return a.Execute()
}
func (a *AdminRpcCmd) runE() error {
return startrpc.Start(a.ctx, &a.adminConfig.Discovery, a.adminConfig.RpcConfig.RPC.ListenIP,
a.adminConfig.RpcConfig.RPC.RegisterIP, a.adminConfig.RpcConfig.RPC.Ports,
a.Index(), a.adminConfig.Discovery.RpcService.Admin, &a.adminConfig.Share, &a.adminConfig,
[]string{
config.ChatRPCAdminCfgFileName,
config.RedisConfigFileName,
config.DiscoveryConfigFileName,
config.MongodbConfigFileName,
config.ShareFileName,
config.LogConfigFileName,
}, nil,
admin.Start)
}

41
pkg/common/cmd/bot_api.go Normal file
View File

@@ -0,0 +1,41 @@
package cmd
import (
"context"
"git.imall.cloud/openim/chat/internal/api/bot"
"git.imall.cloud/openim/chat/pkg/common/config"
"github.com/openimsdk/tools/system/program"
"github.com/spf13/cobra"
)
type BotApiCmd struct {
*RootCmd
ctx context.Context
configMap map[string]any
apiConfig bot.Config
}
func NewBotApiCmd() *BotApiCmd {
ret := BotApiCmd{apiConfig: bot.Config{}}
ret.configMap = map[string]any{
config.DiscoveryConfigFileName: &ret.apiConfig.Discovery,
config.ChatAPIBotCfgFileName: &ret.apiConfig.ApiConfig,
config.ShareFileName: &ret.apiConfig.Share,
config.RedisConfigFileName: &ret.apiConfig.Redis,
}
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
return ret.runE()
}
return &ret
}
func (a *BotApiCmd) Exec() error {
return a.Execute()
}
func (a *BotApiCmd) runE() error {
return bot.Start(a.ctx, a.Index(), &a.apiConfig)
}

54
pkg/common/cmd/bot_rpc.go Normal file
View File

@@ -0,0 +1,54 @@
package cmd
import (
"context"
"git.imall.cloud/openim/chat/internal/rpc/bot"
"git.imall.cloud/openim/chat/pkg/common/config"
"git.imall.cloud/openim/chat/pkg/common/startrpc"
"github.com/openimsdk/tools/system/program"
"github.com/spf13/cobra"
)
type BotRpcCmd struct {
*RootCmd
ctx context.Context
configMap map[string]any
botConfig bot.Config
}
func NewBotRpcCmd() *BotRpcCmd {
var ret BotRpcCmd
ret.configMap = map[string]any{
config.ChatRPCBotCfgFileName: &ret.botConfig.RpcConfig,
config.RedisConfigFileName: &ret.botConfig.RedisConfig,
config.DiscoveryConfigFileName: &ret.botConfig.Discovery,
config.MongodbConfigFileName: &ret.botConfig.MongodbConfig,
config.ShareFileName: &ret.botConfig.Share,
}
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
return ret.runE()
}
return &ret
}
func (a *BotRpcCmd) Exec() error {
return a.Execute()
}
func (a *BotRpcCmd) runE() error {
return startrpc.Start(a.ctx, &a.botConfig.Discovery, a.botConfig.RpcConfig.RPC.ListenIP,
a.botConfig.RpcConfig.RPC.RegisterIP, a.botConfig.RpcConfig.RPC.Ports,
a.Index(), a.botConfig.Discovery.RpcService.Bot, &a.botConfig.Share, &a.botConfig,
[]string{
config.ChatRPCBotCfgFileName,
config.RedisConfigFileName,
config.DiscoveryConfigFileName,
config.MongodbConfigFileName,
config.ShareFileName,
config.LogConfigFileName,
}, nil,
bot.Start)
}

View File

@@ -0,0 +1,41 @@
package cmd
import (
"context"
"git.imall.cloud/openim/chat/internal/api/chat"
"git.imall.cloud/openim/chat/pkg/common/config"
"github.com/openimsdk/tools/system/program"
"github.com/spf13/cobra"
)
type ChatApiCmd struct {
*RootCmd
ctx context.Context
configMap map[string]any
apiConfig chat.Config
}
func NewChatApiCmd() *ChatApiCmd {
var ret ChatApiCmd
ret.configMap = map[string]any{
config.ShareFileName: &ret.apiConfig.Share,
config.ChatAPIChatCfgFileName: &ret.apiConfig.ApiConfig,
config.DiscoveryConfigFileName: &ret.apiConfig.Discovery,
config.RedisConfigFileName: &ret.apiConfig.Redis,
}
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
return ret.runE()
}
return &ret
}
func (a *ChatApiCmd) Exec() error {
return a.Execute()
}
func (a *ChatApiCmd) runE() error {
return chat.Start(a.ctx, a.Index(), &a.apiConfig)
}

View File

@@ -0,0 +1,68 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"context"
"git.imall.cloud/openim/chat/internal/rpc/chat"
"git.imall.cloud/openim/chat/pkg/common/config"
"git.imall.cloud/openim/chat/pkg/common/startrpc"
"github.com/openimsdk/tools/system/program"
"github.com/spf13/cobra"
)
type ChatRpcCmd struct {
*RootCmd
ctx context.Context
configMap map[string]any
chatConfig chat.Config
}
func NewChatRpcCmd() *ChatRpcCmd {
var ret ChatRpcCmd
ret.configMap = map[string]any{
config.ChatRPCChatCfgFileName: &ret.chatConfig.RpcConfig,
config.RedisConfigFileName: &ret.chatConfig.RedisConfig,
config.DiscoveryConfigFileName: &ret.chatConfig.Discovery,
config.MongodbConfigFileName: &ret.chatConfig.MongodbConfig,
config.ShareFileName: &ret.chatConfig.Share,
}
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
return ret.runE()
}
return &ret
}
func (a *ChatRpcCmd) Exec() error {
return a.Execute()
}
func (a *ChatRpcCmd) runE() error {
return startrpc.Start(a.ctx, &a.chatConfig.Discovery, a.chatConfig.RpcConfig.RPC.ListenIP,
a.chatConfig.RpcConfig.RPC.RegisterIP, a.chatConfig.RpcConfig.RPC.Ports,
a.Index(), a.chatConfig.Discovery.RpcService.Chat, &a.chatConfig.Share, &a.chatConfig,
[]string{
config.ChatRPCChatCfgFileName,
config.RedisConfigFileName,
config.DiscoveryConfigFileName,
config.MongodbConfigFileName,
config.ShareFileName,
config.LogConfigFileName,
}, nil,
chat.Start)
}

266
pkg/common/cmd/root.go Normal file
View File

@@ -0,0 +1,266 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"context"
"encoding/json"
"fmt"
"git.imall.cloud/openim/chat/pkg/common/config"
"git.imall.cloud/openim/chat/pkg/common/kdisc"
disetcd "git.imall.cloud/openim/chat/pkg/common/kdisc/etcd"
"git.imall.cloud/openim/chat/version"
"github.com/openimsdk/tools/discovery/etcd"
clientv3 "go.etcd.io/etcd/client/v3"
"github.com/openimsdk/tools/errs"
"github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/utils/runtimeenv"
"github.com/spf13/cobra"
)
type RootCmd struct {
Command cobra.Command
processName string
port int
prometheusPort int
log config.Log
index int
configPath string
etcdClient *clientv3.Client
}
func (r *RootCmd) Index() int {
return r.index
}
func (r *RootCmd) Port() int {
return r.port
}
type CmdOpts struct {
loggerPrefixName string
configMap map[string]any
}
func WithLogName(logName string) func(*CmdOpts) {
return func(opts *CmdOpts) {
opts.loggerPrefixName = logName
}
}
func WithConfigMap(configMap map[string]any) func(*CmdOpts) {
return func(opts *CmdOpts) {
opts.configMap = configMap
}
}
func NewRootCmd(processName string, opts ...func(*CmdOpts)) *RootCmd {
rootCmd := &RootCmd{processName: processName}
cmd := cobra.Command{
Use: "Start openIM chat application",
Long: fmt.Sprintf(`Start %s `, processName),
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return rootCmd.persistentPreRun(cmd, opts...)
},
SilenceUsage: true,
SilenceErrors: false,
}
cmd.Flags().StringP(config.FlagConf, "c", "", "path of config directory")
cmd.Flags().IntP(config.FlagTransferIndex, "i", 0, "process startup sequence number")
rootCmd.Command = cmd
return rootCmd
}
func (r *RootCmd) initEtcd() error {
configDirectory, _, err := r.getFlag(&r.Command)
if err != nil {
return err
}
disConfig := config.Discovery{}
env := runtimeenv.PrintRuntimeEnvironment()
err = config.Load(configDirectory, config.DiscoveryConfigFileName, config.EnvPrefixMap[config.DiscoveryConfigFileName],
env, &disConfig)
if err != nil {
return err
}
if disConfig.Enable == kdisc.ETCDCONST {
discov, _ := kdisc.NewDiscoveryRegister(&disConfig, env, nil)
// 安全类型断言:仅当为 etcd 实现时才获取客户端,避免在 K8s 模式下崩溃
if etcdDiscov, ok := discov.(*etcd.SvcDiscoveryRegistryImpl); ok {
r.etcdClient = etcdDiscov.GetClient()
}
}
return nil
}
func (r *RootCmd) persistentPreRun(cmd *cobra.Command, opts ...func(*CmdOpts)) error {
if err := r.initEtcd(); err != nil {
return err
}
cmdOpts := r.applyOptions(opts...)
if err := r.initializeConfiguration(cmd, cmdOpts); err != nil {
return err
}
if err := r.updateConfigFromEtcd(cmdOpts); err != nil {
return err
}
if err := r.initializeLogger(cmdOpts); err != nil {
return errs.WrapMsg(err, "failed to initialize logger")
}
if r.etcdClient != nil {
if err := r.etcdClient.Close(); err != nil {
return errs.WrapMsg(err, "failed to close etcd client")
}
}
return nil
}
func (r *RootCmd) initializeConfiguration(cmd *cobra.Command, opts *CmdOpts) error {
configDirectory, _, err := r.getFlag(cmd)
if err != nil {
return err
}
r.configPath = configDirectory
runtimeEnv := runtimeenv.PrintRuntimeEnvironment()
// Load common configuration file
//opts.configMap[ShareFileName] = StructEnvPrefix{EnvPrefix: shareEnvPrefix, ConfigStruct: &r.share}
for configFileName, configStruct := range opts.configMap {
err := config.Load(configDirectory, configFileName,
config.EnvPrefixMap[configFileName], runtimeEnv, configStruct)
if err != nil {
return err
}
}
// Load common log configuration file
return config.Load(configDirectory, config.LogConfigFileName,
config.EnvPrefixMap[config.LogConfigFileName], runtimeEnv, &r.log)
}
func (r *RootCmd) updateConfigFromEtcd(opts *CmdOpts) error {
if r.etcdClient == nil {
return nil
}
ctx := context.TODO()
res, err := r.etcdClient.Get(ctx, disetcd.BuildKey(disetcd.EnableConfigCenterKey))
if err != nil {
log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Get EnableConfigCenterKey err: %v", errs.Wrap(err))
return nil
}
if res.Count == 0 {
return nil
} else {
if string(res.Kvs[0].Value) == disetcd.Disable {
return nil
} else if string(res.Kvs[0].Value) != disetcd.Enable {
return errs.New("unknown EnableConfigCenter value").Wrap()
}
}
update := func(configFileName string, configStruct any) error {
key := disetcd.BuildKey(configFileName)
etcdRes, err := r.etcdClient.Get(ctx, key)
if err != nil {
log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Get err: %v", errs.Wrap(err))
return nil
}
if etcdRes.Count == 0 {
data, err := json.Marshal(configStruct)
if err != nil {
return errs.ErrArgs.WithDetail(err.Error()).Wrap()
}
_, err = r.etcdClient.Put(ctx, disetcd.BuildKey(configFileName), string(data))
if err != nil {
log.ZWarn(ctx, "root cmd updateConfigFromEtcd, etcd Put err: %v", errs.Wrap(err))
}
return nil
}
err = json.Unmarshal(etcdRes.Kvs[0].Value, configStruct)
if err != nil {
return errs.WrapMsg(err, "failed to unmarshal config from etcd")
}
return nil
}
for configFileName, configStruct := range opts.configMap {
if err := update(configFileName, configStruct); err != nil {
return err
}
}
if err := update(config.LogConfigFileName, &r.log); err != nil {
return err
}
// Load common log configuration file
return nil
}
func (r *RootCmd) applyOptions(opts ...func(*CmdOpts)) *CmdOpts {
cmdOpts := defaultCmdOpts()
for _, opt := range opts {
opt(cmdOpts)
}
return cmdOpts
}
func (r *RootCmd) initializeLogger(cmdOpts *CmdOpts) error {
err := log.InitLoggerFromConfig(
cmdOpts.loggerPrefixName,
r.processName,
"", "",
r.log.RemainLogLevel,
r.log.IsStdout,
r.log.IsJson,
r.log.StorageLocation,
r.log.RemainRotationCount,
r.log.RotationTime,
version.Version,
r.log.IsSimplify,
)
if err != nil {
return errs.Wrap(err)
}
return errs.Wrap(log.InitConsoleLogger(r.processName, r.log.RemainLogLevel, r.log.IsJson, config.Version))
}
func defaultCmdOpts() *CmdOpts {
return &CmdOpts{
loggerPrefixName: "openim-chat-log",
}
}
func (r *RootCmd) getFlag(cmd *cobra.Command) (string, int, error) {
configDirectory, err := cmd.Flags().GetString(config.FlagConf)
if err != nil {
return "", 0, errs.Wrap(err)
}
index, err := cmd.Flags().GetInt(config.FlagTransferIndex)
if err != nil {
return "", 0, errs.Wrap(err)
}
r.index = index
return configDirectory, index, nil
}
func (r *RootCmd) Execute() error {
return r.Command.Execute()
}