添加图片验证

This commit is contained in:
hawklin2017 2026-03-30 16:24:08 +08:00
parent bce5747164
commit 34ecfd283d
15 changed files with 366 additions and 2 deletions

View File

@ -122,6 +122,17 @@ builds:
- amd64 - amd64
- arm64 - arm64
- binary: openim-rpc-captcha
id: openim-rpc-captcha
main: ./cmd/openim-rpc/openim-rpc-captcha/main.go
goos:
- darwin
- windows
- linux
goarch:
- amd64
- arm64
- binary: openim-rpc-conversation - binary: openim-rpc-conversation
id: openim-rpc-conversation id: openim-rpc-conversation
main: ./cmd/openim-rpc/openim-rpc-conversation/main.go main: ./cmd/openim-rpc/openim-rpc-conversation/main.go
@ -355,6 +366,7 @@ nfpms:
- openim-msgtransfer - openim-msgtransfer
- openim-push - openim-push
- openim-rpc-auth - openim-rpc-auth
- openim-rpc-captcha
- openim-rpc-conversation - openim-rpc-conversation
- openim-rpc-friend - openim-rpc-friend
- openim-rpc-group - openim-rpc-group

View File

@ -0,0 +1,12 @@
package main
import (
"github.com/openimsdk/open-im-server/v3/pkg/common/cmd"
"github.com/openimsdk/tools/system/program"
)
func main() {
if err := cmd.NewCaptchaRpcCmd().Exec(); err != nil {
program.ExitWithError(err)
}
}

View File

@ -0,0 +1,12 @@
rpc:
registerIP: ""
listenIP: 0.0.0.0
autoSetPorts: false
ports: [10520]
prometheus:
enable: false
ports: [12520]
verifyPadding: 8
expireSeconds: 120

View File

@ -9,6 +9,7 @@ rpcRegisterName:
auth: auth auth: auth
conversation: conversation conversation: conversation
third: third third: third
captcha: captcha
imAdminUserID: [ imAdmin ] imAdminUserID: [ imAdmin ]

6
go.mod
View File

