refactor: api update

This commit is contained in:
Gordon 2024-04-08 16:26:20 +08:00
parent 8c10e4f532
commit 9b3aedc795
9 changed files with 110 additions and 99 deletions

View File

@ -22,10 +22,7 @@ import (
) )
func main() { func main() {
apiCmd := cmd.NewApiCmd(cmd.ApiServer) if err := cmd.NewApiCmd().Exec(); err != nil {
//apiCmd.AddPortFlag()
//apiCmd.AddPrometheusPortFlag()
if err := apiCmd.Execute(); err != nil {
program.ExitWithError(err) program.ExitWithError(err)
} }
} }

View File

@ -20,8 +20,7 @@ import (
) )
func main() { func main() {
cronTaskCmd := cmd.NewCronTaskCmd(cmd.CronTaskServer) if err := cmd.NewCronTaskCmd().Exec(); err != nil {
if err := cronTaskCmd.Exec(); err != nil {
program.ExitWithError(err) program.ExitWithError(err)
} }
} }

View File

@ -40,15 +40,13 @@ type MessageApi struct {
*rpcclient.Message *rpcclient.Message
validate *validator.Validate validate *validator.Validate
userRpcClient *rpcclient.UserRpcClient userRpcClient *rpcclient.UserRpcClient
manager *config.Manager
imAdmin *config.IMAdmin imAdmin *config.IMAdmin
} }
func NewMessageApi(msgRpcClient *rpcclient.Message, userRpcClient *rpcclient.User, manager *config.Manager, func NewMessageApi(msgRpcClient *rpcclient.Message, userRpcClient *rpcclient.User,
imAdmin *config.IMAdmin) MessageApi { imAdmin *config.IMAdmin) MessageApi {
return MessageApi{Message: msgRpcClient, validate: validator.New(), return MessageApi{Message: msgRpcClient, validate: validator.New(),
userRpcClient: rpcclient.NewUserRpcClientByUser(userRpcClient), userRpcClient: rpcclient.NewUserRpcClientByUser(userRpcClient), imAdmin: imAdmin}
manager: manager, imAdmin: imAdmin}
} }
func (MessageApi) SetOptions(options map[string]bool, value bool) { func (MessageApi) SetOptions(options map[string]bool, value bool) {
@ -206,7 +204,7 @@ func (m *MessageApi) SendMessage(c *gin.Context) {
} }
// Check if the user has the app manager role. // Check if the user has the app manager role.
if !authverify.IsAppManagerUid(c, m.manager, m.imAdmin) { if !authverify.IsAppManagerUid(c, m.imAdmin) {
// Respond with a permission error if the user is not an app manager. // Respond with a permission error if the user is not an app manager.
apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message")) apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message"))
return return
@ -261,7 +259,7 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
return return
} }
if !authverify.IsAppManagerUid(c, m.manager, m.imAdmin) { if !authverify.IsAppManagerUid(c, m.imAdmin) {
apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message")) apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message"))
return return
} }
@ -280,7 +278,7 @@ func (m *MessageApi) SendBusinessNotification(c *gin.Context) {
SessionType: constant.SingleChatType, SessionType: constant.SingleChatType,
CreateTime: timeutil.GetCurrentTimestampByMill(), CreateTime: timeutil.GetCurrentTimestampByMill(),
ClientMsgID: idutil.GetMsgIDByMD5(mcontext.GetOpUserID(c)), ClientMsgID: idutil.GetMsgIDByMD5(mcontext.GetOpUserID(c)),
Options: config.GetOptionsByNotification(config.NotificationConf{ Options: config.GetOptionsByNotification(config.NotificationConfig{
IsSendMsg: false, IsSendMsg: false,
ReliabilityLevel: 1, ReliabilityLevel: 1,
UnreadCount: false, UnreadCount: false,
@ -304,7 +302,7 @@ func (m *MessageApi) BatchSendMsg(c *gin.Context) {
apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap()) apiresp.GinError(c, errs.ErrArgs.WithDetail(err.Error()).Wrap())
return return
} }
if err := authverify.CheckAdmin(c, m.manager, m.imAdmin); err != nil { if err := authverify.CheckAdmin(c, m.imAdmin); err != nil {
apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message")) apiresp.GinError(c, errs.ErrNoPermission.WrapMsg("only app manager can send message"))
return return
} }

View File

@ -17,7 +17,10 @@ package api
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/tools/db/redisutil" "github.com/openimsdk/tools/db/redisutil"
"github.com/openimsdk/tools/utils/datautil"
"github.com/openimsdk/tools/utils/network"
"net" "net"
"net/http" "net/http"
"os" "os"
@ -51,11 +54,16 @@ import (
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
) )
func Start(ctx context.Context, config *config.GlobalConfig, port int, proPort int) error { func Start(ctx context.Context, index int, config *cmd.ApiConfig) error {
if port == 0 || proPort == 0 { apiPort, err := datautil.GetElemByIndex(config.RpcConfig.Api.Ports, index)
return errs.New("port or proPort is empty", "port", port, "proPort", proPort).Wrap() if err != nil {
return err
} }
rdb, err := redisutil.NewRedisClient(ctx, config.Redis.Build()) prometheusPort, err := datautil.GetElemByIndex(config.RpcConfig.Prometheus.Ports, index)
if err != nil {
return err
}
rdb, err := redisutil.NewRedisClient(ctx, config.RedisConfig.Build())
if err != nil { if err != nil {
return err return err
} }
@ -63,46 +71,36 @@ func Start(ctx context.Context, config *config.GlobalConfig, port int, proPort i
var client discovery.SvcDiscoveryRegistry var client discovery.SvcDiscoveryRegistry
// Determine whether zk is passed according to whether it is a clustered deployment // Determine whether zk is passed according to whether it is a clustered deployment
client, err = kdisc.NewDiscoveryRegister(config) client, err = kdisc.NewDiscoveryRegister(&config.ZookeeperConfig)
if err != nil { if err != nil {
return errs.WrapMsg(err, "failed to register discovery service") return errs.WrapMsg(err, "failed to register discovery service")
} }
if err = client.CreateRpcRootNodes(config.GetServiceNames()); err != nil { if err = client.CreateRpcRootNodes(config.Share.RpcRegisterName.GetServiceNames()); err != nil {
return errs.WrapMsg(err, "failed to create RPC root nodes") return errs.WrapMsg(err, "failed to create RPC root nodes")
} }
if err = client.RegisterConf2Registry(constant.OpenIMCommonConfigKey, config.EncodeConfig()); err != nil {
return errs.WrapMsg(err, "failed to register configuration to registry")
}
var ( var (
netDone = make(chan struct{}, 1) netDone = make(chan struct{}, 1)
netErr error netErr error
) )
router := newGinRouter(client, rdb, config) router := newGinRouter(client, rdb, config)
if config.Prometheus.Enable { if config.RpcConfig.Prometheus.Enable {
go func() { go func() {
p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api")) p := ginprom.NewPrometheus("app", prommetrics.GetGinCusMetrics("Api"))
p.SetListenAddress(fmt.Sprintf(":%d", proPort)) p.SetListenAddress(fmt.Sprintf(":%d", prometheusPort))
if err = p.Use(router); err != nil && err != http.ErrServerClosed { if err = p.Use(router); err != nil && err != http.ErrServerClosed {
netErr = errs.WrapMsg(err, fmt.Sprintf("prometheus start err: %d", proPort)) netErr = errs.WrapMsg(err, fmt.Sprintf("prometheus start err: %d", prometheusPort))
netDone <- struct{}{} netDone <- struct{}{}
} }
}() }()
} }
address := net.JoinHostPort(network.GetListenIP(config.RpcConfig.Api.ListenIP), strconv.Itoa(apiPort))
var address string
if config.Api.ListenIP != "" {
address = net.JoinHostPort(config.Api.ListenIP, strconv.Itoa(port))
} else {
address = net.JoinHostPort("0.0.0.0", strconv.Itoa(port))
}
server := http.Server{Addr: address, Handler: router} server := http.Server{Addr: address, Handler: router}
log.CInfo(ctx, "API server is initializing", "address", address, "apiPort", port, "prometheusPort", proPort) log.CInfo(ctx, "API server is initializing", "address", address, "apiPort", apiPort, "prometheusPort", prometheusPort)
go func() { go func() {
err = server.ListenAndServe() err = server.ListenAndServe()
if err != nil && err != http.ErrServerClosed { if err != nil && err != http.ErrServerClosed {
@ -131,8 +129,9 @@ func Start(ctx context.Context, config *config.GlobalConfig, port int, proPort i
return nil return nil
} }
func newGinRouter(disCov discovery.SvcDiscoveryRegistry, rdb redis.UniversalClient, config *config.GlobalConfig) *gin.Engine { func newGinRouter(disCov discovery.SvcDiscoveryRegistry, rdb redis.UniversalClient, config *cmd.ApiConfig) *gin.Engine {
disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin"))) disCov.AddOption(mw.GrpcClient(), grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, "round_robin")))
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
r := gin.New() r := gin.New()
if v, ok := binding.Validator.Engine().(*validator.Validate); ok { if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
@ -140,17 +139,17 @@ func newGinRouter(disCov discovery.SvcDiscoveryRegistry, rdb redis.UniversalClie
} }
r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID()) r.Use(gin.Recovery(), mw.CorsHandler(), mw.GinParseOperationID())
// init rpc client here // init rpc client here
userRpc := rpcclient.NewUser(disCov, config.RpcRegisterName.OpenImUserName, config.RpcRegisterName.OpenImMessageGatewayName, userRpc := rpcclient.NewUser(disCov, config.Share.RpcRegisterName.User, config.Share.RpcRegisterName.MessageGateway,
&config.Manager, &config.IMAdmin) &config.Share.IMAdmin)
groupRpc := rpcclient.NewGroup(disCov, config.RpcRegisterName.OpenImGroupName) groupRpc := rpcclient.NewGroup(disCov, config.Share.RpcRegisterName.Group)
friendRpc := rpcclient.NewFriend(disCov, config.RpcRegisterName.OpenImFriendName) friendRpc := rpcclient.NewFriend(disCov, config.Share.RpcRegisterName.Friend)
messageRpc := rpcclient.NewMessage(disCov, config.RpcRegisterName.OpenImMsgName) messageRpc := rpcclient.NewMessage(disCov, config.Share.RpcRegisterName.Msg)
conversationRpc := rpcclient.NewConversation(disCov, config.RpcRegisterName.OpenImConversationName) conversationRpc := rpcclient.NewConversation(disCov, config.Share.RpcRegisterName.Conversation)
authRpc := rpcclient.NewAuth(disCov, config.RpcRegisterName.OpenImAuthName) authRpc := rpcclient.NewAuth(disCov, config.Share.RpcRegisterName.Auth)
thirdRpc := rpcclient.NewThird(disCov, config.RpcRegisterName.OpenImThirdName, config.Prometheus.GrafanaUrl) thirdRpc := rpcclient.NewThird(disCov, config.Share.RpcRegisterName.Third, config.RpcConfig.Prometheus.GrafanaURL)
u := NewUserApi(*userRpc) u := NewUserApi(*userRpc)
m := NewMessageApi(messageRpc, userRpc, &config.Manager, &config.IMAdmin) m := NewMessageApi(messageRpc, userRpc, &config.Share.IMAdmin)
ParseToken := GinParseToken(rdb, config) ParseToken := GinParseToken(rdb, config)
userRouterGroup := r.Group("/user") userRouterGroup := r.Group("/user")
{ {

View File

@ -16,10 +16,8 @@ package cmd
import ( import (
"context" "context"
"github.com/openimsdk/open-im-server/v3/internal/api" "github.com/openimsdk/open-im-server/v3/internal/api"
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/protocol/constant"
"github.com/openimsdk/tools/system/program" "github.com/openimsdk/tools/system/program"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -27,35 +25,40 @@ import (
type ApiCmd struct { type ApiCmd struct {
*RootCmd *RootCmd
ctx context.Context ctx context.Context
configMap map[string]StructEnvPrefix
apiConfig ApiConfig
}
type ApiConfig struct {
RpcConfig config.API
RedisConfig config.Redis
MongodbConfig config.Mongo
ZookeeperConfig config.ZooKeeper
NotificationConfig config.Notification
Share config.Share
MinioConfig config.Minio
} }
func NewApiCmd(name string) *ApiCmd { func NewApiCmd() *ApiCmd {
ret := &ApiCmd{RootCmd: NewRootCmd(program.GetProcessName(), name)} var apiConfig ApiConfig
ret.ctx = context.WithValue(context.Background(), "version", config2.Version) ret := &ApiCmd{apiConfig: apiConfig}
ret.SetRootCmdPt(ret) ret.configMap = map[string]StructEnvPrefix{
ret.addPreRun() OpenIMAPICfgFileName: {EnvPrefix: apiEnvPrefix, ConfigStruct: &apiConfig.RpcConfig},
ret.addRunE() RedisConfigFileName: {EnvPrefix: redisEnvPrefix, ConfigStruct: &apiConfig.RedisConfig},
ZookeeperConfigFileName: {EnvPrefix: zoopkeeperEnvPrefix, ConfigStruct: &apiConfig.ZookeeperConfig},
ShareFileName: {EnvPrefix: shareEnvPrefix, ConfigStruct: &apiConfig.Share},
}
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
ret.ctx = context.WithValue(context.Background(), "version", config.Version)
ret.Command.PreRunE = func(cmd *cobra.Command, args []string) error {
return ret.preRunE()
}
return ret return ret
} }
func (a *ApiCmd) addPreRun() { func (a *ApiCmd) Exec() error {
a.Command.PreRun = func(cmd *cobra.Command, args []string) { return a.Execute()
a.port = a.getPortFlag(cmd)
a.prometheusPort = a.getPrometheusPortFlag(cmd)
}
} }
func (a *ApiCmd) addRunE() { func (a *ApiCmd) preRunE() error {
a.Command.RunE = func(cmd *cobra.Command, args []string) error { return api.Start(a.ctx, a.Index(), &a.apiConfig)
return api.Start(a.ctx, a.config, a.port, a.prometheusPort)
}
}
func (a *ApiCmd) GetPortFromConfig(portType string) int {
if portType == constant.FlagPort {
return a.config.Api.OpenImApiPort[0]
} else if portType == constant.FlagPrometheusPort {
return a.config.Prometheus.ApiPrometheusPort[0]
}
return 0
} }

View File

@ -63,6 +63,7 @@ const (
minioEnvPrefix = "openim-minio" minioEnvPrefix = "openim-minio"
kafkaEnvPrefix = "openim-kafka" kafkaEnvPrefix = "openim-kafka"
zoopkeeperEnvPrefix = "openim-zookeeper" zoopkeeperEnvPrefix = "openim-zookeeper"
apiEnvPrefix = "openim-api"
authEnvPrefix = "openim-auth" authEnvPrefix = "openim-auth"
conversationEnvPrefix = "openim-conversation" conversationEnvPrefix = "openim-conversation"
friendEnvPrefix = "openim-friend" friendEnvPrefix = "openim-friend"

View File

@ -326,7 +326,10 @@ type WebhookConfig struct {
type Share struct { type Share struct {
Env string `mapstructure:"env"` Env string `mapstructure:"env"`
RpcRegisterName struct { RpcRegisterName RpcRegisterName `mapstructure:"rpcRegisterName"`
IMAdmin IMAdmin `mapstructure:"imAdmin"`
}
type RpcRegisterName struct {
User string `mapstructure:"user"` User string `mapstructure:"user"`
Friend string `mapstructure:"friend"` Friend string `mapstructure:"friend"`
Msg string `mapstructure:"msg"` Msg string `mapstructure:"msg"`
@ -336,9 +339,22 @@ type Share struct {
Auth string `mapstructure:"auth"` Auth string `mapstructure:"auth"`
Conversation string `mapstructure:"conversation"` Conversation string `mapstructure:"conversation"`
Third string `mapstructure:"third"` Third string `mapstructure:"third"`
} `mapstructure:"rpcRegisterName"`
IMAdmin IMAdmin `mapstructure:"imAdmin"`
} }
func (r *RpcRegisterName) GetServiceNames() []string {
return []string{
r.User,
r.Friend,
r.Msg,
r.Push,
r.MessageGateway,
r.Group,
r.Auth,
r.Conversation,
r.Third,
}
}
type IMAdmin struct { type IMAdmin struct {
UserID []string `mapstructure:"userID"` UserID []string `mapstructure:"userID"`
Nickname []string `mapstructure:"nickname"` Nickname []string `mapstructure:"nickname"`

View File

@ -16,14 +16,19 @@ package discoveryregister
import ( import (
"github.com/openimsdk/open-im-server/v3/pkg/common/config" "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/direct"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes" "github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/kubernetes"
"github.com/openimsdk/open-im-server/v3/pkg/common/discoveryregister/zookeeper"
"github.com/openimsdk/tools/discovery" "github.com/openimsdk/tools/discovery"
"github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/errs"
"time" "time"
) )
const (
zookeeper = "zoopkeeper"
kubenetes = "k8s"
direct = "direct"
)
// NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type. // NewDiscoveryRegister creates a new service discovery and registry client based on the provided environment type.
func NewDiscoveryRegister(zookeeperConfig *config.ZooKeeper) (discovery.SvcDiscoveryRegistry, error) { func NewDiscoveryRegister(zookeeperConfig *config.ZooKeeper) (discovery.SvcDiscoveryRegistry, error) {

View File

@ -18,6 +18,7 @@ import (
"context" "context"
"fmt" "fmt"
config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config" config2 "github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/tools/utils/datautil"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"net" "net"
"net/http" "net/http"
@ -47,11 +48,11 @@ func Start[T any](ctx context.Context, zookeeperConfig *config2.ZooKeeper, prome
registerIP string, rpcPorts []int, index int, rpcRegisterName string, config T, rpcFn func(ctx context.Context, registerIP string, rpcPorts []int, index int, rpcRegisterName string, config T, rpcFn func(ctx context.Context,
config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error { config T, client discovery.SvcDiscoveryRegistry, server *grpc.Server) error, options ...grpc.ServerOption) error {
rpcPort, err := getElemByIndex(rpcPorts, index) rpcPort, err := datautil.GetElemByIndex(rpcPorts, index)
if err != nil { if err != nil {
return err return err
} }
prometheusPort, err := getElemByIndex(prometheusConfig.Ports, index) prometheusPort, err := datautil.GetElemByIndex(prometheusConfig.Ports, index)
if err != nil { if err != nil {
return err return err
} }
@ -173,11 +174,3 @@ func gracefulStopWithCtx(ctx context.Context, f func()) error {
return nil return nil
} }
} }
func getElemByIndex(array []int, index int) (int, error) {
if index < 0 || index >= len(array) {
return 0, errs.New("index out of range", "index", index, "array", array).Wrap()
}
return array[index], nil
}