1、配置文件使用个数进行配置,而不是使用数组。2、errorgroups模块使用参数列表进行注册。3、程序结束时defer关闭数据库。4、http模块使用syncpool来提高性能。5、httproute模块使用接口进行通信管道的传递。6、中间件增加回复数据的保存。7、rpc尽量支持可以使用unix配置。8、rpcserver可以自适应jsonrpc或者gobrpc。9、swarm模块进行重大调整,修改调度写成等待工作协程结束之后再结束(会发生死锁导致程序无法结束),修改调度协程无法执行defer函数问题,原因是main结束太快导致调度协程的defer来不及执行,使用函数选项来注入log。10、unis业务进行重大调整。11、所有皆采用面向对象的方式。

This commit is contained in:
redhat 2025-06-03 17:35:50 +08:00
parent a297dfbb0f
commit 5a24eff7f1
30 changed files with 912 additions and 318 deletions

View File

@ -2,7 +2,7 @@ base:
name: "avcnet_dash" name: "avcnet_dash"
port: 8080 port: 8080
mode: "dev" mode: "dev"
version: "v0.0.1" version: "v0.1.0"
log: log:
level: "debug" level: "debug"
@ -14,7 +14,7 @@ log:
database: database:
# sqlite只需要指定db_name即可 # sqlite只需要指定db_name即可
type: "sqlite" type: "sqlite"
db_name: "/tmp/data/sqlite/avcnet.db" # 如果是sqlite需要指定完整路径和文件名称 db_name: "/home/zs/tftpboot/cache/data/sqlite/avcnet.db" # 如果是sqlite需要指定完整路径和文件名称
# 其他远程数据库需要指定下面的内容 # 其他远程数据库需要指定下面的内容
user: "root" user: "root"
password: "password" password: "password"
@ -25,8 +25,12 @@ database:
unis: unis:
rpc: rpc:
type: "json" type: "json"
network: "tcp"
host: "" host: ""
port: 5501 base_port: 5500
httpc:
clients: 5
instances: 2
# 使用令牌桶限流 # 使用令牌桶限流
rate: rate:

View File