@ -102,6 +102,7 @@ require (
github.com/go-openapi/swag v0.22.4 // indirect github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-zookeeper/zk v1.0.3 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
@ -171,6 +172,7 @@ require (
github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect github.com/tklauser/numcpus v0.11.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/wenlng/go-captcha/v2 v2.0.5 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/scram v1.1.2 // indirect
@ -191,7 +193,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.7.0 // indirect golang.org/x/arch v0.7.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/image v0.15.0 // indirect golang.org/x/image v0.16.0 // indirect
golang.org/x/net v0.34.0 // indirect golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect
golang.org/x/sys v0.42.0 // indirect golang.org/x/sys v0.42.0 // indirect
@ -226,3 +228,5 @@ require (
golang.org/x/crypto v0.32.0 // indirect golang.org/x/crypto v0.32.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
) )
replace github.com/openimsdk/protocol => ./protocol

6
go.sum
View File

@ -178,6 +178,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
@ -450,6 +452,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/wenlng/go-captcha/v2 v2.0.5 h1:+1FpVwJZmLCqEHxOt+HvpUArFGo107nRxOeRVHkZhTc=
github.com/wenlng/go-captcha/v2 v2.0.5/go.mod h1:5hac1em3uXoyC5ipZ0xFv9umNM/waQvYAQdr0cx/h34=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
@ -518,6 +522,8 @@ golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjs
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw=
golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=

49
internal/api/captcha.go Normal file
View File

@ -0,0 +1,49 @@
package api
import (
"github.com/gin-gonic/gin"
pbcaptcha "github.com/openimsdk/protocol/captcha"
"github.com/openimsdk/tools/a2r"
"github.com/openimsdk/tools/apiresp"
"github.com/openimsdk/tools/log"
)
type CaptchaApi struct {
Client pbcaptcha.CaptchaClient
}
func NewCaptchaApi(client pbcaptcha.CaptchaClient) *CaptchaApi {
return &CaptchaApi{Client: client}
}
func (c *CaptchaApi) GenerateCaptcha(ctx *gin.Context) {
req, err := a2r.ParseRequestNotCheck[pbcaptcha.GenerateCaptchaReq](ctx)
if err != nil {
log.ZError(ctx, "captcha generate request parse failed", err)
apiresp.GinError(ctx, err)
return
}
resp, err := c.Client.GenerateCaptcha(ctx, req)
if err != nil {
log.ZError(ctx, "captcha generate rpc failed", err)
apiresp.GinError(ctx, err)
return
}
apiresp.GinSuccess(ctx, resp)
}
func (c *CaptchaApi) VerifyCaptcha(ctx *gin.Context) {
req, err := a2r.ParseRequestNotCheck[pbcaptcha.VerifyCaptchaReq](ctx)
if err != nil {
log.ZError(ctx, "captcha verify request parse failed", err)
apiresp.GinError(ctx, err)
return
}
resp, err := c.Client.VerifyCaptcha(ctx, req)
if err != nil {
log.ZError(ctx, "captcha verify rpc failed", err, "captchaID", req.GetCaptchaID(), "x", req.GetX(), "y", req.GetY())
apiresp.GinError(ctx, err)
return
}
apiresp.GinSuccess(ctx, resp)
}

View File

@ -46,6 +46,7 @@ func Start(ctx context.Context, index int, cfg *Config) error {
// 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(&cfg.Discovery, &cfg.Share, []string{ client, err = kdisc.NewDiscoveryRegister(&cfg.Discovery, &cfg.Share, []string{
cfg.Share.RpcRegisterName.MessageGateway, cfg.Share.RpcRegisterName.MessageGateway,
cfg.Share.RpcRegisterName.Captcha,
}) })
if err != nil { if err != nil {
return errs.WrapMsg(err, "failed to register discovery service") return errs.WrapMsg(err, "failed to register discovery service")

View File

@ -7,6 +7,7 @@ import (
"github.com/openimsdk/open-im-server/v3/pkg/rpcli" "github.com/openimsdk/open-im-server/v3/pkg/rpcli"
pbAuth "github.com/openimsdk/protocol/auth" pbAuth "github.com/openimsdk/protocol/auth"
pbcaptcha "github.com/openimsdk/protocol/captcha"
"github.com/openimsdk/protocol/conversation" "github.com/openimsdk/protocol/conversation"
"github.com/openimsdk/protocol/group" "github.com/openimsdk/protocol/group"
"github.com/openimsdk/protocol/msg" "github.com/openimsdk/protocol/msg"
@ -81,6 +82,10 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
if err != nil { if err != nil {
return nil, err return nil, err
} }
captchaConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Captcha)
if err != nil {
return nil, err
}
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 {
@ -98,6 +103,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn))) r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn)))
u := NewUserApi(user.NewUserClient(userConn), client, config.Share.RpcRegisterName) u := NewUserApi(user.NewUserClient(userConn), client, config.Share.RpcRegisterName)
m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), config.Share.IMAdminUserID) m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), config.Share.IMAdminUserID)
cp := NewCaptchaApi(pbcaptcha.NewCaptchaClient(captchaConn))
userRouterGroup := r.Group("/user") userRouterGroup := r.Group("/user")
{ {
userRouterGroup.POST("/user_register", u.UserRegister) userRouterGroup.POST("/user_register", u.UserRegister)
@ -264,6 +270,12 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs) conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs)
} }
{
captchaGroup := r.Group("/captcha")
captchaGroup.POST("/generate", cp.GenerateCaptcha)
captchaGroup.POST("/verify", cp.VerifyCaptcha)
}
{ {
statisticsGroup := r.Group("/statistics") statisticsGroup := r.Group("/statistics")
statisticsGroup.POST("/user/register", u.UserRegisterCount) statisticsGroup.POST("/user/register", u.UserRegisterCount)

View File

@ -0,0 +1,158 @@
package captcha
import (
"context"
"errors"
"time"
"github.com/google/uuid"
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
pbcaptcha "github.com/openimsdk/protocol/captcha"
"github.com/openimsdk/tools/db/mongoutil"
"github.com/openimsdk/tools/discovery"
"github.com/openimsdk/tools/log"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"google.golang.org/grpc"
"github.com/wenlng/go-captcha/v2/base/option"
"github.com/wenlng/go-captcha/v2/slide"
)
type Config struct {
RpcConfig config.Captcha
MongodbConfig config.Mongo
Share config.Share
Discovery config.Discovery
}
type server struct {
pbcaptcha.UnimplementedCaptchaServer
conf config.Captcha
capt slide.Captcha
collection *mongo.Collection
}
type captchaDoc struct {
CaptchaID string `bson:"captcha_id"`
X int `bson:"x"`
Y int `bson:"y"`
ExpiredAt time.Time `bson:"expired_at"`
CreateTime time.Time `bson:"create_time"`
VerifyTime time.Time `bson:"verify_time,omitempty"`
}
func Start(ctx context.Context, cfg *Config, _ discovery.SvcDiscoveryRegistry, grpcServer *grpc.Server) error {
mongoClient, err := mongoutil.NewMongoDB(ctx, cfg.MongodbConfig.Build())
if err != nil {
log.ZError(ctx, "captcha connect mongodb failed", err)
return err
}
collection := mongoClient.GetDB().Collection("captcha")
_, err = collection.Indexes().CreateMany(ctx, []mongo.IndexModel{
{
Keys: bson.D{{Key: "captcha_id", Value: 1}},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{{Key: "expired_at", Value: 1}},
Options: options.Index().SetExpireAfterSeconds(0),
},
})
if err != nil {
log.ZError(ctx, "captcha create mongodb indexes failed", err)
return err
}
s := &server{
conf: cfg.RpcConfig,
capt: slide.NewBuilder().Make(),
collection: collection,
}
if s.conf.ExpireSeconds <= 0 {
s.conf.ExpireSeconds = 120
}
if s.conf.VerifyPadding <= 0 {
s.conf.VerifyPadding = 8
}
pbcaptcha.RegisterCaptchaServer(grpcServer, s)
return nil
}
func (s *server) GenerateCaptcha(ctx context.Context, _ *pbcaptcha.GenerateCaptchaReq) (*pbcaptcha.GenerateCaptchaResp, error) {
captData, err := s.capt.Generate()
if err != nil {
log.ZError(ctx, "captcha generate failed", err)
return nil, err
}
block := captData.GetData()
masterImage, err := captData.GetMasterImage().ToBase64DataWithQuality(option.QualityNone)
if err != nil {
log.ZError(ctx, "captcha encode master image failed", err)
return nil, err
}
tileImage, err := captData.GetTileImage().ToBase64Data()
if err != nil {
log.ZError(ctx, "captcha encode tile image failed", err)
return nil, err
}
id := uuid.NewString()
now := time.Now()
expiredAt := now.Add(time.Duration(s.conf.ExpireSeconds) * time.Second)
_, err = s.collection.InsertOne(ctx, captchaDoc{
CaptchaID: id,
X: block.X,
Y: block.Y,
ExpiredAt: expiredAt,
CreateTime: now,
})
if err != nil {
log.ZError(ctx, "captcha insert mongodb failed", err, "captchaID", id)
return nil, err
}
return &pbcaptcha.GenerateCaptchaResp{
CaptchaID: id,
MasterImage: masterImage,
TileImage: tileImage,
ExpireAt: expiredAt.Unix(),
}, nil
}
func (s *server) VerifyCaptcha(ctx context.Context, req *pbcaptcha.VerifyCaptchaReq) (*pbcaptcha.VerifyCaptchaResp, error) {
now := time.Now()
filter := bson.M{
"captcha_id": req.CaptchaID,
"verify_time": bson.M{"$exists": false},
}
update := bson.M{
"$set": bson.M{
"verify_time": now,
},
}
var doc captchaDoc
err := s.collection.FindOneAndUpdate(
ctx,
filter,
update,
options.FindOneAndUpdate().SetReturnDocument(options.Before),
).Decode(&doc)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
log.ZWarn(ctx, "captcha not found or already verified", err, "captchaID", req.CaptchaID)
return nil, servererrs.ErrRecordNotFound.WrapMsg("captcha not found, expired, or already verified", "captchaID", req.CaptchaID)
}
log.ZError(ctx, "captcha verify query failed", err, "captchaID", req.CaptchaID)
return nil, servererrs.ErrDatabase.WrapMsg("verify captcha query failed", "captchaID", req.CaptchaID)
}
if now.After(doc.ExpiredAt) {
log.ZWarn(ctx, "captcha expired", nil, "captchaID", req.CaptchaID, "expiredAt", doc.ExpiredAt.Unix())
return nil, servererrs.ErrFileUploadedExpired.WrapMsg("captcha expired", "captchaID", req.CaptchaID)
}
success := slide.Validate(int(req.X), int(req.Y), doc.X, doc.Y, s.conf.VerifyPadding)
if !success {
log.ZWarn(ctx, "captcha validate failed", nil, "captchaID", req.CaptchaID, "x", req.X, "y", req.Y)
}
return &pbcaptcha.VerifyCaptchaResp{Success: success}, nil
}

