init
This commit is contained in:
38
logic/CHANGELOG.md
Normal file
38
logic/CHANGELOG.md
Normal file
@@ -0,0 +1,38 @@
|
||||
版本号`major.minor.patch`具体规则如下:
|
||||
- major:主版本号,如有重大版本重构则该字段递增,通常各主版本间接口不兼容。
|
||||
- minor:次版本号,各次版本号间接口保持兼容,如有接口新增或优化则该字段递增。
|
||||
- patch:补丁号,如有功能改善或缺陷修复则该字段递增。
|
||||
|
||||
## version 3.1.4 @2021.10.28
|
||||
|
||||
优化 log 模块
|
||||
|
||||
配置文件更新
|
||||
新增
|
||||
```toml
|
||||
[log]
|
||||
Level="debug"
|
||||
Mode="console"
|
||||
Path=""
|
||||
Display="json"
|
||||
```
|
||||
|
||||
## version 3.1.3 @2021.7.29
|
||||
|
||||
修复当 addr 为空产生 panic
|
||||
|
||||
## version 3.1.2 @2021.7.22
|
||||
|
||||
**Feature**
|
||||
- 支持根据 server 使用指定位置的 comet rpc @3.1.2 2021.7.22
|
||||
|
||||
|
||||
## example x.x.x @yy.mm.dd
|
||||
|
||||
**Feature**
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
**Improvement**
|
||||
|
||||
**Breaking Change**
|
||||
23
logic/auth/auth.go
Normal file
23
logic/auth/auth.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package auth
|
||||
|
||||
import "time"
|
||||
|
||||
var execAuth = make(map[string]CreateFunc)
|
||||
|
||||
type CreateFunc func(url string, timeout time.Duration) Auth
|
||||
|
||||
func Register(name string, exec CreateFunc) {
|
||||
execAuth[name] = exec
|
||||
}
|
||||
|
||||
func Load(name string) (CreateFunc, error) {
|
||||
exec, ok := execAuth[name]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
return exec, nil
|
||||
}
|
||||
|
||||
type Auth interface {
|
||||
DoAuth(token string) (string, error)
|
||||
}
|
||||
67
logic/auth/dtalk/auth.go
Normal file
67
logic/auth/dtalk/auth.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package acc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"gitlab.33.cn/btrade/auto_trade_tools/reqtypes"
|
||||
"gitlab.33.cn/btrade/auto_trade_tools/util"
|
||||
)
|
||||
|
||||
type talkClient struct {
|
||||
url string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func (a *talkClient) DoAuth(token string) (uid string, err error) {
|
||||
var (
|
||||
bytes []byte
|
||||
)
|
||||
headers := map[string]string{}
|
||||
headers["FZM-SIGNATURE"] = token
|
||||
bytes, err = util.HttpReq(&reqtypes.HttpParams{
|
||||
Method: "POST",
|
||||
ReqUrl: a.url,
|
||||
HeaderMap: headers,
|
||||
Timeout: a.timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var res map[string]interface{}
|
||||
err = json.Unmarshal(bytes, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if e, ok := res["error"]; ok {
|
||||
err = errors.New(e.(string))
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := res["data"]; !ok {
|
||||
err = errors.New("invalid auth res")
|
||||
return
|
||||
}
|
||||
|
||||
data, ok := res["data"].(map[string]interface{})
|
||||
if !ok {
|
||||
err = errors.New("invalid auth data format")
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := data["address"]; !ok {
|
||||
err = errors.New("invalid auth data")
|
||||
return
|
||||
}
|
||||
|
||||
uid, ok = data["address"].(string)
|
||||
if !ok {
|
||||
err = errors.New("invalid auth data id format")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
17
logic/auth/dtalk/plugin.go
Normal file
17
logic/auth/dtalk/plugin.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package acc
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gitlab.33.cn/chat/im/logic/auth"
|
||||
)
|
||||
|
||||
const Name = "dtalk"
|
||||
|
||||
func init() {
|
||||
auth.Register(Name, NewAuth)
|
||||
}
|
||||
|
||||
func NewAuth(url string, timeout time.Duration) auth.Auth {
|
||||
return &talkClient{url: url, timeout: timeout}
|
||||
}
|
||||
67
logic/auth/zhaobi/auth.go
Normal file
67
logic/auth/zhaobi/auth.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package acc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"gitlab.33.cn/btrade/auto_trade_tools/reqtypes"
|
||||
"gitlab.33.cn/btrade/auto_trade_tools/util"
|
||||
)
|
||||
|
||||
type talkClient struct {
|
||||
url string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func (a *talkClient) DoAuth(token string) (uid string, err error) {
|
||||
var (
|
||||
bytes []byte
|
||||
)
|
||||
headers := map[string]string{}
|
||||
headers["Authorization"] = token
|
||||
bytes, err = util.HttpReq(&reqtypes.HttpParams{
|
||||
Method: "GET",
|
||||
ReqUrl: a.url,
|
||||
HeaderMap: headers,
|
||||
Timeout: a.timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var res map[string]interface{}
|
||||
err = json.Unmarshal(bytes, &res)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if e, ok := res["error"]; ok {
|
||||
err = errors.New(e.(string))
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := res["data"]; !ok {
|
||||
err = errors.New("invalid auth res")
|
||||
return
|
||||
}
|
||||
|
||||
data, ok := res["data"].(map[string]interface{})
|
||||
if !ok {
|
||||
err = errors.New("invalid auth data format")
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := data["user_id"]; !ok {
|
||||
err = errors.New("invalid auth data")
|
||||
return
|
||||
}
|
||||
|
||||
uid, ok = data["user_id"].(string)
|
||||
if !ok {
|
||||
err = errors.New("invalid auth data id format")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
17
logic/auth/zhaobi/plugin.go
Normal file
17
logic/auth/zhaobi/plugin.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package acc
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gitlab.33.cn/chat/im/logic/auth"
|
||||
)
|
||||
|
||||
const Name = "zb_otc"
|
||||
|
||||
func init() {
|
||||
auth.Register(Name, NewAuth)
|
||||
}
|
||||
|
||||
func NewAuth(url string, timeout time.Duration) auth.Auth {
|
||||
return &talkClient{url: url, timeout: timeout}
|
||||
}
|
||||
130
logic/cmd/main.go
Normal file
130
logic/cmd/main.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/Terry-Mao/goim/pkg/ip"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/uber/jaeger-client-go"
|
||||
"github.com/uber/jaeger-client-go/config"
|
||||
xlog "gitlab.33.cn/chat/im-pkg/log"
|
||||
"gitlab.33.cn/chat/im-pkg/trace"
|
||||
"gitlab.33.cn/chat/im/logic"
|
||||
_ "gitlab.33.cn/chat/im/logic/auth/dtalk"
|
||||
_ "gitlab.33.cn/chat/im/logic/auth/zhaobi"
|
||||
"gitlab.33.cn/chat/im/logic/conf"
|
||||
"gitlab.33.cn/chat/im/logic/grpc"
|
||||
"gitlab.33.cn/chat/im/naming"
|
||||
)
|
||||
|
||||
const (
|
||||
srvName = "logic"
|
||||
)
|
||||
|
||||
var (
|
||||
debug bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.BoolVar(&debug, "debug", false, "sets log level to debug")
|
||||
}
|
||||
|
||||
var (
|
||||
// projectVersion 项目版本
|
||||
projectVersion = "3.1.4"
|
||||
// goVersion go版本
|
||||
goVersion = ""
|
||||
// gitCommit git提交commit id
|
||||
gitCommit = ""
|
||||
// buildTime 编译时间
|
||||
buildTime = ""
|
||||
|
||||
isShowVersion = flag.Bool("version", false, "show project version")
|
||||
)
|
||||
|
||||
// showVersion 显示项目版本信息
|
||||
func showVersion(isShow bool) {
|
||||
if isShow {
|
||||
fmt.Printf("Project: %s\n", srvName)
|
||||
fmt.Printf(" Version: %s\n", projectVersion)
|
||||
fmt.Printf(" Go Version: %s\n", goVersion)
|
||||
fmt.Printf(" Git Commit: %s\n", gitCommit)
|
||||
fmt.Printf(" Build Time: %s\n", buildTime)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
showVersion(*isShowVersion)
|
||||
|
||||
if err := conf.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//log init
|
||||
var err error
|
||||
log.Logger, err = xlog.Init(conf.Conf.Log)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Logger.With().Str("service", srvName)
|
||||
|
||||
byte, _ := json.Marshal(conf.Conf)
|
||||
log.Info().Str("config", string(byte)).Send()
|
||||
|
||||
// trace init
|
||||
tracer, tracerCloser := trace.Init(srvName, conf.Conf.Trace, config.Logger(jaeger.NullLogger))
|
||||
//不然后续不会有Jaeger实例
|
||||
opentracing.SetGlobalTracer(tracer)
|
||||
|
||||
srv := logic.New(conf.Conf)
|
||||
rpcSrv := grpc.New(conf.Conf.RPCServer, srv)
|
||||
|
||||
go func() {
|
||||
if err := http.ListenAndServe(":8001", nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// register logic
|
||||
_, port, _ := net.SplitHostPort(conf.Conf.RPCServer.Addr)
|
||||
addr := fmt.Sprintf("%s:%s", ip.InternalIP(), port)
|
||||
if err := naming.Register(conf.Conf.Reg.RegAddrs, conf.Conf.Reg.SrvName, addr, conf.Conf.Reg.Schema, 15); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("register ok")
|
||||
|
||||
// signal
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
|
||||
for {
|
||||
s := <-c
|
||||
log.Info().Str("signal", s.String()).Send()
|
||||
switch s {
|
||||
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
|
||||
if err := naming.UnRegister(conf.Conf.Reg.SrvName, addr, conf.Conf.Reg.Schema); err != nil {
|
||||
log.Error().Err(err).Msg("naming.UnRegister")
|
||||
}
|
||||
srv.Close()
|
||||
rpcSrv.GracefulStop()
|
||||
if err := tracerCloser.Close(); err != nil {
|
||||
log.Error().Err(err).Msg("tracer close failed")
|
||||
}
|
||||
//log.Flush()
|
||||
return
|
||||
case syscall.SIGHUP:
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
6
logic/cmd/run.sh
Normal file
6
logic/cmd/run.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
# -log_dir=log 日志输出文件夹
|
||||
# -logtostderr=true 打印到标准错误而不是文件。
|
||||
# -alsologtostderr=true 同时打印到标准错误。
|
||||
# -v=4 设置日志级别
|
||||
# -vmodule=main=5 设置单个文件日志级别
|
||||
./main -v=4 -log_dir=log -alsologtostderr=true
|
||||
164
logic/conf/conf.go
Normal file
164
logic/conf/conf.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
xtime "github.com/Terry-Mao/goim/pkg/time"
|
||||
"github.com/uber/jaeger-client-go"
|
||||
traceConfig "github.com/uber/jaeger-client-go/config"
|
||||
xlog "gitlab.33.cn/chat/im-pkg/log"
|
||||
)
|
||||
|
||||
var (
|
||||
confPath string
|
||||
regAddrs string
|
||||
|
||||
// Conf config
|
||||
Conf *Config
|
||||
)
|
||||
|
||||
func init() {
|
||||
var (
|
||||
defAddrs = os.Getenv("REGADDRS")
|
||||
)
|
||||
flag.StringVar(&confPath, "conf", "logic.toml", "default config path")
|
||||
flag.StringVar(®Addrs, "reg", defAddrs, "etcd register addrs. eg:127.0.0.1:2379")
|
||||
}
|
||||
|
||||
// Init init config.
|
||||
func Init() (err error) {
|
||||
Conf = Default()
|
||||
_, err = toml.DecodeFile(confPath, &Conf)
|
||||
return
|
||||
}
|
||||
|
||||
// Default new a config with specified defualt value.
|
||||
func Default() *Config {
|
||||
return &Config{
|
||||
Env: "",
|
||||
Log: xlog.Config{
|
||||
Level: "debug",
|
||||
Mode: "console",
|
||||
Path: "",
|
||||
Display: "console",
|
||||
},
|
||||
Trace: traceConfig.Configuration{
|
||||
ServiceName: "answer",
|
||||
Gen128Bit: true,
|
||||
Sampler: &traceConfig.SamplerConfig{
|
||||
Type: jaeger.SamplerTypeConst,
|
||||
Param: 1,
|
||||
},
|
||||
Reporter: &traceConfig.ReporterConfig{
|
||||
LogSpans: true,
|
||||
LocalAgentHostPort: "127.0.0.1:6831",
|
||||
},
|
||||
},
|
||||
Reg: &Reg{
|
||||
Schema: "im",
|
||||
SrvName: "logic",
|
||||
RegAddrs: regAddrs,
|
||||
},
|
||||
CometRPCClient: &RPCClient{
|
||||
Schema: "im",
|
||||
SrvName: "comet",
|
||||
Dial: xtime.Duration(time.Second),
|
||||
Timeout: xtime.Duration(time.Second)},
|
||||
RPCServer: &RPCServer{
|
||||
Network: "tcp",
|
||||
Addr: "3119",
|
||||
Timeout: xtime.Duration(time.Second),
|
||||
IdleTimeout: xtime.Duration(time.Second * 60),
|
||||
MaxLifeTime: xtime.Duration(time.Hour * 2),
|
||||
ForceCloseWait: xtime.Duration(time.Second * 20),
|
||||
KeepAliveInterval: xtime.Duration(time.Second * 60),
|
||||
KeepAliveTimeout: xtime.Duration(time.Second * 20),
|
||||
},
|
||||
Backoff: &Backoff{MaxDelay: 300, BaseDelay: 3, Factor: 1.8, Jitter: 1.3},
|
||||
}
|
||||
}
|
||||
|
||||
// Config config.
|
||||
type Config struct {
|
||||
Env string
|
||||
Log xlog.Config
|
||||
Trace traceConfig.Configuration
|
||||
Reg *Reg
|
||||
CometRPCClient *RPCClient
|
||||
RPCServer *RPCServer
|
||||
Kafka *Kafka
|
||||
Redis *Redis
|
||||
Node *Node
|
||||
Backoff *Backoff
|
||||
Apps []*App
|
||||
}
|
||||
|
||||
// Reg is service register/discovery config
|
||||
type Reg struct {
|
||||
Schema string
|
||||
SrvName string // call
|
||||
RegAddrs string // etcd addrs, seperate by ','
|
||||
}
|
||||
|
||||
type App struct {
|
||||
AppId string
|
||||
AuthUrl string
|
||||
Timeout xtime.Duration
|
||||
}
|
||||
|
||||
// Node node config.
|
||||
type Node struct {
|
||||
HeartbeatMax int
|
||||
Heartbeat xtime.Duration
|
||||
}
|
||||
|
||||
// Backoff backoff.
|
||||
type Backoff struct {
|
||||
MaxDelay int32
|
||||
BaseDelay int32
|
||||
Factor float32
|
||||
Jitter float32
|
||||
}
|
||||
|
||||
// Redis .
|
||||
type Redis struct {
|
||||
Network string
|
||||
Addr string
|
||||
Auth string
|
||||
Active int
|
||||
Idle int
|
||||
DialTimeout xtime.Duration
|
||||
ReadTimeout xtime.Duration
|
||||
WriteTimeout xtime.Duration
|
||||
IdleTimeout xtime.Duration
|
||||
Expire xtime.Duration
|
||||
}
|
||||
|
||||
// Kafka .
|
||||
type Kafka struct {
|
||||
Topic string
|
||||
Brokers []string
|
||||
}
|
||||
|
||||
// RPCClient is RPC client config.
|
||||
type RPCClient struct {
|
||||
Schema string
|
||||
SrvName string
|
||||
Dial xtime.Duration
|
||||
Timeout xtime.Duration
|
||||
}
|
||||
|
||||
// RPCServer is RPC server config.
|
||||
type RPCServer struct {
|
||||
Network string
|
||||
Addr string
|
||||
Timeout xtime.Duration
|
||||
IdleTimeout xtime.Duration
|
||||
MaxLifeTime xtime.Duration
|
||||
ForceCloseWait xtime.Duration
|
||||
KeepAliveInterval xtime.Duration
|
||||
KeepAliveTimeout xtime.Duration
|
||||
}
|
||||
69
logic/conf/logic.toml
Normal file
69
logic/conf/logic.toml
Normal file
@@ -0,0 +1,69 @@
|
||||
env="debug"
|
||||
|
||||
[log]
|
||||
Level="debug"
|
||||
Mode="console"
|
||||
Path=""
|
||||
Display="json"
|
||||
|
||||
[Trace]
|
||||
ServiceName=""
|
||||
Gen128Bit=true
|
||||
[Trace.Sampler]
|
||||
Type="const"
|
||||
Param=1.0
|
||||
[Trace.Reporter]
|
||||
LogSpans=true
|
||||
LocalAgentHostPort="172.16.101.130:6831"
|
||||
|
||||
[reg]
|
||||
schema = "im"
|
||||
srvName = "logic"
|
||||
regAddrs = "127.0.0.1:2379"
|
||||
|
||||
[node]
|
||||
heartbeat = "4m"
|
||||
heartbeatMax = 2
|
||||
|
||||
[backoff]
|
||||
maxDelay = 300
|
||||
baseDelay = 3
|
||||
factor = 1.8
|
||||
jitter = 0.3
|
||||
|
||||
[RPCServer]
|
||||
Network = "tcp"
|
||||
Addr = ":3119"
|
||||
Timeout = "1s"
|
||||
KeepAliveMaxConnectionIdle = "60s"
|
||||
KeepAliveMaxConnectionAge = "2h"
|
||||
KeepAliveMaxMaxConnectionAgeGrace = "20s"
|
||||
KeepAliveTime = "60s"
|
||||
KeepAliveTimeout = "20s"
|
||||
|
||||
|
||||
[CometRPCClient]
|
||||
schema = "im"
|
||||
srvName = "comet"
|
||||
dial = "1s"
|
||||
timeout = "1s"
|
||||
|
||||
[kafka]
|
||||
topic = "goim-push-topic"
|
||||
brokers = ["127.0.0.1:9092"]
|
||||
|
||||
[redis]
|
||||
network = "tcp"
|
||||
addr = "127.0.0.1:6379"
|
||||
active = 60000
|
||||
idle = 1024
|
||||
dialTimeout = "200ms"
|
||||
readTimeout = "500ms"
|
||||
writeTimeout = "500ms"
|
||||
idleTimeout = "120s"
|
||||
expire = "30m"
|
||||
|
||||
[[apps]]
|
||||
appId = "dtalk"
|
||||
authUrl = "http://127.0.0.1:18002/user/login"
|
||||
timeout = "1s"
|
||||
72
logic/dao/dao.go
Normal file
72
logic/dao/dao.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"gitlab.33.cn/chat/im/logic/conf"
|
||||
kafka "gopkg.in/Shopify/sarama.v1"
|
||||
)
|
||||
|
||||
// Dao dao.
|
||||
type Dao struct {
|
||||
c *conf.Config
|
||||
kafkaPub kafka.SyncProducer
|
||||
redis *redis.Pool
|
||||
redisExpire int32
|
||||
}
|
||||
|
||||
// New new a dao and return.
|
||||
func New(c *conf.Config) *Dao {
|
||||
d := &Dao{
|
||||
c: c,
|
||||
kafkaPub: newKafkaPub(c.Kafka),
|
||||
redis: newRedis(c.Redis),
|
||||
redisExpire: int32(time.Duration(c.Redis.Expire) / time.Second),
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func newKafkaPub(c *conf.Kafka) kafka.SyncProducer {
|
||||
kc := kafka.NewConfig()
|
||||
kc.Producer.RequiredAcks = kafka.WaitForAll // Wait for all in-sync replicas to ack the message
|
||||
kc.Producer.Retry.Max = 10 // Retry up to 10 times to produce the message
|
||||
kc.Producer.Return.Successes = true
|
||||
kc.Version = kafka.V0_11_0_2
|
||||
pub, err := kafka.NewSyncProducer(c.Brokers, kc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pub
|
||||
}
|
||||
|
||||
func newRedis(c *conf.Redis) *redis.Pool {
|
||||
return &redis.Pool{
|
||||
MaxIdle: c.Idle,
|
||||
MaxActive: c.Active,
|
||||
IdleTimeout: time.Duration(c.IdleTimeout),
|
||||
Dial: func() (redis.Conn, error) {
|
||||
conn, err := redis.Dial(c.Network, c.Addr,
|
||||
redis.DialConnectTimeout(time.Duration(c.DialTimeout)),
|
||||
redis.DialReadTimeout(time.Duration(c.ReadTimeout)),
|
||||
redis.DialWriteTimeout(time.Duration(c.WriteTimeout)),
|
||||
redis.DialPassword(c.Auth),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Close close the resource.
|
||||
func (d *Dao) Close() error {
|
||||
return d.redis.Close()
|
||||
}
|
||||
|
||||
// Ping dao ping.
|
||||
func (d *Dao) Ping(c context.Context) error {
|
||||
return d.pingRedis(c)
|
||||
}
|
||||
44
logic/dao/kafka.go
Normal file
44
logic/dao/kafka.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"gitlab.33.cn/chat/im-pkg/trace"
|
||||
comet "gitlab.33.cn/chat/im/api/comet/grpc"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/rs/zerolog/log"
|
||||
pb "gitlab.33.cn/chat/im/api/logic/grpc"
|
||||
"gopkg.in/Shopify/sarama.v1"
|
||||
)
|
||||
|
||||
// PushMsg push a message to databus.
|
||||
func (d *Dao) PublishMsg(ctx context.Context, appId string, fromId string, op comet.Op, key string, msg []byte) (err error) {
|
||||
tracer := opentracing.GlobalTracer()
|
||||
span, ctx := opentracing.StartSpanFromContextWithTracer(ctx, tracer, fmt.Sprintf("Publish -%v-%v", appId, op.String()))
|
||||
defer span.Finish()
|
||||
|
||||
pushMsg := &pb.BizMsg{
|
||||
AppId: appId,
|
||||
FromId: fromId,
|
||||
Op: int32(op),
|
||||
Key: key,
|
||||
Msg: msg,
|
||||
}
|
||||
b, err := proto.Marshal(pushMsg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appTopic := fmt.Sprintf("goim-%s-topic", appId)
|
||||
m := &sarama.ProducerMessage{
|
||||
Key: sarama.StringEncoder(fromId),
|
||||
Topic: appTopic,
|
||||
Value: sarama.ByteEncoder(b),
|
||||
}
|
||||
trace.InjectMQHeader(tracer, span.Context(), ctx, m)
|
||||
if _, _, err = d.kafkaPub.SendMessage(m); err != nil {
|
||||
log.Error().Interface("pushMsg", pushMsg).Err(err).Msg("kafkaPub.SendMessage error")
|
||||
}
|
||||
return
|
||||
}
|
||||
32
logic/dao/main_test.go
Normal file
32
logic/dao/main_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
xtime "github.com/Terry-Mao/goim/pkg/time"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"gitlab.33.cn/chat/im/logic/conf"
|
||||
)
|
||||
|
||||
var (
|
||||
testConf *conf.Config
|
||||
testRedis *redis.Pool
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testRedis = newRedis(&conf.Redis{
|
||||
Network: "tcp",
|
||||
Addr: "127.0.0.1:6379",
|
||||
Auth: "",
|
||||
Active: 60000,
|
||||
Idle: 1024,
|
||||
DialTimeout: xtime.Duration(200 * time.Millisecond),
|
||||
ReadTimeout: xtime.Duration(500 * time.Millisecond),
|
||||
WriteTimeout: xtime.Duration(500 * time.Millisecond),
|
||||
IdleTimeout: xtime.Duration(120 * time.Second),
|
||||
Expire: xtime.Duration(30 * time.Minute),
|
||||
})
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
300
logic/dao/redis.go
Normal file
300
logic/dao/redis.go
Normal file
@@ -0,0 +1,300 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
MidFmt = "%s:%v" // {appId}:{uid}
|
||||
_prefixMidServer = "mid_%s:%v" // mid_{appId}:{uid} -> key:server
|
||||
_prefixKeyServer = "key_%s" // key_{key} -> server
|
||||
_prefixKeyUser = "usr_%s" // usr_{key} -> {appId}:{uid}
|
||||
_prefixGroupServer = "group_%s:%s" // group_{appId}:{gid} -> {server}:{score}
|
||||
)
|
||||
|
||||
func keyMidServer(appId string, mid string) string {
|
||||
return fmt.Sprintf(_prefixMidServer, appId, mid)
|
||||
}
|
||||
|
||||
func keyKeyServer(key string) string {
|
||||
return fmt.Sprintf(_prefixKeyServer, key)
|
||||
}
|
||||
|
||||
func keyKeyUser(key string) string {
|
||||
return fmt.Sprintf(_prefixKeyUser, key)
|
||||
}
|
||||
|
||||
func keyGroupServer(appId, gid string) string {
|
||||
return fmt.Sprintf(_prefixGroupServer, appId, gid)
|
||||
}
|
||||
|
||||
func (d *Dao) pingRedis(c context.Context) (err error) {
|
||||
conn := d.redis.Get()
|
||||
_, err = conn.Do("SET", "PING", "PONG")
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Dao) GetMember(c context.Context, key string) (appId string, mid string, err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
ss, err := redis.String(conn.Do("GET", keyKeyUser(key)))
|
||||
if err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.DO(GET)")
|
||||
return "", "", err
|
||||
}
|
||||
arr := strings.Split(ss, ":")
|
||||
if len(arr) != 2 {
|
||||
return "", "", errors.New("invalid key")
|
||||
}
|
||||
appId = arr[0]
|
||||
mid = arr[1]
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Dao) GetServer(c context.Context, key string) (server string, err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
if server, err = redis.String(conn.Do("GET", keyKeyServer(key))); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.DO(GET)")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Dao) AddMapping(c context.Context, mid string, appId string, key string, server string) (err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
var n = 4
|
||||
if mid != "" {
|
||||
if err = conn.Send("HSET", keyMidServer(appId, mid), key, server); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(HSET %s,%s,%s,%s) error", appId, mid, server, key))
|
||||
return
|
||||
}
|
||||
if err = conn.Send("EXPIRE", keyMidServer(appId, mid), d.redisExpire); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(EXPIRE %s,%s,%s,%s)", appId, mid, key, server))
|
||||
return
|
||||
}
|
||||
n += 2
|
||||
}
|
||||
if err = conn.Send("SET", keyKeyServer(key), server); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(HSET %s,%s,%s) error", mid, server, key))
|
||||
return
|
||||
}
|
||||
if err = conn.Send("EXPIRE", keyKeyServer(key), d.redisExpire); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(EXPIRE %s,%s,%s) error", mid, key, server))
|
||||
return
|
||||
}
|
||||
user := fmt.Sprintf(MidFmt, appId, mid)
|
||||
if err = conn.Send("SET", keyKeyUser(key), user); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(HSET %s,%s,%s) error", mid, appId, key))
|
||||
return
|
||||
}
|
||||
if err = conn.Send("EXPIRE", keyKeyUser(key), d.redisExpire); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(EXPIRE %s,%s,%s) error", mid, appId, key))
|
||||
return
|
||||
}
|
||||
if err = conn.Flush(); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Flush() error")
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if _, err = conn.Receive(); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Receive() error")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ExpireMapping expire a mapping.
|
||||
func (d *Dao) ExpireMapping(c context.Context, mid string, appId string, key string) (has bool, err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
var n = 2
|
||||
if mid != "" {
|
||||
if err = conn.Send("EXPIRE", keyMidServer(appId, mid), d.redisExpire); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(EXPIRE %s) error", keyMidServer(appId, mid)))
|
||||
return
|
||||
}
|
||||
n++
|
||||
}
|
||||
if err = conn.Send("EXPIRE", keyKeyServer(key), d.redisExpire); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(EXPIRE %s) error", keyKeyServer(key)))
|
||||
return
|
||||
}
|
||||
if err = conn.Send("EXPIRE", keyKeyUser(key), d.redisExpire); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(EXPIRE %s) error", keyKeyServer(key)))
|
||||
return
|
||||
}
|
||||
if err = conn.Flush(); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Flush() error")
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if has, err = redis.Bool(conn.Receive()); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Receive() error")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Dao) DelMapping(c context.Context, mid string, appId string, key string) (has bool, err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
var n = 2
|
||||
if mid != "" {
|
||||
if err = conn.Send("HDEL", keyMidServer(appId, mid), key); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(HDEL %s) error", keyMidServer(appId, mid)))
|
||||
return
|
||||
}
|
||||
n++
|
||||
}
|
||||
if err = conn.Send("DEL", keyKeyServer(key)); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(DEL %s) error", keyKeyServer(key)))
|
||||
return
|
||||
}
|
||||
if err = conn.Send("DEL", keyKeyUser(key)); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(DEL %s) error", keyKeyUser(key)))
|
||||
return
|
||||
}
|
||||
if err = conn.Flush(); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Flush() error")
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if has, err = redis.Bool(conn.Receive()); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Receive() error")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ServersByKeys get a server by key.
|
||||
func (d *Dao) ServersByKeys(c context.Context, keys []string) (res []string, err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
var args []interface{}
|
||||
for _, key := range keys {
|
||||
args = append(args, keyKeyServer(key))
|
||||
}
|
||||
if res, err = redis.Strings(conn.Do("MGET", args...)); err != nil {
|
||||
log.Error().Err(err).Msg(fmt.Sprintf("conn.Do(MGET %v) error", args))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// KeysByMids get a key server by mid.
|
||||
func (d *Dao) KeysByMids(c context.Context, appId string, mids []string) (ress map[string]string, olMids []string, err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
ress = make(map[string]string)
|
||||
for _, mid := range mids {
|
||||
if err = conn.Send("HGETALL", keyMidServer(appId, mid)); err != nil {
|
||||
log.Error().Err(err).Msg(fmt.Sprintf("conn.Do(HGETALL %s) error", mid))
|
||||
return
|
||||
}
|
||||
}
|
||||
if err = conn.Flush(); err != nil {
|
||||
log.Error().Err(err).Msg("conn.Flush() error")
|
||||
return
|
||||
}
|
||||
for idx := 0; idx < len(mids); idx++ {
|
||||
var (
|
||||
res map[string]string
|
||||
)
|
||||
if res, err = redis.StringMap(conn.Receive()); err != nil {
|
||||
log.Error().Err(err).Msg("conn.Receive() error")
|
||||
return
|
||||
}
|
||||
if len(res) > 0 {
|
||||
olMids = append(olMids, mids[idx])
|
||||
}
|
||||
for k, v := range res {
|
||||
ress[k] = v
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//groups
|
||||
func (d *Dao) IncGroupServer(c context.Context, appId, key, server string, gid []string) (err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
var n = 0
|
||||
for _, g := range gid {
|
||||
if err = conn.Send("ZINCRBY", keyGroupServer(appId, g), "1", server); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(
|
||||
fmt.Sprintf("conn.Send(ZINCRBY %s,%s,%s) error", keyGroupServer(appId, g), "1", server))
|
||||
return
|
||||
}
|
||||
//if err = conn.Send("EXPIRE", keyGroupServer(appId, g), d.redisExpire); err != nil {
|
||||
// log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(EXPIRE %s,%s,%s,%s)", appId, mid, key, server))
|
||||
// return
|
||||
//}
|
||||
n++
|
||||
}
|
||||
if err = conn.Flush(); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Flush() error")
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if _, err = conn.Receive(); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Receive() error")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *Dao) DecGroupServer(c context.Context, appId, key, server string, gid []string) (err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
var n = 0
|
||||
for _, g := range gid {
|
||||
if err = conn.Send("ZINCRBY", keyGroupServer(appId, g), "-1", server); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg(
|
||||
fmt.Sprintf("conn.Send(ZINCRBY %s,%s,%s) error", keyGroupServer(appId, g), "-1", server))
|
||||
return
|
||||
}
|
||||
//if err = conn.Send("EXPIRE", keyGroupServer(appId, g), d.redisExpire); err != nil {
|
||||
// log.Error().Str("key", key).Err(err).Msg(fmt.Sprintf("conn.Send(EXPIRE %s,%s,%s,%s)", appId, mid, key, server))
|
||||
// return
|
||||
//}
|
||||
n++
|
||||
}
|
||||
if err = conn.Flush(); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Flush() error")
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if _, err = conn.Receive(); err != nil {
|
||||
log.Error().Str("key", key).Err(err).Msg("conn.Receive() error")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// KeysByMids get a key server by mid.
|
||||
func (d *Dao) ServersByGid(c context.Context, appId string, gid string) (res []string, err error) {
|
||||
conn := d.redis.Get()
|
||||
defer conn.Close()
|
||||
res = make([]string, 0)
|
||||
ress := make(map[string]string)
|
||||
if ress, err = redis.StringMap(conn.Do("ZRANGE", keyGroupServer(appId, gid), "0", "-1", "WITHSCORES")); err != nil {
|
||||
log.Error().Str("appId", appId).Str("gid", gid).Err(err).Msg(
|
||||
fmt.Sprintf("conn.DO(ZRANGE %s,%s,%s,%s) error", keyGroupServer(appId, gid), "0", "-1", "WITHSCORES"))
|
||||
}
|
||||
for k, _ := range ress {
|
||||
res = append(res, k)
|
||||
}
|
||||
return
|
||||
}
|
||||
231
logic/dao/redis_test.go
Normal file
231
logic/dao/redis_test.go
Normal file
@@ -0,0 +1,231 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"gopkg.in/Shopify/sarama.v1"
|
||||
"testing"
|
||||
|
||||
"gitlab.33.cn/chat/im/logic/conf"
|
||||
)
|
||||
|
||||
func TestDao_IncGroupServer(t *testing.T) {
|
||||
type fields struct {
|
||||
c *conf.Config
|
||||
kafkaPub sarama.SyncProducer
|
||||
redis *redis.Pool
|
||||
redisExpire int32
|
||||
}
|
||||
type args struct {
|
||||
c context.Context
|
||||
appId string
|
||||
key string
|
||||
server string
|
||||
gid []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{
|
||||
name: "",
|
||||
fields: fields{
|
||||
c: testConf,
|
||||
kafkaPub: nil,
|
||||
redis: testRedis,
|
||||
redisExpire: 0,
|
||||
},
|
||||
args: args{
|
||||
c: nil,
|
||||
appId: "dtalk",
|
||||
key: "1",
|
||||
server: "grpc://172.0.0.1:8080",
|
||||
gid: []string{"1"},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := &Dao{
|
||||
c: tt.fields.c,
|
||||
kafkaPub: tt.fields.kafkaPub,
|
||||
redis: tt.fields.redis,
|
||||
redisExpire: tt.fields.redisExpire,
|
||||
}
|
||||
if err := d.IncGroupServer(tt.args.c, tt.args.appId, tt.args.key, tt.args.server, tt.args.gid); (err != nil) != tt.wantErr {
|
||||
t.Errorf("IncGroupServer() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDao_DecGroupServer(t *testing.T) {
|
||||
type fields struct {
|
||||
c *conf.Config
|
||||
kafkaPub sarama.SyncProducer
|
||||
redis *redis.Pool
|
||||
redisExpire int32
|
||||
}
|
||||
type args struct {
|
||||
c context.Context
|
||||
appId string
|
||||
key string
|
||||
server string
|
||||
gid []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{
|
||||
name: "",
|
||||
fields: fields{
|
||||
c: testConf,
|
||||
kafkaPub: nil,
|
||||
redis: testRedis,
|
||||
redisExpire: 0,
|
||||
},
|
||||
args: args{
|
||||
c: nil,
|
||||
appId: "dtalk",
|
||||
key: "1",
|
||||
server: "grpc://172.0.0.1:8080",
|
||||
gid: []string{"1"},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := &Dao{
|
||||
c: tt.fields.c,
|
||||
kafkaPub: tt.fields.kafkaPub,
|
||||
redis: tt.fields.redis,
|
||||
redisExpire: tt.fields.redisExpire,
|
||||
}
|
||||
if err := d.DecGroupServer(tt.args.c, tt.args.appId, tt.args.key, tt.args.server, tt.args.gid); (err != nil) != tt.wantErr {
|
||||
t.Errorf("IncGroupServer() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDao_ServersByGid(t *testing.T) {
|
||||
type fields struct {
|
||||
c *conf.Config
|
||||
kafkaPub sarama.SyncProducer
|
||||
redis *redis.Pool
|
||||
redisExpire int32
|
||||
}
|
||||
type args struct {
|
||||
c context.Context
|
||||
appId string
|
||||
gid string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantRes []string
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{
|
||||
name: "",
|
||||
fields: fields{
|
||||
c: nil,
|
||||
kafkaPub: nil,
|
||||
redis: testRedis,
|
||||
redisExpire: 0,
|
||||
},
|
||||
args: args{
|
||||
c: nil,
|
||||
appId: "dtalk",
|
||||
gid: "1",
|
||||
},
|
||||
wantRes: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := &Dao{
|
||||
c: tt.fields.c,
|
||||
kafkaPub: tt.fields.kafkaPub,
|
||||
redis: tt.fields.redis,
|
||||
redisExpire: tt.fields.redisExpire,
|
||||
}
|
||||
gotRes, err := d.ServersByGid(tt.args.c, tt.args.appId, tt.args.gid)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ServersByGid() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
for i, re := range gotRes {
|
||||
t.Logf("got %v:%v\n", i, re)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDao_KeysByMids(t *testing.T) {
|
||||
type fields struct {
|
||||
c *conf.Config
|
||||
kafkaPub sarama.SyncProducer
|
||||
redis *redis.Pool
|
||||
redisExpire int32
|
||||
}
|
||||
type args struct {
|
||||
c context.Context
|
||||
appId string
|
||||
mids []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantRess map[string]string
|
||||
wantOlMids []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "",
|
||||
fields: fields{
|
||||
c: testConf,
|
||||
kafkaPub: nil,
|
||||
redis: testRedis,
|
||||
redisExpire: 0,
|
||||
},
|
||||
args: args{
|
||||
c: context.Background(),
|
||||
appId: "dtalk",
|
||||
mids: []string{"1ygj6Un2UzL2rev6ub6NukWrGcKjW8LoG", "1LNaxM1BtkkRpWEGty8bDxmvWwRwxsCy1B", "14si8HGSBKN2B4Ps7QQJeRLvqWoXHX2NwB", ""},
|
||||
},
|
||||
wantRess: nil,
|
||||
wantOlMids: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d := &Dao{
|
||||
c: tt.fields.c,
|
||||
kafkaPub: tt.fields.kafkaPub,
|
||||
redis: tt.fields.redis,
|
||||
redisExpire: tt.fields.redisExpire,
|
||||
}
|
||||
gotRess, gotOlMids, err := d.KeysByMids(tt.args.c, tt.args.appId, tt.args.mids)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(gotRess)
|
||||
t.Log(gotOlMids)
|
||||
})
|
||||
}
|
||||
}
|
||||
187
logic/grpc/server.go
Normal file
187
logic/grpc/server.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"gitlab.33.cn/chat/im-pkg/trace"
|
||||
pb "gitlab.33.cn/chat/im/api/logic/grpc"
|
||||
"gitlab.33.cn/chat/im/logic"
|
||||
"gitlab.33.cn/chat/im/logic/conf"
|
||||
"google.golang.org/grpc"
|
||||
_ "google.golang.org/grpc/encoding/gzip"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
)
|
||||
|
||||
func New(c *conf.RPCServer, l *logic.Logic) *grpc.Server {
|
||||
keepParams := grpc.KeepaliveParams(keepalive.ServerParameters{
|
||||
MaxConnectionIdle: time.Duration(c.IdleTimeout),
|
||||
MaxConnectionAgeGrace: time.Duration(c.ForceCloseWait),
|
||||
Time: time.Duration(c.KeepAliveInterval),
|
||||
Timeout: time.Duration(c.KeepAliveTimeout),
|
||||
MaxConnectionAge: time.Duration(c.MaxLifeTime),
|
||||
})
|
||||
connectionTimeout := grpc.ConnectionTimeout(time.Duration(c.Timeout))
|
||||
srv := grpc.NewServer(keepParams, connectionTimeout,
|
||||
grpc.ChainUnaryInterceptor(
|
||||
trace.OpentracingServerInterceptor,
|
||||
))
|
||||
pb.RegisterLogicServer(srv, &server{srv: l})
|
||||
lis, err := net.Listen(c.Network, c.Addr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
go func() {
|
||||
if err := srv.Serve(lis); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
return srv
|
||||
}
|
||||
|
||||
type server struct {
|
||||
pb.UnimplementedLogicServer
|
||||
srv *logic.Logic
|
||||
}
|
||||
|
||||
var _ pb.LogicServer = &server{}
|
||||
|
||||
// Connect connect a conn.
|
||||
func (s *server) Connect(ctx context.Context, req *pb.ConnectReq) (*pb.ConnectReply, error) {
|
||||
mid, appId, key, hb, err := s.srv.Connect(ctx, req.Server, req.Proto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.ConnectReply{Key: key, AppId: appId, Mid: mid, Heartbeat: hb}, nil
|
||||
}
|
||||
|
||||
// Disconnect disconnect a conn.
|
||||
func (s *server) Disconnect(ctx context.Context, req *pb.DisconnectReq) (*pb.Reply, error) {
|
||||
_, err := s.srv.Disconnect(ctx, req.Key, req.Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true}, nil
|
||||
}
|
||||
|
||||
// Heartbeat beartbeat a conn.
|
||||
func (s *server) Heartbeat(ctx context.Context, req *pb.HeartbeatReq) (*pb.Reply, error) {
|
||||
if err := s.srv.Heartbeat(ctx, req.Key, req.Server); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true}, nil
|
||||
}
|
||||
|
||||
// Receive receive a message from client.
|
||||
func (s *server) Receive(ctx context.Context, req *pb.ReceiveReq) (*pb.Reply, error) {
|
||||
if err := s.srv.Receive(ctx, req.Key, req.Proto); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true}, nil
|
||||
}
|
||||
|
||||
// Push push a biz message to client.
|
||||
func (s *server) PushByMids(ctx context.Context, req *pb.MidsMsg) (*pb.Reply, error) {
|
||||
reply, err := s.srv.PushByMids(ctx, req.AppId, req.ToIds, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := proto.Marshal(reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true, Msg: msg}, nil
|
||||
}
|
||||
|
||||
// Push push a biz message to client.
|
||||
func (s *server) PushByKeys(ctx context.Context, req *pb.KeysMsg) (*pb.Reply, error) {
|
||||
reply, err := s.srv.PushByKeys(ctx, req.AppId, req.ToKeys, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := proto.Marshal(reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true, Msg: msg}, nil
|
||||
}
|
||||
|
||||
// Push push a biz message to client.
|
||||
func (s *server) PushGroup(ctx context.Context, req *pb.GroupMsg) (*pb.Reply, error) {
|
||||
reply, err := s.srv.PushGroup(ctx, req.AppId, req.Group, req.Msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := proto.Marshal(reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true, Msg: msg}, nil
|
||||
}
|
||||
|
||||
// Push push a biz message to client.
|
||||
func (s *server) JoinGroupsByKeys(ctx context.Context, req *pb.GroupsKey) (*pb.Reply, error) {
|
||||
reply, err := s.srv.JoinGroupsByKeys(ctx, req.AppId, req.Keys, req.Gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := proto.Marshal(reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true, Msg: msg}, nil
|
||||
}
|
||||
|
||||
// Push push a biz message to client.
|
||||
func (s *server) JoinGroupsByMids(ctx context.Context, req *pb.GroupsMid) (*pb.Reply, error) {
|
||||
reply, err := s.srv.JoinGroupsByMids(ctx, req.AppId, req.Mids, req.Gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := proto.Marshal(reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true, Msg: msg}, nil
|
||||
}
|
||||
|
||||
// Push push a biz message to client.
|
||||
func (s *server) LeaveGroupsByKeys(ctx context.Context, req *pb.GroupsKey) (*pb.Reply, error) {
|
||||
reply, err := s.srv.LeaveGroupsByKeys(ctx, req.AppId, req.Keys, req.Gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := proto.Marshal(reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true, Msg: msg}, nil
|
||||
}
|
||||
|
||||
// Push push a biz message to client.
|
||||
func (s *server) LeaveGroupsByMids(ctx context.Context, req *pb.GroupsMid) (*pb.Reply, error) {
|
||||
reply, err := s.srv.LeaveGroupsByMids(ctx, req.AppId, req.Mids, req.Gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := proto.Marshal(reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true, Msg: msg}, nil
|
||||
}
|
||||
|
||||
// Push push a biz message to client.
|
||||
func (s *server) DelGroups(ctx context.Context, req *pb.DelGroupsReq) (*pb.Reply, error) {
|
||||
reply, err := s.srv.DelGroups(ctx, req.AppId, req.Gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := proto.Marshal(reply)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.Reply{IsOk: true, Msg: msg}, nil
|
||||
}
|
||||
426
logic/logic.go
Normal file
426
logic/logic.go
Normal file
@@ -0,0 +1,426 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog/log"
|
||||
"gitlab.33.cn/chat/im-pkg/trace"
|
||||
comet "gitlab.33.cn/chat/im/api/comet/grpc"
|
||||
"gitlab.33.cn/chat/im/common"
|
||||
"gitlab.33.cn/chat/im/logic/auth"
|
||||
"gitlab.33.cn/chat/im/logic/conf"
|
||||
"gitlab.33.cn/chat/im/logic/dao"
|
||||
"gitlab.33.cn/chat/im/naming"
|
||||
xkey "gitlab.33.cn/chat/im/naming/balancer/key"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
var ErrInvalidAuthReq = errors.New("ErrInvalidAuthReq")
|
||||
var ErrInvalidAppId = errors.New("ErrInvalidAppId")
|
||||
|
||||
type Logic struct {
|
||||
c *conf.Config
|
||||
dao *dao.Dao
|
||||
cometClient comet.CometClient
|
||||
apps map[string]auth.Auth
|
||||
}
|
||||
|
||||
func New(c *conf.Config) (l *Logic) {
|
||||
cometClient, err := newCometClient(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
l = &Logic{
|
||||
c: c,
|
||||
dao: dao.New(c),
|
||||
cometClient: cometClient,
|
||||
apps: make(map[string]auth.Auth),
|
||||
}
|
||||
l.loadApps()
|
||||
return l
|
||||
}
|
||||
|
||||
func newCometClient(c *conf.Config) (comet.CometClient, error) {
|
||||
rb := naming.NewResolver(c.Reg.RegAddrs, c.CometRPCClient.Schema)
|
||||
resolver.Register(rb)
|
||||
|
||||
addr := fmt.Sprintf("%s:///%s", c.CometRPCClient.Schema, c.CometRPCClient.SrvName) // "schema://[authority]/service"
|
||||
fmt.Println("rpc client call addr:", addr)
|
||||
conn, err := common.NewGRPCConnWithKey(addr, time.Duration(c.CometRPCClient.Dial), grpc.WithUnaryInterceptor(trace.OpentracingClientInterceptor))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return comet.NewCometClient(conn), err
|
||||
}
|
||||
|
||||
func (l *Logic) loadApps() {
|
||||
for _, app := range l.c.Apps {
|
||||
newAuth, _ := auth.Load(app.AppId)
|
||||
if newAuth == nil {
|
||||
panic("exec auth not exist:" + app.AppId)
|
||||
}
|
||||
exec := newAuth(app.AuthUrl, time.Duration(app.Timeout))
|
||||
l.apps[app.AppId] = exec
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logic) Close() {
|
||||
l.dao.Close()
|
||||
}
|
||||
|
||||
// Connect connected a conn.
|
||||
func (l *Logic) Connect(c context.Context, server string, p *comet.Proto) (mid string, appId string, key string, hb int64, err error) {
|
||||
var (
|
||||
authMsg comet.AuthMsg
|
||||
bytes []byte
|
||||
)
|
||||
log.Info().Str("appId", authMsg.AppId).Bytes("body", p.Body).Str("token", authMsg.Token).Msg("call Connect")
|
||||
err = proto.Unmarshal(p.Body, &authMsg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if authMsg.AppId == "" || authMsg.Token == "" {
|
||||
err = ErrInvalidAuthReq
|
||||
return
|
||||
}
|
||||
log.Info().Str("appId", authMsg.AppId).Str("token", authMsg.Token).Msg("call auth")
|
||||
appId = authMsg.AppId
|
||||
authExec, _ := l.apps[authMsg.AppId]
|
||||
if authExec == nil {
|
||||
err = ErrInvalidAppId
|
||||
return
|
||||
}
|
||||
|
||||
mid, err = authExec.DoAuth(authMsg.Token)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hb = int64(l.c.Node.Heartbeat) * int64(l.c.Node.HeartbeatMax)
|
||||
key = uuid.New().String() //连接标识
|
||||
if err = l.dao.AddMapping(c, mid, appId, key, server); err != nil {
|
||||
log.Error().Err(err).Msg(fmt.Sprintf("l.dao.AddMapping(%s,%s,%s) error", mid, key, server))
|
||||
return
|
||||
}
|
||||
log.Info().Str("key", key).Str("mid", mid).Str("appId", appId).Str("comet", server).Msg("conn connected")
|
||||
// notify biz user connected
|
||||
bytes, err = proto.Marshal(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = l.dao.PublishMsg(c, appId, mid, comet.Op_Auth, key, bytes)
|
||||
return
|
||||
}
|
||||
|
||||
// Disconnect disconnect a conn.
|
||||
func (l *Logic) Disconnect(c context.Context, key string, server string) (has bool, err error) {
|
||||
appId, mid, err := l.dao.GetMember(c, key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if has, err = l.dao.DelMapping(c, mid, appId, key); err != nil {
|
||||
log.Error().Err(err).Msg(fmt.Sprintf("l.dao.DelMapping(%s,%s) error", mid, appId))
|
||||
return
|
||||
}
|
||||
log.Info().Str("key", key).Str("mid", mid).Str("appId", appId).Str("comet", server).Msg("conn disconnected")
|
||||
// notify biz user disconnected
|
||||
l.dao.PublishMsg(c, appId, mid, comet.Op_Disconnect, key, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Heartbeat heartbeat a conn.
|
||||
func (l *Logic) Heartbeat(c context.Context, key string, server string) (err error) {
|
||||
appId, mid, err := l.dao.GetMember(c, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var has bool
|
||||
has, err = l.dao.ExpireMapping(c, mid, appId, key)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg(fmt.Sprintf("l.dao.ExpireMapping(%s,%s) error", mid, appId))
|
||||
return
|
||||
}
|
||||
if !has {
|
||||
if err = l.dao.AddMapping(c, mid, appId, key, server); err != nil {
|
||||
log.Error().Err(err).Msg(fmt.Sprintf("l.dao.AddMapping(%s,%s,%s) error", mid, appId, server))
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Debug().Str("key", key).Str("mid", mid).Str("appId", appId).Str("comet", server).Msg("conn heartbeat")
|
||||
return
|
||||
}
|
||||
|
||||
// Receive receive a message from client.
|
||||
func (l *Logic) Receive(c context.Context, key string, p *comet.Proto) (err error) {
|
||||
appId, mid, err := l.dao.GetMember(c, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug().Str("appId", appId).Str("mid", mid).Interface("proto", p).Msg("receive proto")
|
||||
msg, err := proto.Marshal(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return l.dao.PublishMsg(c, appId, mid, comet.Op(p.Op), key, msg)
|
||||
}
|
||||
|
||||
// PushByMids Push push a biz message to client.
|
||||
func (l *Logic) PushByMids(c context.Context, appId string, toIds []string, msg []byte) (reply *comet.PushMsgReply, err error) {
|
||||
log.Debug().Str("appId", appId).Strs("mids", toIds).Msg("PushByMids start")
|
||||
|
||||
var p comet.Proto
|
||||
err = proto.Unmarshal(msg, &p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
server2keys, err := l.getServerByMids(c, appId, toIds)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for server, keys := range server2keys {
|
||||
log.Debug().Strs("keys", keys).Str("server", server).Msg("PushByMids pushing")
|
||||
reply, err = l.cometClient.PushMsg(context.WithValue(c, xkey.DefaultKey, convertAddress(server)), &comet.PushMsgReq{Keys: keys, Proto: &p})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Strs("keys", keys).Str("server", server).Msg("PushByMids l.cometClient.PushMsg")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PushByKeys Push push a biz message to client.
|
||||
func (l *Logic) PushByKeys(c context.Context, appId string, keys []string, msg []byte) (reply *comet.PushMsgReply, err error) {
|
||||
log.Debug().Str("appId", appId).Strs("keys", keys).Msg("PushByKeys start")
|
||||
|
||||
var p comet.Proto
|
||||
err = proto.Unmarshal(msg, &p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
server2keys, err := l.getServerByKeys(c, keys)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for server, keys := range server2keys {
|
||||
log.Debug().Strs("keys", keys).Str("server", server).Msg("PushByMids pushing")
|
||||
reply, err = l.cometClient.PushMsg(context.WithValue(c, xkey.DefaultKey, convertAddress(server)), &comet.PushMsgReq{Keys: keys, Proto: &p})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Strs("keys", keys).Str("server", server).Msg("PushByMids l.cometClient.PushMsg")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PushGroup Push push a biz message to client.
|
||||
func (l *Logic) PushGroup(c context.Context, appId string, group string, msg []byte) (reply *comet.BroadcastGroupReply, err error) {
|
||||
log.Debug().Str("appId", appId).Str("group", group).Msg("PushGroup start")
|
||||
var p comet.Proto
|
||||
err = proto.Unmarshal(msg, &p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cometServers, err := l.dao.ServersByGid(c, appId, group)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, server := range cometServers {
|
||||
log.Debug().Str("appId", appId).Str("group", group).Str("server", server).Msg("PushGroup pushing")
|
||||
reply, err = l.cometClient.BroadcastGroup(context.WithValue(c, xkey.DefaultKey, convertAddress(server)), &comet.BroadcastGroupReq{GroupID: appGid(appId, group), Proto: &p})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("appId", appId).Str("group", group).Str("server", server).Msg("PushGroup l.cometClient.BroadcastGroup")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// JoinGroupsByMids Push push a biz message to client.
|
||||
func (l *Logic) JoinGroupsByMids(c context.Context, appId string, mids []string, gids []string) (reply *comet.JoinGroupsReply, err error) {
|
||||
log.Debug().Str("appId", appId).Strs("mids", mids).Strs("group", gids).Msg("JoinGroupsByMids start")
|
||||
|
||||
server2keys, err := l.getServerByMids(c, appId, mids)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for server, keys := range server2keys {
|
||||
for _, key := range keys {
|
||||
_ = l.dao.IncGroupServer(c, appId, key, server, gids)
|
||||
}
|
||||
|
||||
log.Debug().Strs("keys", keys).Str("server", server).Msg("JoinGroupsByMids pushing")
|
||||
reply, err = l.cometClient.JoinGroups(context.WithValue(c, xkey.DefaultKey, convertAddress(server)), &comet.JoinGroupsReq{Keys: keys, Gid: appGids(appId, gids)})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Strs("keys", keys).Str("server", server).Msg("JoinGroupsByMids l.cometClient.JoinGroups")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// JoinGroupsByKeys Push push a biz message to client.
|
||||
func (l *Logic) JoinGroupsByKeys(c context.Context, appId string, keys []string, gids []string) (reply *comet.JoinGroupsReply, err error) {
|
||||
log.Debug().Str("appId", appId).Strs("keys", keys).Strs("group", gids).Msg("JoinGroupsByKeys start")
|
||||
|
||||
server2keys, err := l.getServerByKeys(c, keys)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for server, keys := range server2keys {
|
||||
for _, key := range keys {
|
||||
_ = l.dao.IncGroupServer(c, appId, key, server, gids)
|
||||
}
|
||||
|
||||
log.Debug().Strs("keys", keys).Str("server", server).Msg("JoinGroupsByKeys pushing")
|
||||
reply, err = l.cometClient.JoinGroups(context.WithValue(c, xkey.DefaultKey, convertAddress(server)), &comet.JoinGroupsReq{Keys: keys, Gid: appGids(appId, gids)})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Strs("keys", keys).Str("server", server).Msg("JoinGroupsByKeys l.cometClient.JoinGroups")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// LeaveGroupsByMids Push push a biz message to client.
|
||||
func (l *Logic) LeaveGroupsByMids(c context.Context, appId string, mids []string, gids []string) (reply *comet.LeaveGroupsReply, err error) {
|
||||
log.Debug().Str("appId", appId).Strs("mids", mids).Strs("group", gids).Msg("LeaveGroupsByMids start")
|
||||
|
||||
server2keys, err := l.getServerByMids(c, appId, mids)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for server, keys := range server2keys {
|
||||
for _, key := range keys {
|
||||
_ = l.dao.DecGroupServer(c, appId, key, server, gids)
|
||||
}
|
||||
|
||||
log.Debug().Strs("keys", keys).Str("server", server).Msg("LeaveGroupsByMids pushing")
|
||||
reply, err = l.cometClient.LeaveGroups(context.WithValue(c, xkey.DefaultKey, convertAddress(server)), &comet.LeaveGroupsReq{Keys: keys, Gid: appGids(appId, gids)})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Strs("keys", keys).Str("server", server).Msg("LeaveGroupsByMids l.cometClient.LeaveGroups")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// LeaveGroupsByKeys Push push a biz message to client.
|
||||
func (l *Logic) LeaveGroupsByKeys(c context.Context, appId string, keys []string, gids []string) (reply *comet.LeaveGroupsReply, err error) {
|
||||
log.Debug().Str("appId", appId).Strs("keys", keys).Strs("group", gids).Msg("LeaveGroupsByKeys start")
|
||||
|
||||
server2keys, err := l.getServerByKeys(c, keys)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for server, keys := range server2keys {
|
||||
for _, key := range keys {
|
||||
_ = l.dao.DecGroupServer(c, appId, key, server, gids)
|
||||
}
|
||||
|
||||
log.Debug().Strs("keys", keys).Str("server", server).Msg("LeaveGroupsByKeys pushing")
|
||||
reply, err = l.cometClient.LeaveGroups(context.WithValue(c, xkey.DefaultKey, convertAddress(server)), &comet.LeaveGroupsReq{Keys: keys, Gid: appGids(appId, gids)})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Strs("keys", keys).Str("server", server).Msg("LeaveGroupsByKeys l.cometClient.LeaveGroups")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DelGroups Push push a biz message to client.
|
||||
func (l *Logic) DelGroups(c context.Context, appId string, gids []string) (reply *comet.DelGroupsReply, err error) {
|
||||
log.Debug().Str("appId", appId).Strs("groups", gids).Msg("DelGroups start")
|
||||
|
||||
server2gids := make(map[string][]string)
|
||||
|
||||
for _, gid := range gids {
|
||||
cometServers, err := l.dao.ServersByGid(c, appId, gid)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, server := range cometServers {
|
||||
server2gids[server] = append(server2gids[server], gid)
|
||||
}
|
||||
}
|
||||
|
||||
for server, gids := range server2gids {
|
||||
log.Debug().Str("appId", appId).Interface("gids", gids).Str("server", server).Msg("DelGroups pushing")
|
||||
reply, err = l.cometClient.DelGroups(context.WithValue(c, xkey.DefaultKey, convertAddress(server)), &comet.DelGroupsReq{Gid: appGids(appId, gids)})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("appId", appId).Strs("groups", gids).Str("server", server).Msg("DelGroups l.cometClient.DelGroups")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// getServerByMids 通过 appid 和 mids 找到所在的 comet servers
|
||||
func (l *Logic) getServerByMids(c context.Context, appId string, mids []string) (map[string][]string, error) {
|
||||
ress, _, err := l.dao.KeysByMids(c, appId, mids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
server2keys := make(map[string][]string)
|
||||
for k, s := range ress {
|
||||
server2keys[s] = append(server2keys[s], k)
|
||||
}
|
||||
|
||||
return server2keys, nil
|
||||
}
|
||||
|
||||
// getServerByKeys 通过 keys 找到所在的 comet servers
|
||||
func (l *Logic) getServerByKeys(c context.Context, keys []string) (map[string][]string, error) {
|
||||
server2keys := make(map[string][]string)
|
||||
for _, key := range keys {
|
||||
server, _ := l.dao.GetServer(c, key)
|
||||
server2keys[server] = append(server2keys[server], key)
|
||||
}
|
||||
return server2keys, nil
|
||||
}
|
||||
|
||||
func appGid(appId, gid string) string {
|
||||
return fmt.Sprintf("%s_%s", appId, gid)
|
||||
}
|
||||
|
||||
func appGids(appId string, gids []string) []string {
|
||||
res := make([]string, 0, len(gids))
|
||||
for _, g := range gids {
|
||||
res = append(res, appGid(appId, g))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func convertAddress(addr string) string {
|
||||
// todo
|
||||
if len(addr) == 0 {
|
||||
return addr
|
||||
}
|
||||
switch addr[0] {
|
||||
case 'g':
|
||||
return addr[7:]
|
||||
default:
|
||||
return addr
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user