@ -1,23 +1,25 @@
package unisc package unisc
import ( import (
"dashboard/dao/dadis/unisd"
"dashboard/models" "dashboard/models"
"dashboard/utils"
"net/http" "net/http"
"reflect" "sync"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
type httpHandle struct { type httpHandle struct {
httpC chan *models.UnisHttpRequest httpC []chan *models.UnisHttpRequest
pool sync.Pool
} }
func newhttpHandle(httpc chan *models.UnisHttpRequest) *httpHandle { func newhttpHandle(httpc []chan *models.UnisHttpRequest) *httpHandle {
res := new(httpHandle) res := new(httpHandle)
res.httpC = httpc res.httpC = httpc
res.pool.New = func() any { return new(models.UnisHttpRequest) }
return res return res
} }
@ -29,44 +31,59 @@ func httpSendWithExpire(httpc chan *models.UnisHttpRequest, data *models.UnisHtt
select { select {
case httpc <- data: case httpc <- data:
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
return nil, models.ErrorTimeOut return nil, models.ErrorSendTimeOut
} }
select { select {
case resp := <-resc: case resp := <-resc:
return resp, nil return resp, nil
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
return nil, models.ErrorTimeOut return nil, models.ErrorReciveTimeOut
} }
} }
func (u *httpHandle) stationConfig(c *gin.Context) error { func (u *httpHandle) stationConfig(c *gin.Context) error {
log, _ := utils.GetLogFromContext(c)
config := new(models.StationConfigParams) config := new(models.StationConfigParams)
if err := c.ShouldBindJSON(config); err != nil { if err := c.ShouldBindJSON(config); err != nil {
log.Sugar().Errorf("stationConfig bind json err: %v", err)
return err return err
} }
if !config.StationConfig.ConfigType { channel := c.GetInt(models.GinContextChannel)
res, ok := unisd.UnisDataGet(string(unisd.DadisKey_UnisStationInfo)) if channel > len(u.httpC)-1 {
if ok { log.Sugar().Errorf("stationConfig channel err: %d", channel)
oldCfg := res.(*models.StationConfigParams) return models.ErrorParamsErr
oldCfg.StationConfig.ConfigType = config.StationConfig.ConfigType
if reflect.DeepEqual(config, oldCfg) {
c.JSON(http.StatusOK, models.UnisHttpResponseOk)
return nil
}
}
} }
req := &models.UnisHttpRequest{ // if !config.StationConfig.ConfigType {
Id: models.UnisHttpUrl(c.Request.URL.String()).GetMsgId(), // res, ok := unisd.UnisDataGet(unisd.DadisKey_UnisStationInfo.KeyWithChannel(channel))
Msg: config, // if ok {
} // oldCfg := res.(*models.StationConfigParams)
resp, err := httpSendWithExpire(u.httpC, req) // oldCfg.StationConfig.ConfigType = config.StationConfig.ConfigType
// if reflect.DeepEqual(config, oldCfg) {
// log.Sugar().Infof("stationConfig is same")
// c.JSON(http.StatusOK, models.UnisHttpResponseOk)
// return nil
// }
// }
// }
req := u.pool.Get().(*models.UnisHttpRequest)
req.Id = models.UnisHttpUrl(c.Request.URL.String()).GetMsgId()
req.Msg = config
// req := &models.UnisHttpRequest{
// Id: models.UnisHttpUrl(c.Request.URL.String()).GetMsgId(),
// Msg: config,
// }
resp, err := httpSendWithExpire(u.httpC[channel], req)
if err != nil { if err != nil {
log.Sugar().Errorf("stationConfig send or recive err: %v", err)
return err return err
} }

View File

@ -10,6 +10,7 @@ import (
"io" "io"
"net/http" "net/http"
"strconv" "strconv"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -19,20 +20,29 @@ type HttpRoute struct {
middleWare *middleWare middleWare *middleWare
} }
func NewHttpRoute(httpc chan *models.UnisHttpRequest) *HttpRoute { type UnisHttpChanneler interface {
GetHttpChannel() chan *models.UnisHttpRequest
}
func NewHttpRoute(httpc ...UnisHttpChanneler) *HttpRoute {
res := new(HttpRoute) res := new(HttpRoute)
res.httpHandle = newhttpHandle(httpc) var httpC []chan *models.UnisHttpRequest
for _, cha := range httpc {
httpC = append(httpC, cha.GetHttpChannel())
}
res.httpHandle = newhttpHandle(httpC)
res.middleWare = newmiddleWare() res.middleWare = newmiddleWare()
return res return res
} }
func (u *HttpRoute) AddRoute(r *gin.Engine) { func (u *HttpRoute) AddRoute(r *gin.Engine) {
unisr := r.Group("/api/unis") unisr := r.Group(models.UnisHttpUrlPrefix)
unisr.Use(routes.ErrWapper(u.middleWare.GinCheckServerId), routes.ErrWapper(u.middleWare.GinStoreRequest)) unisr.Use(routes.ErrWapper(u.middleWare.ginCheckServerId), routes.ErrWapper(u.middleWare.ginStoreRequest))
{ {
unisr.POST("/config/v1/add", routes.ErrWapper(u.httpHandle.stationConfig)) unisr.POST(models.UNIS_HTTP_URL_CONFIG_ADD.Url(), routes.ErrWapper(u.httpHandle.stationConfig))
} }
} }
@ -43,7 +53,7 @@ func newmiddleWare() *middleWare {
return new(middleWare) return new(middleWare)
} }
func (m *middleWare) GinCheckServerId(c *gin.Context) error { func (m *middleWare) ginCheckServerId(c *gin.Context) error {
serverId := c.GetHeader("serverId") serverId := c.GetHeader("serverId")
if serverId != serverId { if serverId != serverId {
@ -71,14 +81,30 @@ func (m *middleWare) GinCheckServerId(c *gin.Context) error {
return nil return nil
} }
func (m *middleWare) GinStoreRequest(c *gin.Context) (err error) { // bodyLogWriter 自定义响应写入器,用于捕获响应体
type bodyLogWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
// Write 实现写入接口,同时写入缓冲区和原始响应
func (w *bodyLogWriter) Write(b []byte) (int, error) {
w.body.Write(b)
return w.ResponseWriter.Write(b)
}
// WriteString 实现字符串写入接口(优化性能)
func (w *bodyLogWriter) WriteString(s string) (int, error) {
w.body.WriteString(s)
return w.ResponseWriter.WriteString(s)
}
func (m *middleWare) ginStoreRequest(c *gin.Context) (err error) {
defer func() { defer func() {
if err != nil { if err != nil {
c.Abort() c.Abort()
return return
} }
c.Next()
}() }()
log, _ := utils.GetLogFromContext(c) log, _ := utils.GetLogFromContext(c)
@ -87,18 +113,39 @@ func (m *middleWare) GinStoreRequest(c *gin.Context) (err error) {
oldConf, _err := sqldb.ResFulDataGet(c.Request.Method, c.Request.URL.String(), channel) oldConf, _err := sqldb.ResFulDataGet(c.Request.Method, c.Request.URL.String(), channel)
if _err != nil { if _err != nil {
err = _err err = _err
return
} }
bodyBytes, _err := io.ReadAll(c.Request.Body) bodyBytes, _err := io.ReadAll(c.Request.Body)
if _err != nil { if _err != nil {
err = _err err = _err
return
} }
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
// 创建自定义响应写入器
blw := &bodyLogWriter{
body: bytes.NewBufferString(""),
ResponseWriter: c.Writer,
}
c.Writer = blw
c.Next()
// 获取响应信息
// statusCode := c.Writer.Status()
responseBody := blw.body.String()
// // 安全日志记录:限制大响应体
// logBody := responseBody
// if len(responseBody) > 1000 {
// logBody = responseBody[:1000] + "...[TRUNCATED]"
// }
if oldConf != string(bodyBytes) { if oldConf != string(bodyBytes) {
log.Sugar().Info("The resful request is not equel local store") log.Sugar().Info("The resful request is not equel local store so will save to database...")
if _err := sqldb.ResFulDataStore(c.Request.Method, c.Request.URL.String(), string(bodyBytes), channel); err != nil { if _err := sqldb.ResFulDataStore(c.Request.Method, c.Request.URL.String(), responseBody, string(bodyBytes), channel); _err != nil {
err = _err err = _err
} }
} }
@ -106,14 +153,14 @@ func (m *middleWare) GinStoreRequest(c *gin.Context) (err error) {
return nil return nil
} }
func (m *middleWare) GinWithUnisObject(unis *uniss.UnisStation) gin.HandlerFunc { func (m *middleWare) ginWithUnisObject(unis *uniss.UnisStation) gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
c.Set(models.GinContextUnis, unis) c.Set(models.GinContextUnis, unis)
c.Next() c.Next()
} }
} }
func (m *middleWare) GetUnisObjectFromContext(c *gin.Context) (*uniss.UnisStation, error) { func (m *middleWare) getUnisObjectFromContext(c *gin.Context) (*uniss.UnisStation, error) {
res, ok := c.Get(models.GinContextUnis) res, ok := c.Get(models.GinContextUnis)
if !ok { if !ok {
return nil, models.ErrorInvalidData return nil, models.ErrorInvalidData
@ -126,3 +173,10 @@ func (m *middleWare) GetUnisObjectFromContext(c *gin.Context) (*uniss.UnisStatio
return unis, nil return unis, nil
} }
func (m *middleWare) ginWithExpireTime(expire time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set(models.GinContextExpire, expire)
c.Next()
}
}

View File

@ -1,8 +1,14 @@
package unisd package unisd
import "fmt"
type DadisKey string type DadisKey string
func (d DadisKey) KeyWithChannel(channel int) string {
return fmt.Sprintf("%d:%s", channel, string(d))
}
const ( const (
DadisKey_UnisSystemInfo DadisKey = "UnisSystemInfo" DadisKey_UnisSystemInfo DadisKey = "UnisSystemInfo"
DadisKey_UnisStationInfo DadisKey = "UnisStationInfo" DadisKey_UnisStationInfo DadisKey = "UnisStationInfo"
) )

View File

@ -6,13 +6,14 @@ const (
createUserSql = `CREATE TABLE IF NOT EXISTS db_unis_aisub (userid TEXT NOT NULL,is_sub INTEGER,CONSTRAINT db_unis_aisub_pk PRIMARY KEY (userid));` createUserSql = `CREATE TABLE IF NOT EXISTS db_unis_aisub (userid TEXT NOT NULL,is_sub INTEGER,CONSTRAINT db_unis_aisub_pk PRIMARY KEY (userid));`
createResStoreSql = `CREATE TABLE IF NOT EXISTS db_unis_res_store ( createResStoreSql = `CREATE TABLE IF NOT EXISTS db_unis_res_store (
key TEXT NOT NULL, url TEXT NOT NULL,
value TEXT, body TEXT,
response TEXT,
channel INTEGER, channel INTEGER,
methord TEXT, methord TEXT,
created_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')), created_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')),
updated_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')), updated_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')),
CONSTRAINT db_unis_res_pk PRIMARY KEY (key,channel,methord) CONSTRAINT db_unis_res_pk PRIMARY KEY (url,channel,methord)
); );
CREATE TRIGGER IF NOT EXISTS trigger_db_unis_res_store_updated_at AFTER UPDATE ON db_unis_res_store CREATE TRIGGER IF NOT EXISTS trigger_db_unis_res_store_updated_at AFTER UPDATE ON db_unis_res_store

View File

@ -5,10 +5,10 @@ import (
"errors" "errors"
) )
func ResFulDataStore(methord, key, value string, channel int) error { func ResFulDataStore(methord, url, response, body string, channel int) error {
sqlStr := `INSERT OR REPLACE INTO db_unis_res_store(key,value,channel,methord) VALUES(?,?,?,?)` sqlStr := `INSERT OR REPLACE INTO db_unis_res_store(url,body,channel,methord,response) VALUES(?,?,?,?,?)`
res, err := db.Exec(sqlStr, key, value, channel,methord) res, err := db.Exec(sqlStr, url, body, channel, methord, response)
if err != nil { if err != nil {
return err return err
} }
@ -25,11 +25,11 @@ func ResFulDataStore(methord, key, value string, channel int) error {
return nil return nil
} }
func ResFulDataGet(methord, key string, channel int) (string, error) { func ResFulDataGet(methord, url string, channel int) (string, error) {
sqlStr := `SELECT value FROM db_unis_res_store WHERE key=? AND channel=? AND methord=?` sqlStr := `SELECT body FROM db_unis_res_store WHERE url=? AND channel=? AND methord=?`
var res string var res string
if err := db.Get(&res, sqlStr, key, channel, methord); err != nil { if err := db.Get(&res, sqlStr, url, channel, methord); err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
return "", nil return "", nil
} }

38
main.go
View File

@ -11,14 +11,25 @@ import (
"dashboard/settings" "dashboard/settings"
"flag" "flag"
"fmt" "fmt"
"github.com/fsnotify/fsnotify"
) )
var config = flag.String("f", "./config/config.yaml", "config file path") var config = flag.String("f", "./config/config.yaml", "config file path")
func callBack(e fsnotify.Event) {
// os.Exit(0)
// fmt.Println(e, os.Args)
// out, err := exec.Command("go", "run", os.Args[0]).Output()
// fmt.Println(out, err)
}
func main() { func main() {
flag.Parse() flag.Parse()
sets := settings.New(settings.WithName(*config)) sets := settings.New(settings.WithName(*config), settings.WithCallBack(callBack))
log, err := logger.New( log, err := logger.New(
logger.WithFileName(sets.LogConfig.Filename), logger.WithFileName(sets.LogConfig.Filename),
@ -36,29 +47,42 @@ func main() {
_ = log.Sync() _ = log.Sync()
}() }()
log.Info("Settings and log init ok") log.Info("Settings and log init ok:)")
db, err := sqldb.NewDb(sets.SqlConfig) db, err := sqldb.NewDb(sets.SqlConfig)
if err != nil { if err != nil {
log.Sugar().Panicf("New db error: %v", err) log.Sugar().Panicf("New db error: %v", err)
} }
defer func() {
_ = db.GetDb().Close()
}()
err = sqldb.SqlDbInit(log, db) err = sqldb.SqlDbInit(log, db)
if err != nil { if err != nil {
log.Sugar().Panicf("New db error: %v", err) log.Sugar().Panicf("New db error: %v", err)
} }
errwg := errgroups.NewErrGroup()
// r := routes.Setup(log, *sets.RateLimitConfig, *sets.JwtConfig) // r := routes.Setup(log, *sets.RateLimitConfig, *sets.JwtConfig)
// listenAndServe(fmt.Sprintf(":%d", sets.BaseConfig.Port), r, log) // listenAndServe(fmt.Sprintf(":%d", sets.BaseConfig.Port), r, log)
sunis := uniss.NewUnis(log, sets.UnisConfig) var sunisa []errgroups.FuncWithErr
var route []unisc.UnisHttpChanneler
for index := range sets.UnisConfig.Instances {
sets.UnisConfig.Instances = index
unis, err := uniss.NewUnis(log, sets.UnisConfig)
if err != nil {
panic(err)
}
sunisa = append(sunisa, unis)
route = append(route, unis)
}
errwg := errgroups.NewErrGroup()
errwg.Add(routes.NewRouter(fmt.Sprintf(":%d", sets.BaseConfig.Port), errwg.Add(routes.NewRouter(fmt.Sprintf(":%d", sets.BaseConfig.Port),
log, *sets.RateLimitConfig, *sets.JwtConfig, log, *sets.RateLimitConfig, *sets.JwtConfig,
unisc.NewHttpRoute(sunis.GetHttpChannel()))) unisc.NewHttpRoute(route...)))
errwg.Add(sunis) errwg.Add(sunisa...)
log.Sugar().Fatalln(errwg.Run(context.Background())) log.Sugar().Fatalln(errwg.Run(context.Background()))
} }

View File

@ -10,6 +10,7 @@ const (
GinContextChannel = "channel" GinContextChannel = "channel"
GinContextServerId = "serverid" GinContextServerId = "serverid"
GinContextUnis = "unis" GinContextUnis = "unis"
GinContextExpire = "expire"
) )
const ( const (
@ -18,10 +19,12 @@ const (
) )
var ( var (
ErrorInvalidData = errors.New("no such value") ErrorInvalidData = errors.New("no such value")
ErrorPasswordErr = errors.New("user or password invalid") ErrorPasswordErr = errors.New("user or password invalid")
ErrorSqlInitErr = errors.New("database init err") ErrorSqlInitErr = errors.New("database init err")
ErrorTimeOut = errors.New("time out") ErrorSendTimeOut = errors.New("send time out")
ErrorReciveTimeOut = errors.New("recive time out")
ErrorParamsErr = errors.New("invalid params")
) )
const ( const (

View File

@ -1,9 +1,12 @@
package models package models
import "strings"
type UnisHttpRequest struct { type UnisHttpRequest struct {
ResC chan *UnisHttpResponse ResC chan *UnisHttpResponse
Id string Channel int
Msg interface{} Id string
Msg interface{}
} }
type UnisHttpResponse struct { type UnisHttpResponse struct {
@ -12,8 +15,28 @@ type UnisHttpResponse struct {
Data interface{} Data interface{}
} }
type UnisHttpClientRequest struct {
Url string
Methord string
Id string
Msg interface{}
}
type UnisHttpClientResponse struct {
Url string
Methord string
Id string
Msg interface{}
}
type UnisHttpUrl string type UnisHttpUrl string
const UnisHttpUrlPrefix = "/api/unis"
func (u UnisHttpUrl) Url() string {
return strings.TrimPrefix(string(u), UnisHttpUrlPrefix)
}
const ( const (
UNIS_HTTP_URL_CONFIG_ADD UnisHttpUrl = "/api/unis/config/v1/add" UNIS_HTTP_URL_CONFIG_ADD UnisHttpUrl = "/api/unis/config/v1/add"
) )

View File

@ -2,22 +2,22 @@ package models
import "fmt" import "fmt"
const rpcNamePrefix = "UnisRpcService" const rpcNamePrefix = "RpcServerStub"
type UnisRpcMethod string type UnisRpcMethod string
func (m UnisRpcMethod)Methord()string{ func (m UnisRpcMethod) Methord() string {
return fmt.Sprintf("%s.%s",rpcNamePrefix,string(m)) return fmt.Sprintf("%s.%s", rpcNamePrefix, string(m))
} }
const( const (
UnisStationConfig UnisRpcMethod = "Config" UnisStationConfig UnisRpcMethod = "Config"
) )
type UnisRpcRequest struct{ type UnisRpcRequest struct {
Id string Id string
} }
type UnisRpcResponse struct{ type UnisRpcResponse struct {
Id string Id string
} }

View File

@ -10,7 +10,7 @@ import (
type Dadis struct { type Dadis struct {
mu sync.Mutex mu sync.Mutex
store map[string]*item store map[string]*item
observe *observe.AsyncEventBus observe *observe.SyncEventBus
} }
type item struct { type item struct {
@ -21,7 +21,7 @@ type item struct {
func NewDadis() *Dadis { func NewDadis() *Dadis {
return &Dadis{ return &Dadis{
store: make(map[string]*item), store: make(map[string]*item),
observe: observe.NewAsyncEventBus(), observe: observe.NewSyncEventBus(),
} }
} }

View File

@ -3,9 +3,9 @@ package errgroups
import ( import (
"context" "context"
"dashboard/utils" "dashboard/utils"
"fmt"
"sync" "sync"
"go.uber.org/zap"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
@ -17,6 +17,7 @@ type ErrGroupFunc struct {
type FuncWithErrFunc func(context.Context) error type FuncWithErrFunc func(context.Context) error
// 注意使用func时如果想要对数组对象执行多个函数不可以使用此种方法因为函数名都是一样的map里面会被替换。此种场景需要使用接口的方式。
func NewErrGroupFunc() *ErrGroupFunc { func NewErrGroupFunc() *ErrGroupFunc {
return &ErrGroupFunc{ return &ErrGroupFunc{
funs: make(map[string]FuncWithErrFunc), funs: make(map[string]FuncWithErrFunc),
@ -33,8 +34,8 @@ func (e *ErrGroupFunc) Run(ctx context.Context) error {
fn := fn fn := fn
name := name name := name
e.wg.Go(func() error { e.wg.Go(func() error {
defer fmt.Printf("func: %s stop\n", name) defer zap.L().Sugar().Warnf("func: %s stop", name)
fmt.Printf("func: %s runing...\n", name) zap.L().Sugar().Infof("func: %s runing...", name)
return fn(ctx) return fn(ctx)
}) })
} }
@ -46,22 +47,24 @@ func (e *ErrGroupFunc) Run(ctx context.Context) error {
return nil return nil
} }
func (e *ErrGroupFunc) Add(fn FuncWithErrFunc) { func (e *ErrGroupFunc) Add(fn ...FuncWithErrFunc) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
fnStr := utils.GetFuncName(fn) for _, f := range fn {
fnStr := utils.GetFuncName(f)
e.funs[fnStr] = fn e.funs[fnStr] = f
}
} }
func (e *ErrGroupFunc) Del(fn FuncWithErrFunc) { func (e *ErrGroupFunc) Del(fn ...FuncWithErrFunc) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
fnStr := utils.GetFuncName(fn) for _, f := range fn {
fnStr := utils.GetFuncName(f)
delete(e.funs, fnStr) delete(e.funs, fnStr)
}
} }
type ErrGroup struct { type ErrGroup struct {
@ -87,8 +90,11 @@ func (e *ErrGroup) Run(ctx context.Context) error {
e.wg, ctx = errgroup.WithContext(ctx) e.wg, ctx = errgroup.WithContext(ctx)
for fn := range e.funs { for fn := range e.funs {
fn := fn fn := fn // shadow
name := utils.GetInterfaceName(fn)
e.wg.Go(func() error { e.wg.Go(func() error {
defer zap.L().Sugar().Warnf("Object: %s stop", name)
zap.L().Sugar().Infof("Object: %s runing...", name)
return fn.Run(ctx) return fn.Run(ctx)
}) })
} }
@ -100,16 +106,20 @@ func (e *ErrGroup) Run(ctx context.Context) error {
return nil return nil
} }
func (e *ErrGroup) Add(fn FuncWithErr) { func (e *ErrGroup) Add(fn ...FuncWithErr) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
e.funs[fn] = struct{}{} for _, f := range fn {
e.funs[f] = struct{}{}
}
} }
func (e *ErrGroup) Del(fn FuncWithErr) { func (e *ErrGroup) Del(fn ...FuncWithErr) {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
delete(e.funs, fn) for _, f := range fn {
delete(e.funs, f)
}
} }

26
pkg/rpcsup/client.go Normal file
View File

@ -0,0 +1,26 @@
package rpcsup
import (
"errors"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"strings"
)
func RpcClient(conf *RpcConfig) (*rpc.Client, error) {
if strings.Contains(conf.Typec, "json") {
dial, err := net.Dial(conf.Network, conf.Address)
if err != nil {
return nil, err
}
return jsonrpc.NewClient(dial), nil
}
if strings.Contains(conf.Typec, "grpc") {
return nil, errors.New("currently not supported")
}
return rpc.Dial(conf.Network, conf.Address)
}

View File

@ -1,74 +0,0 @@
package rpcsup
import (
"context"
"dashboard/logger"
"errors"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"golang.org/x/sync/errgroup"
)
func JsonServer(ctx context.Context, log *logger.Logger, address string, service ...interface{}) error {
for _, re := range service {
if err := rpc.Register(re); err != nil {
log.Sugar().Error(err)
return err
}
}
listen, err := net.Listen("tcp", address)
if err != nil {
log.Sugar().Error(err)
return err
}
log.Sugar().Infof("Rpc server listen on: %s", address)
wg, ctxx := errgroup.WithContext(ctx)
wg.Go(func() error {
for {
accept, err := listen.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
log.Sugar().Error(err)
break
}
log.Sugar().Error(err)
continue
}
go jsonrpc.ServeConn(accept)
}
return err
})
wg.Go(func() error {
<-ctxx.Done()
log.Sugar().Errorf("Unis Rpc Server cancel by ctx")
listen.Close()
return ctxx.Err()
})
if err := wg.Wait(); err != nil {
return err
}
return nil
}
func JsonClient(log *logger.Logger, address string) (*rpc.Client, error) {
dial, err := net.Dial("tcp", address)
if err != nil {
log.Sugar().Error(err)
return nil, err
}
return jsonrpc.NewClient(dial), nil
}

103
pkg/rpcsup/rpcsup.go Normal file
View File

@ -0,0 +1,103 @@
package rpcsup
import (
"context"
"errors"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"strings"
"golang.org/x/sync/errgroup"
)
type RpcServicer interface {
Name() string
}
type RpcService struct {
rpc *rpc.Server
listen net.Listener
handler func(net.Conn)
}
type RpcConfig struct {
Typec string
Network string
Address string
}
func NewRpcService(conf *RpcConfig) (res *RpcService, err error) {
res = new(RpcService)
res.rpc = rpc.NewServer()
res.listen, err = net.Listen(conf.Network, conf.Address)
if err != nil {
return
}
if strings.Contains(conf.Typec, "json") {
res.handler = func(c net.Conn) {
res.rpc.ServeCodec(jsonrpc.NewServerCodec(c))
}
return
}
if strings.Contains(conf.Typec, "grpc") {
return nil, errors.New("currently not supported")
}
res.handler = func(c net.Conn) {
res.rpc.ServeConn(c)
}
return
}
func (r *RpcService) Register(service ...interface{}) error {
for _, ser := range service {
if nser, ok := ser.(RpcServicer); ok {
if err := r.rpc.RegisterName(nser.Name(), nser); err != nil {
return err
}
continue
}
if err := r.rpc.Register(ser); err != nil {
return err
}
}
return nil
}
func (r *RpcService) Run(ctx context.Context) error {
wg, ctxx := errgroup.WithContext(ctx)
wg.Go(func() error {
for {
accept, err := r.listen.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
return err
}
continue
}
go r.handler(accept)
}
})
wg.Go(func() error {
<-ctxx.Done()
r.listen.Close()
return ctxx.Err()
})
if err := wg.Wait(); err != nil {
return err
}
return nil
}

22
pkg/swarm/option.go Normal file
View File

@ -0,0 +1,22 @@
package swarm
import "log"
type options struct {
log *log.Logger
}
type Option func(*options)
func WithLog(log *log.Logger) Option {
return func(o *options) {
o.log = log
}
}
func(o *options)repire(){
if o.log == nil{
o.log = log.Default()
}
}

69
pkg/swarm/scheduler.go Normal file
View File

@ -0,0 +1,69 @@
package swarm
import (
"context"
"log"
)
type defaultScheduler[T any] struct {
worker chan chan T
request chan T
log *log.Logger
calFn context.CancelFunc
ctx context.Context
}
func newdefaultScheduler[T any](log *log.Logger) *defaultScheduler[T] {
res := new(defaultScheduler[T])
res.worker = make(chan chan T)
res.request = make(chan T)
res.log = log
res.ctx, res.calFn = context.WithCancel(context.TODO())
return res
}
func (s *defaultScheduler[T]) Submit(req T) {
s.request <- req
}
func (s *defaultScheduler[T]) Done(worker chan T) {
s.worker <- worker
}
func (s *defaultScheduler[T]) GenChannel() chan T {
return make(chan T)
}
func (s *defaultScheduler[T]) Stop() {
s.calFn()
}
func (s *defaultScheduler[T]) Run() error {
var workers []chan T
var requests []T
for {
var work chan T
var req T
if len(workers) > 0 && len(requests) > 0 {
work = workers[0]
req = requests[0]
}
select {
case <-s.ctx.Done():
s.log.Printf("%sScheduler: %p down...", logPrefix, s)
return s.ctx.Err()
case w := <-s.worker:
workers = append(workers, w)
case r := <-s.request:
requests = append(requests, r)
case work <- req:
workers = workers[1:]
requests = requests[1:]
}
}
}

117
pkg/swarm/swarm.go Normal file
View File

@ -0,0 +1,117 @@
package swarm
import (
"context"
"dashboard/pkg/errgroups"
"log"
"golang.org/x/sync/errgroup"
)
const logPrefix = "[swarm] "
type Swarm[T any] struct {
scheduler Scheduler[T]
bees []*beeJob[T]
opts options
}
func NewSwarm[T any](num int, work func(T) error, opts ...Option) *Swarm[T] {
res := new(Swarm[T])
for _, o := range opts {
o(&res.opts)
}
res.opts.repire()
res.scheduler = newdefaultScheduler[T](res.opts.log)
for index := range num {
res.bees = append(res.bees, &beeJob[T]{
done: func(c chan T) { res.scheduler.Done(c) },
wc: res.scheduler.GenChannel(),
do: work,
index: index,
log: res.opts.log,
})
}
res.opts.log.Printf("%sStart bees number: %d.", logPrefix, len(res.bees))
return res
}
type beeJob[T any] struct {
done func(chan T)
wc chan T
do func(T) error
index int
log *log.Logger
}
func (b *beeJob[T]) Run(ctx context.Context) error {
for {
b.done(b.wc)
select {
case <-ctx.Done():
b.log.Printf("Bee num: %d,down\n", b.index)
return ctx.Err()
case req := <-b.wc:
if err := b.do(req); err != nil {
b.log.Printf("%sBee num: %d, do the work error: %v", logPrefix, b.index, err)
continue
}
b.log.Printf("%sBee num: %d, do the work success:)", logPrefix, b.index)
}
}
}
type Scheduler[T any] interface {
Run() error
Submit(T)
Done(chan T)
GenChannel() chan T
Stop()
}
func (s *Swarm[T]) Submit(sub T) {
s.scheduler.Submit(sub)
}
// implement FuncWithErr interface
func (s *Swarm[T]) Run(ctx context.Context) error {
wgs, ctx := errgroup.WithContext(ctx)
wgs.Go(func() error {
defer s.scheduler.Stop()
ewgs := errgroups.NewErrGroup()
// // 可以保证bee结束但是不能保证scheduler正常退出
// schectx, cancel := context.WithCancel(context.TODO())
// defer cancel()
// go s.scheduler.Run(schectx)
// ewgs.Add(s.scheduler) // 结束的比bee早导致bee可能会被永久阻塞导致进程不能退出。
for _, bee := range s.bees {
ewgs.Add(bee)
}
return ewgs.Run(ctx)
})
wgs.Go(func() error {
return s.scheduler.Run()
})
if err := wgs.Wait(); err != nil {
return err
}
return nil
}

32
pkg/swarm/swarm_test.go Normal file
View File

@ -0,0 +1,32 @@
package swarm
import (
"context"
"fmt"
"testing"
"time"
)
func testwork(req string) error {
fmt.Println(req)
return nil
}
func Test_swarm(t *testing.T) {
swarm := NewSwarm(10, testwork)
for range 10 {
go func() {
for {
swarm.scheduler.Submit("nihao")
time.Sleep(time.Second)
}
}()
}
ctx, calFn := context.WithTimeout(context.Background(), 5*time.Second)
defer calFn()
swarm.Run(ctx)
}

View File

@ -4,21 +4,24 @@ import (
"dashboard/dao/dadis/unisd" "dashboard/dao/dadis/unisd"
"dashboard/models" "dashboard/models"
"fmt" "fmt"
"net/http"
) )
type commonService struct { type commonService struct {
rpcClients *rpcClients comm *communicateService
} }
func newcommonService(http *httpHandle) *commonService { func newcommonService(comm *communicateService) *commonService {
res := new(commonService) res := new(commonService)
http.pushHandle(string(models.UNIS_HTTP_ID_CONFIG_ADD), res.stationConfig) res.comm = comm
res.comm.httpServerHandler.pushHandle(string(models.UNIS_HTTP_ID_CONFIG_ADD), res.stationConfig)
return res return res
} }
func (c *commonService) stationConfig(reqest *models.UnisHttpRequest) (*models.UnisHttpResponse, error) { func (c *commonService) stationConfig(reqest *models.UnisHttpRequest, respons *models.UnisHttpResponse) error {
req := reqest.Msg.(*models.StationConfigParams) req := reqest.Msg.(*models.StationConfigParams)
fmt.Println(req) fmt.Println(req)
@ -32,16 +35,23 @@ func (c *commonService) stationConfig(reqest *models.UnisHttpRequest) (*models.U
addres = append(addres, add) addres = append(addres, add)
} }
c.rpcClients.flushRpcClients(addres) c.comm.rpcClientStub.flushRpcClients(addres)
fmt.Println(c.rpcClients.getConfig(addres[0].id, models.UnisRpcRequest{Id: "zhangshuo"})) fmt.Println(c.comm.rpcClientStub.getConfig(addres[0].id, models.UnisRpcRequest{Id: "zhangshuo"}))
res := &models.UnisHttpResponse{ // res := &models.UnisHttpResponse{
Code: int(models.CodeSuccess), // Code: int(models.CodeSuccess),
Msg: "config ok", // Msg: "config ok",
} // }
respons.Code = int(models.CodeSuccess)
respons.Msg = "config ok"
unisd.UnisDataSet(string(unisd.DadisKey_UnisStationInfo), req, 0) unisd.UnisDataSet(unisd.DadisKey_UnisStationInfo.KeyWithChannel(reqest.Channel), req, 0)
return res, nil c.comm.httpClientHandler.curl(&models.UnisHttpClientRequest{
Url: "http://192.168.177.7:8080/api/unis/source-list/v1/update",
Methord: http.MethodGet,
})
return nil
} }

View File

@ -0,0 +1,54 @@
package uniss
import (
"context"
"dashboard/pkg/errgroups"
"dashboard/pkg/rpcsup"
"dashboard/settings"
"fmt"
)
type communicateService struct {
rpcClientStub *rpcClientStub
rpcService *rpcsup.RpcService
httpServerHandler *httpServerHandler
httpClientHandler *httpClientHandler
}
func newcommunicateService(conf *settings.UnisConfig) (res *communicateService, err error) {
res = new(communicateService)
var rpcConf = &rpcsup.RpcConfig{
Typec: conf.RpcConfig.Type,
Network: conf.RpcConfig.Network,
Address: fmt.Sprintf("%s:%d", conf.RpcConfig.Host, conf.RpcConfig.BasePort+conf.Instances)}
res.rpcService, err = rpcsup.NewRpcService(rpcConf)
if err != nil {
log.Sugar().Errorf("New rpc service error: %v", err)
return
}
log.Sugar().Infof("New rpc service ok type: %s, network: %s, address: %s", rpcConf.Typec, rpcConf.Network, rpcConf.Address)
err = res.rpcService.Register(newrpcServerStub())
if err != nil {
log.Sugar().Errorf("Rpc service register error: %v", err)
return
}
log.Sugar().Infof("Rpc service register all ok")
res.httpServerHandler = newhttpServerHandler()
res.rpcClientStub = newRpcClients(conf.RpcConfig)
res.httpClientHandler = newhttpClientHandle(conf.HttpClientConfig.Clients)
return
}
func (c *communicateService) Run(ctx context.Context) error {
ewgs := errgroups.NewErrGroup()
ewgs.Add(c.rpcService)
ewgs.Add(c.httpClientHandler.swarm)
return ewgs.Run(ctx)
}

View File

@ -0,0 +1,20 @@
package uniss
import (
"dashboard/pkg/dadis"
"dashboard/settings"
)
type dataCenterService struct {
conf *settings.UnisConfig
dataMap *dadis.Dadis
}
func newDataCenterService(conf *settings.UnisConfig) *dataCenterService {
res := new(dataCenterService)
res.conf = conf
res.dataMap = dadis.NewDadis()
return res
}

View File

@ -0,0 +1,72 @@
package uniss
import (
"bytes"
"dashboard/dao/sqldb"
"dashboard/models"
"dashboard/pkg/swarm"
"encoding/json"
"fmt"
"io"
"net/http"
"go.uber.org/zap"
)
type httpClientHandler struct {
swarm *swarm.Swarm[*models.UnisHttpClientRequest]
httpC chan *models.UnisHttpClientResponse
}
func newhttpClientHandle(clients int) *httpClientHandler {
res := new(httpClientHandler)
res.swarm = swarm.NewSwarm(clients, res.doRequest, swarm.WithLog(zap.NewStdLog(log.Logger)))
res.httpC = make(chan *models.UnisHttpClientResponse)
return res
}
func (c *httpClientHandler) curl(msg *models.UnisHttpClientRequest) {
c.swarm.Submit(msg)
}
func (c *httpClientHandler) doRequest(req *models.UnisHttpClientRequest) error {
body, err := json.Marshal(req.Msg)
fmt.Println(string(body), err)
reqs, err := http.NewRequest(req.Methord, req.Url, bytes.NewReader(body))
if err != nil {
fmt.Println(err)
return err
}
reqs.Header.Add("Content-type", "application/json;charset=utf-8")
client := http.Client{}
resp, err := client.Do(reqs)
if err != nil {
fmt.Println(err)
return err
}
defer resp.Body.Close()
msg, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if err := sqldb.ResFulDataStore(req.Methord, req.Url, string(body), string(msg), 0); err != nil {
fmt.Println(err)
return err
}
response := &models.UnisHttpClientResponse{
Id: req.Id,
Methord: req.Methord,
Msg: msg,
}
c.httpC <- response
return nil
}

View File

@ -1,66 +0,0 @@
package uniss
import (
"dashboard/models"
"sync"
)
type httpHandle struct {
httpC chan *models.UnisHttpRequest
mu sync.RWMutex
mapFn map[string]HttpHandler
}
type HttpHandler func(*models.UnisHttpRequest) (*models.UnisHttpResponse, error)
func newhttpHandle() *httpHandle {
res := new(httpHandle)
res.httpC = make(chan *models.UnisHttpRequest)
res.mapFn = make(map[string]HttpHandler)
return res
}
func (u *httpHandle) httpHandle(msg *models.UnisHttpRequest) {
var res *models.UnisHttpResponse
resC := msg.ResC
defer func() {
if resC != nil {
resC <- res
}
}()
fn, ok := u.getHandle(msg.Id)
if ok {
if re, err := fn(msg); err == nil {
res = re
}
}
}
func (u *httpHandle) pushHandle(key string, handle HttpHandler) {
u.mu.Lock()
defer u.mu.Unlock()
u.mapFn[key] = handle
}
func (u *httpHandle) delHandle(key string) {
u.mu.Lock()
defer u.mu.Unlock()
delete(u.mapFn, key)
}
func (u *httpHandle) getHandle(key string) (HttpHandler, bool) {
u.mu.RLock()
defer u.mu.RUnlock()
res, ok := u.mapFn[key]
if !ok {
return nil, false
}
return res, ok
}

View File

@ -0,0 +1,68 @@
package uniss
import (
"dashboard/models"
"sync"
)
type httpServerHandler struct {
httpC chan *models.UnisHttpRequest
mu sync.RWMutex
mapFn map[string]HttpServerHandlerFunc
pool sync.Pool
}
type HttpServerHandlerFunc func(*models.UnisHttpRequest, *models.UnisHttpResponse) error
func newhttpServerHandler() *httpServerHandler {
res := new(httpServerHandler)
res.httpC = make(chan *models.UnisHttpRequest)
res.mapFn = make(map[string]HttpServerHandlerFunc)
res.pool.New = func() any { return new(models.UnisHttpResponse) }
return res
}
func (u *httpServerHandler) httpHandle(msg *models.UnisHttpRequest) {
res := u.pool.Get().(*models.UnisHttpResponse)
resC := msg.ResC
defer func() {
if resC != nil {
resC <- res
}
}()
fn, ok := u.getHandle(msg.Id)
if ok {
if err := fn(msg, res); err == nil {
}
}
}
func (u *httpServerHandler) pushHandle(key string, handle HttpServerHandlerFunc) {
u.mu.Lock()
defer u.mu.Unlock()
u.mapFn[key] = handle
}
func (u *httpServerHandler) delHandle(key string) {
u.mu.Lock()
defer u.mu.Unlock()
delete(u.mapFn, key)
}
func (u *httpServerHandler) getHandle(key string) (HttpServerHandlerFunc, bool) {
u.mu.RLock()
defer u.mu.RUnlock()
res, ok := u.mapFn[key]
if !ok {
return nil, false
}
return res, ok
}

View File

@ -1,45 +1,54 @@
package uniss package uniss
// TODO
// 1.data center object 2.swarm stop after scheduler
import ( import (
"context" "context"
"dashboard/logger" "dashboard/logger"
"dashboard/models" "dashboard/models"
"dashboard/pkg/errgroups" "dashboard/pkg/errgroups"
"dashboard/settings" "dashboard/settings"
"fmt"
) )
var log *logger.Logger
type UnisStation struct { type UnisStation struct {
log *logger.Logger commonService *commonService
conf *settings.UnisConfig communicateService *communicateService
httpHandle *httpHandle dataCenterService *dataCenterService
commonService *commonService
} }
func NewUnis(log *logger.Logger, conf *settings.UnisConfig) *UnisStation { func NewUnis(_log *logger.Logger, conf *settings.UnisConfig) (res *UnisStation, err error) {
res := new(UnisStation) res = new(UnisStation)
log = _log
res.log = log res.dataCenterService = newDataCenterService(conf)
res.conf = conf res.communicateService, err = newcommunicateService(conf)
if err != nil {
return
}
res.httpHandle = newhttpHandle() res.commonService = newcommonService(res.communicateService)
res.commonService = newcommonService(res.httpHandle)
res.commonService.rpcClients = newRpcClients(log, conf.RpcConfig.Port)
return res return
} }
func (u *UnisStation) GetHttpChannel() chan *models.UnisHttpRequest { func (u *UnisStation) GetHttpChannel() chan *models.UnisHttpRequest {
return u.httpHandle.httpC return u.communicateService.httpServerHandler.httpC
} }
func (u *UnisStation) mesageHandle(ctx context.Context) error { func (u *UnisStation) mainthread(ctx context.Context) error {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
u.log.Error("Unis mesageHandle cancel by ctx") log.Error("Unis mesageHandle cancel by ctx")
return ctx.Err() return ctx.Err()
case httpMsg := <-u.httpHandle.httpC: case httpMsg := <-u.communicateService.httpServerHandler.httpC:
u.httpHandle.httpHandle(httpMsg) u.communicateService.httpServerHandler.httpHandle(httpMsg)
case httpc := <-u.communicateService.httpClientHandler.httpC:
fmt.Println(string(httpc.Msg.([]byte)))
// default: // default:
} }
@ -47,12 +56,10 @@ func (u *UnisStation) mesageHandle(ctx context.Context) error {
} }
func (u *UnisStation) Run(ctx context.Context) error { func (u *UnisStation) Run(ctx context.Context) error {
rpc := newUnisRpcServer(u.log, u.conf.RpcConfig)
ewgs := errgroups.NewErrGroupFunc() ewgs := errgroups.NewErrGroupFunc()
ewgs.Add(rpc.rpcListenAndServe) ewgs.Add(u.communicateService.Run)
ewgs.Add(u.mesageHandle) ewgs.Add(u.mainthread)
return ewgs.Run(ctx) return ewgs.Run(ctx)
} }

View File

@ -1,39 +1,38 @@
package uniss package uniss
import ( import (
"dashboard/logger"
"dashboard/models" "dashboard/models"
"dashboard/pkg/rpcsup" "dashboard/pkg/rpcsup"
"dashboard/settings"
"fmt" "fmt"
"net/rpc" "net/rpc"
"sync" "sync"
) )
type rpcClients struct { // Called by someone else
*logger.Logger type rpcClientStub struct {
mu sync.RWMutex mu sync.RWMutex
conf *settings.RpcConfig
rpcMapClients map[string]*rpc.Client rpcMapClients map[string]*rpc.Client
port int
} }
type rpcIdAddres struct { type rpcIdAddres struct {
id string id string
host string host string
port int index int
} }
func newRpcClients(log *logger.Logger, mport int) *rpcClients { func newRpcClients(conf *settings.RpcConfig) *rpcClientStub {
res := new(rpcClients) res := new(rpcClientStub)
res.Logger = log res.conf = conf
res.port = mport
res.rpcMapClients = make(map[string]*rpc.Client) res.rpcMapClients = make(map[string]*rpc.Client)
return res return res
} }
func (r *rpcClients) flushRpcClients(ids []*rpcIdAddres) { func (r *rpcClientStub) flushRpcClients(ids []*rpcIdAddres) {
r.mu.Lock() r.mu.Lock()
defer r.mu.Unlock() defer r.mu.Unlock()
@ -44,18 +43,22 @@ func (r *rpcClients) flushRpcClients(ids []*rpcIdAddres) {
} }
for _, idAddr := range ids { for _, idAddr := range ids {
address := fmt.Sprintf("%s:%d", idAddr.host, r.port) address := fmt.Sprintf("%s:%d", idAddr.host, idAddr.index+r.conf.BasePort)
cli, err := rpcsup.JsonClient(r.Logger, address) cli, err := rpcsup.RpcClient(&rpcsup.RpcConfig{
Typec: r.conf.Type,
Network: r.conf.Network,
Address: address,
})
if err != nil { if err != nil {
r.Sugar().Errorf("%s create rpc client error: %s", idAddr.id, address) log.Sugar().Errorf("%s create rpc client error: %s", idAddr.id, address)
continue continue
} }
r.rpcMapClients[idAddr.id] = cli r.rpcMapClients[idAddr.id] = cli
} }
} }
func (r *rpcClients) getConfig(id string, req models.UnisRpcRequest) (*models.UnisRpcResponse, error) { func (r *rpcClientStub) getConfig(id string, req models.UnisRpcRequest) (*models.UnisRpcResponse, error) {
r.mu.RLock() r.mu.RLock()
defer r.mu.RUnlock() defer r.mu.RUnlock()

View File

@ -1,54 +1,27 @@
package uniss package uniss
import ( import (
"context"
"dashboard/logger"
"dashboard/models" "dashboard/models"
"dashboard/pkg/rpcsup"
"dashboard/settings"
"fmt"
) )
type UnisRpcService struct { // Alarm concurrency
*logger.Logger type RpcServerStub struct {
} }
func NewRpcService(log *logger.Logger) *UnisRpcService { func newrpcServerStub() *RpcServerStub {
res := new(UnisRpcService) res := new(RpcServerStub)
res.Logger = log
return res return res
} }
func (u *UnisRpcService) Config(res models.UnisRpcRequest, rsp *models.UnisRpcResponse) error { // func (u *RpcServerStub) Name() string {
u.Sugar().Info("rpc server get mesage", res) // return u.name
// }
func (u *RpcServerStub) Config(res models.UnisRpcRequest, rsp *models.UnisRpcResponse) error {
log.Sugar().Info("rpc server get mesage", res)
rsp.Id = res.Id rsp.Id = res.Id
return nil return nil
} }
type unisRpcServer struct {
log *logger.Logger
port int
host string
typec string
}
func newUnisRpcServer(log *logger.Logger, conf *settings.RpcConfig) *unisRpcServer {
res := new(unisRpcServer)
res.log = log
res.port = conf.Port
res.host = conf.Host
res.typec = conf.Type
return res
}
func (u *unisRpcServer) rpcListenAndServe(ctx context.Context) error {
addrees := fmt.Sprintf("%s:%d", u.host, u.port)
return rpcsup.JsonServer(ctx, u.log, addrees, NewRpcService(u.log))
}

View File

@ -36,13 +36,20 @@ type SqlConfig struct {
} }
type UnisConfig struct { type UnisConfig struct {
*RpcConfig `mapstructure:"rpc"` Instances int `mapstructure:"instances"`
*RpcConfig `mapstructure:"rpc"`
*HttpClientConfig `mapstructure:"httpc"`
} }
type RpcConfig struct { type RpcConfig struct {
Port int `mapstructure:"port"` BasePort int `mapstructure:"base_port"`
Host string `mapstructure:"host"` Network string `mapstructure:"network"`
Type string `mapstructure:"type"` Host string `mapstructure:"host"`
Type string `mapstructure:"type"`
}
type HttpClientConfig struct {
Clients int `mapstructure:"clients"`
} }
type SnowflakeConfig struct { type SnowflakeConfig struct {

View File

@ -10,3 +10,12 @@ func GetFuncName(fn interface{}) string {
return runtime.FuncForPC(ptr).Name() return runtime.FuncForPC(ptr).Name()
} }
func GetInterfaceName(obj interface{}) string {
t := reflect.TypeOf(obj)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t.Name()
}