View File

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/magefile/mage/sh"
"github.com/openimsdk/gomake/mageutil" "github.com/openimsdk/gomake/mageutil"
"github.com/openimsdk/open-im-server/v3/version" "github.com/openimsdk/open-im-server/v3/version"
"github.com/openimsdk/tools/utils/datautil" "github.com/openimsdk/tools/utils/datautil"
@ -37,6 +38,14 @@ func Build() {
if len(bin) != 0 { if len(bin) != 0 {
bin = bin[1:] bin = bin[1:]
} }
mageutil.WithSpinner("Generating protocol artifacts...", func() {
if err := sh.Run("mage", "-d", "protocol", "GenGo"); err != nil {
mageutil.PrintRed("protocol compilation failed: " + err.Error())
os.Exit(1)
}
})
mageutil.WithSpinner("Building binaries...", func() { mageutil.Build(bin, nil, nil) }) mageutil.WithSpinner("Building binaries...", func() { mageutil.Build(bin, nil, nil) })
} }
@ -54,11 +63,28 @@ func BuildWithCustomConfig() {
ToolsDir: &customToolsDir, ToolsDir: &customToolsDir,
} }
mageutil.WithSpinner("Generating protocol artifacts...", func() {
if err := sh.Run("mage", "-d", "protocol", "GenGo"); err != nil {
mageutil.PrintRed("protocol compilation failed: " + err.Error())
os.Exit(1)
}
})
mageutil.WithSpinner("Building binaries with custom config...", func() { mageutil.WithSpinner("Building binaries with custom config...", func() {
mageutil.Build(bin, config, nil) mageutil.Build(bin, config, nil)
}) })
} }
// Protocol generates protobuf artifacts under `./protocol`.
func Protocol() {
mageutil.WithSpinner("Generating protocol artifacts...", func() {
if err := sh.Run("mage", "-d", "protocol", "GenGo"); err != nil {
mageutil.PrintRed("protocol compilation failed: " + err.Error())
os.Exit(1)
}
})
}
func Start() { func Start() {
mageutil.InitForSSC() mageutil.InitForSSC()
err := setMaxOpenFiles() err := setMaxOpenFiles()

View File

@ -34,7 +34,9 @@ var (
OpenIMMsgGatewayCfgFileName string OpenIMMsgGatewayCfgFileName string
OpenIMMsgTransferCfgFileName string OpenIMMsgTransferCfgFileName string
OpenIMPushCfgFileName string OpenIMPushCfgFileName string
OpenIMCaptchaCfgFileName string
OpenIMRPCAuthCfgFileName string OpenIMRPCAuthCfgFileName string
OpenIMRPCCaptchaCfgFileName string
OpenIMRPCConversationCfgFileName string OpenIMRPCConversationCfgFileName string
OpenIMRPCFriendCfgFileName string OpenIMRPCFriendCfgFileName string
OpenIMRPCGroupCfgFileName string OpenIMRPCGroupCfgFileName string
@ -62,7 +64,9 @@ func init() {
OpenIMMsgGatewayCfgFileName = "openim-msggateway.yml" OpenIMMsgGatewayCfgFileName = "openim-msggateway.yml"
OpenIMMsgTransferCfgFileName = "openim-msgtransfer.yml" OpenIMMsgTransferCfgFileName = "openim-msgtransfer.yml"
OpenIMPushCfgFileName = "openim-push.yml" OpenIMPushCfgFileName = "openim-push.yml"
OpenIMCaptchaCfgFileName = "openim-captcha.yml"
OpenIMRPCAuthCfgFileName = "openim-rpc-auth.yml" OpenIMRPCAuthCfgFileName = "openim-rpc-auth.yml"
OpenIMRPCCaptchaCfgFileName = "openim-rpc-captcha.yml"
OpenIMRPCConversationCfgFileName = "openim-rpc-conversation.yml" OpenIMRPCConversationCfgFileName = "openim-rpc-conversation.yml"
OpenIMRPCFriendCfgFileName = "openim-rpc-friend.yml" OpenIMRPCFriendCfgFileName = "openim-rpc-friend.yml"
OpenIMRPCGroupCfgFileName = "openim-rpc-group.yml" OpenIMRPCGroupCfgFileName = "openim-rpc-group.yml"
@ -77,7 +81,7 @@ func init() {
KafkaConfigFileName, RedisConfigFileName, KafkaConfigFileName, RedisConfigFileName,
MongodbConfigFileName, MinioConfigFileName, LogConfigFileName, MongodbConfigFileName, MinioConfigFileName, LogConfigFileName,
OpenIMAPICfgFileName, OpenIMCronTaskCfgFileName, OpenIMMsgGatewayCfgFileName, OpenIMAPICfgFileName, OpenIMCronTaskCfgFileName, OpenIMMsgGatewayCfgFileName,
OpenIMMsgTransferCfgFileName, OpenIMPushCfgFileName, OpenIMRPCAuthCfgFileName, OpenIMMsgTransferCfgFileName, OpenIMPushCfgFileName, OpenIMCaptchaCfgFileName, OpenIMRPCAuthCfgFileName, OpenIMRPCCaptchaCfgFileName,
OpenIMRPCConversationCfgFileName, OpenIMRPCFriendCfgFileName, OpenIMRPCGroupCfgFileName, OpenIMRPCConversationCfgFileName, OpenIMRPCFriendCfgFileName, OpenIMRPCGroupCfgFileName,
OpenIMRPCMsgCfgFileName, OpenIMRPCThirdCfgFileName, OpenIMRPCUserCfgFileName, DiscoveryConfigFilename, OpenIMRPCMsgCfgFileName, OpenIMRPCThirdCfgFileName, OpenIMRPCUserCfgFileName, DiscoveryConfigFilename,
} }

View File

@ -0,0 +1,47 @@
package cmd
import (
"context"
"github.com/openimsdk/open-im-server/v3/internal/rpc/captcha"
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
"github.com/openimsdk/open-im-server/v3/version"
"github.com/openimsdk/tools/system/program"
"github.com/spf13/cobra"
)
type CaptchaRpcCmd struct {
*RootCmd
ctx context.Context
configMap map[string]any
captchaConfig *captcha.Config
}
func NewCaptchaRpcCmd() *CaptchaRpcCmd {
var captchaConfig captcha.Config
ret := &CaptchaRpcCmd{captchaConfig: &captchaConfig}
ret.configMap = map[string]any{
OpenIMRPCCaptchaCfgFileName: &captchaConfig.RpcConfig,
MongodbConfigFileName: &captchaConfig.MongodbConfig,
ShareFileName: &captchaConfig.Share,
DiscoveryConfigFilename: &captchaConfig.Discovery,
}
ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap))
ret.ctx = context.WithValue(context.Background(), "version", version.Version)
ret.Command.RunE = func(cmd *cobra.Command, args []string) error {
return ret.runE()
}
return ret
}
func (c *CaptchaRpcCmd) Exec() error {
return c.Execute()
}
func (c *CaptchaRpcCmd) runE() error {
return startrpc.Start(c.ctx, &c.captchaConfig.Discovery, &c.captchaConfig.RpcConfig.Prometheus, c.captchaConfig.RpcConfig.RPC.ListenIP,
c.captchaConfig.RpcConfig.RPC.RegisterIP, c.captchaConfig.RpcConfig.RPC.AutoSetPorts, c.captchaConfig.RpcConfig.RPC.Ports,
c.Index(), c.captchaConfig.Share.RpcRegisterName.Captcha, &c.captchaConfig.Share, c.captchaConfig,
nil,
captcha.Start)
}

View File

@ -249,6 +249,18 @@ type Auth struct {
} `mapstructure:"tokenPolicy"` } `mapstructure:"tokenPolicy"`
} }
type Captcha struct {
RPC struct {
RegisterIP string `mapstructure:"registerIP"`
ListenIP string `mapstructure:"listenIP"`
AutoSetPorts bool `mapstructure:"autoSetPorts"`
Ports []int `mapstructure:"ports"`
} `mapstructure:"rpc"`
Prometheus Prometheus `mapstructure:"prometheus"`
VerifyPadding int `mapstructure:"verifyPadding"`
ExpireSeconds int `mapstructure:"expireSeconds"`
}
type Conversation struct { type Conversation struct {
RPC struct { RPC struct {
RegisterIP string `mapstructure:"registerIP"` RegisterIP string `mapstructure:"registerIP"`
@ -407,6 +419,7 @@ type RpcRegisterName 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"`
Captcha string `mapstructure:"captcha"`
} }
func (r *RpcRegisterName) GetServiceNames() []string { func (r *RpcRegisterName) GetServiceNames() []string {
@ -420,6 +433,7 @@ func (r *RpcRegisterName) GetServiceNames() []string {
r.Auth, r.Auth,
r.Conversation, r.Conversation,
r.Third, r.Third,
r.Captcha,
} }
} }
@ -625,6 +639,7 @@ var (
OpenIMMsgTransferCfgFileName = "openim-msgtransfer.yml" OpenIMMsgTransferCfgFileName = "openim-msgtransfer.yml"
OpenIMPushCfgFileName = "openim-push.yml" OpenIMPushCfgFileName = "openim-push.yml"
OpenIMRPCAuthCfgFileName = "openim-rpc-auth.yml" OpenIMRPCAuthCfgFileName = "openim-rpc-auth.yml"
OpenIMRPCCaptchaCfgFileName = "openim-rpc-captcha.yml"
OpenIMRPCConversationCfgFileName = "openim-rpc-conversation.yml" OpenIMRPCConversationCfgFileName = "openim-rpc-conversation.yml"
OpenIMRPCFriendCfgFileName = "openim-rpc-friend.yml" OpenIMRPCFriendCfgFileName = "openim-rpc-friend.yml"
OpenIMRPCGroupCfgFileName = "openim-rpc-group.yml" OpenIMRPCGroupCfgFileName = "openim-rpc-group.yml"
@ -688,6 +703,10 @@ func (a *Auth) GetConfigFileName() string {
return OpenIMRPCAuthCfgFileName return OpenIMRPCAuthCfgFileName
} }
func (c *Captcha) GetConfigFileName() string {
return OpenIMRPCCaptchaCfgFileName
}
func (c *Conversation) GetConfigFileName() string { func (c *Conversation) GetConfigFileName() string {
return OpenIMRPCConversationCfgFileName return OpenIMRPCConversationCfgFileName
} }

View File

@ -7,6 +7,7 @@ serviceBinaries:
openim-msgtransfer: 8 openim-msgtransfer: 8
openim-rpc-conversation: 1 openim-rpc-conversation: 1
openim-rpc-auth: 1 openim-rpc-auth: 1
openim-rpc-captcha: 1
openim-rpc-group: 1 openim-rpc-group: 1
openim-rpc-friend: 1 openim-rpc-friend: 1
openim-rpc-msg: 1 openim-rpc-msg: 1