Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/main/kvo/cmd:all-srcs",
"//app/interface/main/kvo/conf:all-srcs",
"//app/interface/main/kvo/dao:all-srcs",
"//app/interface/main/kvo/http:all-srcs",
"//app/interface/main/kvo/model:all-srcs",
"//app/interface/main/kvo/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,61 @@
#### kvo
##### Version 1.6.3
> 1.add player subtitle key
##### Version 1.6.2
> 1.fix module key
##### Version 1.6.1
> 1.conf change
##### Version 1.6.0
> 1.新增key player_danmaku_domain
##### Version 1.5.3
> 1.identify使用grpc
##### Version 1.5.2
> fix http
##### Version 1.5.1
> 迁移bm
##### Version 1.5.0
> module key 新增 web_player
##### Version 1.4.0
> 迁移到main目录
##### Version 1.3.0
> 同步cache 策略
##### Version 1.2.9
> log add mid
##### Version 1.2.8
> 添加timestamp compare
##### Version 1.2.7
> 去掉ecode nologin
##### Version 1.2.6
> fix stmt nil bug
##### Version 1.2.3
> 移动到interface下
##### Version 1.2.2
> fix code -304
##### Version 1.2.1
> 添加db ping
##### Version 1.2.0
> 去掉userget
##### Version 1.1.0
> 添加readme,使用userget
##### Version 1.0.0
> 1.添加到大仓库

View File

@@ -0,0 +1,13 @@
# Owner
liweijia
zhapuyu
# Author
wuhao02
guanyanliang
liweijia
# Reviewer
guanyanliang
liweijia
zhapuyu

View File

@@ -0,0 +1,18 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- guanyanliang
- liweijia
- wuhao02
- zhapuyu
labels:
- interface
- interface/main/kvo
- main
options:
no_parent_owners: true
reviewers:
- guanyanliang
- liweijia
- wuhao02
- zhapuyu

View File

@@ -0,0 +1,11 @@
#### kvo
##### 项目简介
> 1.客户端配置项
##### 编译环境
> golang v1.7.x以上
##### 依赖包
> 1.公共包go-common

View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = [
"kvo-example.toml",
"kvo-test.toml",
],
importpath = "go-common/app/interface/main/kvo/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/kvo/conf:go_default_library",
"//app/interface/main/kvo/http:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,95 @@
# toml config
version = "1.0.0"
user = "nobody"
pid= "/Users/bilibili/log/kvo.pid"
perf = "127.0.0.1:6690"
checkFile = "/Users/bilibili/log/kvo.html"
dir = "./"
family = "kvo"
address = ""
env = "test"
docLimit = 102400
[mysql]
addr = "localhost:3306"
dsn = "root:123@tcp(localhost:3306)/bilibili_kvo?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
idleTimeout = "4h"
queryTimeout = "500ms"
execTimeout = "500ms"
tranTimeout = "500ms"
[mysql.breaker]
window = "1s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[xlog]
dir = "/Users/bilibili/log/kvo/"
[xlog.elk]
project = "kvo"
addr = "172.18.20.17:8520"
chanSize = 10240
[tracer]
proto = "udp"
addr = "172.16.33.46:5140"
tag = "platform/kvo"
[multiHttp]
[multiHttp.outer]
addrs = ["0.0.0.0:6691"]
maxListen = 100
[multiHttp.local]
addrs = ["0.0.0.0:6692"]
maxListen = 100
[identify]
whiteAccessKey = ""
whiteMid = 0
[identify.memcache]
name = "go-business/identify"
proto = "tcp"
addr = "172.16.33.54:11211"
active = 5
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[identify.host]
auth = "http://passport.bilibili.co"
secret = "http://open.bilibili.co"
[identify.httpClient]
key = "e7482d29be4a95b8"
secret = "9e803791cdef756e75faee68e12b7442"
dial = "300ms"
timeout = "500ms"
keepAlive = "60s"
[identify.httpClient.breaker]
window = "10s"
sleep = "300ms"
bucket = 10
ratio = 0.5
request = 100
[identify.httpClient.url]
"http://passport.bilibili.co/intranet/auth/tokenInfo" = {timeout = "100ms"}
"http://passport.bilibili.co/intranet/auth/cookieInfo" = {timeout = "100ms"}
"http://open.bilibili.co/api/getsecret" = {timeout = "500ms"}
[memcache]
expire = "10s"
[memcache.kvo]
name = "kvo"
proto = "tcp"
addr = "localhost:11211"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"

View File

@@ -0,0 +1,93 @@
# toml config
version = "1.0.0"
user = "nobody"
pid= "/tmp/kvo.pid"
perf = "127.0.0.1:6690"
checkFile = "/data/www/kvo.html"
dir = "./"
family = "kvo"
address = ""
env = "test"
docLimit = 102400
[mysql]
addr = "172.16.33.54:3306"
dsn = "test:test@tcp(172.16.33.54:3306)/bilibili_kvo?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
[xlog]
dir = "/data/log/kvo/"
# [xlog.elk]
# project = "kvo"
# addr = "172.18.20.17:8520"
# chanSize = 10240
[tracer]
proto = "udp"
addr = "172.16.33.46:5140"
tag = "platform/kvo"
[multiHttp]
[multiHttp.outer]
addrs = ["0.0.0.0:6691"]
maxListen = 100
[multiHttp.local]
addrs = ["0.0.0.0:6692"]
maxListen = 100
[identify]
whiteAccessKey = ""
whiteMid = 0
[identify.app]
key = "e7482d29be4a95b8"
secret = "9e803791cdef756e75faee68e12b7442"
[identify.memcache]
name = "go-business/identify"
proto = "tcp"
addr = "172.16.33.54:11211"
active = 5
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[identify.host]
auth = "http://passport.bilibili.com"
secret = "http://open.bilibili.com"
[identify.authHTTPClient]
dial = "1s"
timeout = "1s"
keepAlive = "60s"
timer = 1000
[identify.authHTTPClient.breaker]
window ="10s"
sleep ="10ms"
bucket = 10
ratio = 0.5
request = 100
[identify.secretHTTPClient]
dial = "1s"
timeout = "1s"
keepAlive = "60s"
timer = 1000
[identify.secretHTTPClient.breaker]
window ="10s"
sleep ="10ms"
bucket = 10
ratio = 0.5
request = 100
[memcache]
expire = "720h"
[memcache.kvo]
name = "kvo"
proto = "tcp"
addr = "172.16.33.54:11213"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"

View File

@@ -0,0 +1,47 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/interface/main/kvo/conf"
"go-common/app/interface/main/kvo/http"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
// init log
log.Init(conf.Conf.XLog)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
log.Info("kvo start")
// service init
http.Init(conf.Conf)
// init pprof conf.Conf.Perf
// init signal
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("kvo get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("kvo exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,39 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/interface/main/kvo/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
"//library/net/trace:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,97 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/auth"
"go-common/library/net/trace"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf conf
Conf = &Config{}
)
// Config config
type Config struct {
Rule *Rule
XLog *log.Config
Tracer *trace.Config
Auth *auth.Config
// memcache
Memcache *KvoMemcache
// mysql
Mysql *sql.Config
// bm
BM *bm.ServerConfig
}
// Rule .
type Rule struct {
DocLimit int
}
// KvoMemcache memcache config
type KvoMemcache struct {
Kvo *memcache.Config
Expire time.Duration
}
func init() {
flag.StringVar(&confPath, "conf", "", "config path")
}
// Init init conf
func Init() (err error) {
if confPath != "" {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
err = remote()
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,54 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["document_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/kvo/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"document.go",
"document_cache.go",
"user_conf.go",
"user_conf_cache.go",
],
importpath = "go-common/app/interface/main/kvo/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/kvo/conf:go_default_library",
"//app/interface/main/kvo/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,50 @@
package dao
import (
"context"
"time"
"go-common/app/interface/main/kvo/conf"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
)
// Dao kvo data access obj with bfs
type Dao struct {
cache *memcache.Pool
mcExpire int32
// http client for bfs req
db *sql.DB
// sql stmt
getUserConf *sql.Stmt
getDocument *sql.Stmt
}
// New new data access
func New(c *conf.Config) (d *Dao) {
d = &Dao{
cache: memcache.NewPool(c.Memcache.Kvo),
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
db: sql.NewMySQL(c.Mysql),
}
d.getUserConf = d.db.Prepared(_getUserConf)
d.getDocument = d.db.Prepared(_getDocument)
return
}
// Ping check if health
func (d *Dao) Ping(ctx context.Context) (err error) {
if err = d.pingMemcache(ctx); err != nil {
return
}
if err = d.db.Ping(ctx); err != nil {
return
}
return
}
// BeginTx begin trans
func (d *Dao) BeginTx(c context.Context) (*sql.Tx, error) {
return d.db.Begin(c)
}

View File

@@ -0,0 +1,41 @@
package dao
import (
"context"
"time"
"go-common/app/interface/main/kvo/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_upDocument = "INSERT INTO document(check_sum,doc,ctime,mtime) VALUES(?,?,?,?) ON DUPLICATE KEY UPDATE doc=?"
_getDocument = "SELECT check_sum,doc FROM document WHERE check_sum=?"
)
// Document get docuemtn
func (d *Dao) Document(ctx context.Context, checkSum int64) (doc *model.Document, err error) {
row := d.getDocument.QueryRow(ctx, checkSum)
doc = &model.Document{}
err = row.Scan(&doc.CheckSum, &doc.Doc)
if err != nil {
if err == sql.ErrNoRows {
doc = nil
err = nil
return
}
log.Error("row.scan err:%v", err)
}
return
}
// TxUpDocuement add a document
func (d *Dao) TxUpDocuement(ctx context.Context, tx *sql.Tx, checkSum int64, data string, now time.Time) (err error) {
_, err = tx.Exec(_upDocument, checkSum, data, now, now, data)
if err != nil {
log.Error("db.exec err:%v", err)
}
return
}

View File

@@ -0,0 +1,69 @@
package dao
import (
"context"
"encoding/json"
"fmt"
mc "go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_docKeyPrefix = "d"
)
// pingMemcache check memcache health
func (d *Dao) pingMemcache(ctx context.Context) (err error) {
conn := d.cache.Get(ctx)
item := mc.Item{Key: "ping", Value: []byte{1}, Expiration: d.mcExpire}
err = conn.Set(&item)
conn.Close()
return
}
// DocumentCache memcache get document(hash)
func (d *Dao) DocumentCache(ctx context.Context, checkSum int64) (data json.RawMessage, err error) {
var result *mc.Item
conn := d.cache.Get(ctx)
defer conn.Close()
if result, err = conn.Get(cacheDocKey(checkSum)); err != nil {
if err == mc.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", cacheDocKey(checkSum), err)
return
}
data = json.RawMessage(result.Value)
return
}
// DelDocumentCache remove memcache document detail
func (d *Dao) DelDocumentCache(ctx context.Context, checkSum int64) (err error) {
conn := d.cache.Get(ctx)
defer conn.Close()
if err = conn.Delete(cacheDocKey(checkSum)); err == mc.ErrNotFound {
err = nil
}
return
}
// SetDocumentCache add document cache
func (d *Dao) SetDocumentCache(ctx context.Context, checkSum int64, data json.RawMessage) (err error) {
conn := d.cache.Get(ctx)
defer conn.Close()
if err = conn.Set(&mc.Item{
Key: cacheDocKey(checkSum),
Value: data,
Expiration: d.mcExpire,
}); err != nil {
log.Error("dao.SetDocumentCache(%v,%s) err:%v", cacheDocKey(checkSum), data, err)
return
}
return
}
func cacheDocKey(checkSum int64) string {
return fmt.Sprintf("%v_%v", _docKeyPrefix, checkSum)
}

View File

@@ -0,0 +1,45 @@
package dao
import (
"context"
"flag"
"path/filepath"
"testing"
"go-common/app/interface/main/kvo/conf"
. "github.com/smartystreets/goconvey/convey"
)
var d *Dao
func WithDao(f func(d *Dao)) func() {
return func() {
dir, _ := filepath.Abs("../cmd/web-interface-test.toml")
flag.Set("conf", dir)
conf.Init()
if d == nil {
d = New(conf.Conf)
}
f(d)
}
}
func TestDao_Document(t *testing.T) {
Convey("test document", t, WithDao(func(d *Dao) {
checkSum := int64(11111)
data, err := d.Document(context.TODO(), checkSum)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}
func TestDao_UserConf(t *testing.T) {
Convey("test document", t, WithDao(func(d *Dao) {
mid := int64(11111)
moduleKey := 1
data, err := d.UserConf(context.TODO(), mid, moduleKey)
So(err, ShouldBeNil)
Printf("%+v", data)
}))
}

View File

@@ -0,0 +1,41 @@
package dao
import (
"context"
"time"
"go-common/app/interface/main/kvo/model"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_getUserConf = "SELECT mid,module_key,check_sum,timestamp FROM user_conf WHERE mid=? AND module_key=?"
_upUserConf = "INSERT INTO user_conf(mid,module_key,check_sum,timestamp,ctime,mtime) VALUES(?,?,?,?,?,?) ON DUPLICATE KEY UPDATE check_sum=?, timestamp=?"
)
// UserConf get userconf
func (d *Dao) UserConf(ctx context.Context, mid int64, moduleKey int) (userConf *model.UserConf, err error) {
row := d.getUserConf.QueryRow(ctx, mid, moduleKey)
userConf = &model.UserConf{}
err = row.Scan(&userConf.Mid, &userConf.ModuleKey, &userConf.CheckSum, &userConf.Timestamp)
if err != nil {
if err == sql.ErrNoRows {
userConf = nil
err = nil
return
}
log.Error("row.Scan err:%v", err)
}
return
}
// TxUpUserConf add or update user conf
func (d *Dao) TxUpUserConf(ctx context.Context, tx *sql.Tx, mid int64, moduleKey int, checkSum int64, now time.Time) (err error) {
_, err = tx.Exec(_upUserConf, mid, moduleKey, checkSum, now.Unix(), now, now, checkSum, now.Unix())
if err != nil {
log.Error("db.exec err:%v", err)
}
return
}

View File

@@ -0,0 +1,70 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"go-common/app/interface/main/kvo/model"
mc "go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_userConfKeyPrefix = "u"
)
func cacheUserConfKey(mid int64, moduleKey int) string {
return fmt.Sprintf("%v_%v_%v", _userConfKeyPrefix, mid, moduleKey)
}
// UserConfCache user config cache
func (d *Dao) UserConfCache(ctx context.Context, mid int64, moduleKey int) (uc *model.UserConf, err error) {
var r *mc.Item
conn := d.cache.Get(ctx)
defer conn.Close()
if r, err = conn.Get(cacheUserConfKey(mid, moduleKey)); err != nil {
if err == mc.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", cacheUserConfKey(mid, moduleKey), err)
return
}
if err = json.Unmarshal(r.Value, &uc); err != nil {
log.Error("json.Unmarshal(%s) error(%v)", r.Value, err)
uc = nil
}
return
}
// SetUserConfCache set user config cache
func (d *Dao) SetUserConfCache(ctx context.Context, uc *model.UserConf) (err error) {
bs, err := json.Marshal(uc)
if err != nil {
log.Error("SetUserConfCache.Marshal err:%v", err)
return
}
conn := d.cache.Get(ctx)
defer conn.Close()
if err = conn.Set(&mc.Item{
Key: cacheUserConfKey(uc.Mid, uc.ModuleKey),
Value: bs,
Expiration: d.mcExpire,
}); err != nil {
log.Error("dao.SetUserConfCache(%v,%v) err:%v", cacheUserConfKey(uc.Mid, uc.ModuleKey), bs, err)
return
}
return
}
// DelUserConfCache del user config cache
func (d *Dao) DelUserConfCache(ctx context.Context, mid int64, moduleKey int) (err error) {
conn := d.cache.Get(ctx)
defer conn.Close()
if err = conn.Delete(cacheUserConfKey(mid, moduleKey)); err == mc.ErrNotFound {
err = nil
}
return
}

View File

@@ -0,0 +1,39 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"http.go",
],
importpath = "go-common/app/interface/main/kvo/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/kvo/conf:go_default_library",
"//app/interface/main/kvo/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,77 @@
package http
import (
"strconv"
"time"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// doc get document
func doc(c *bm.Context) {
params := c.Request.Form
tsStr := params.Get("timestamp")
moduleKey := params.Get("module_key")
checkSumStr := params.Get("check_sum")
// check login
midIf, _ := c.Get("mid")
mid := midIf.(int64)
ts, err := strconv.ParseInt(tsStr, 10, 64)
if err != nil {
log.Error("strconv.ParseInt64(%v) error(%v)", tsStr, err)
c.JSON(nil, ecode.RequestErr)
return
}
checkSum, err := strconv.ParseInt(checkSumStr, 10, 64)
if err != nil {
log.Error("strconv.ParseInt64(%v) error(%v)", checkSumStr, err)
c.JSON(nil, ecode.RequestErr)
return
}
// doc
data, err := kvoSvr.Document(c, mid, moduleKey, ts, checkSum)
if err != nil {
if ecode.Cause(err) != ecode.NotModified {
log.Error("kvoSvr.Document(%v,%v) error(%v)", mid, moduleKey, err)
}
c.JSON(nil, err)
return
}
c.JSON(data, nil)
}
// addDoc add document
func addDoc(c *bm.Context) {
params := c.Request.Form
data := params.Get("data")
tsStr := params.Get("timestamp")
checkSumStr := params.Get("check_sum")
moduleKey := params.Get("module_key")
// check login
midIf, _ := c.Get("mid")
mid := midIf.(int64)
ts, err := strconv.ParseInt(tsStr, 10, 64)
if err != nil {
log.Error("strconv.ParseInt64(%v) error(%v)", tsStr, err)
c.JSON(nil, ecode.RequestErr)
return
}
checkSum, err := strconv.ParseInt(checkSumStr, 10, 64)
if err != nil {
log.Error("strconv.ParseInt64(%v) error(%v)", checkSumStr, err)
c.JSON(nil, ecode.RequestErr)
return
}
// add doc
resp, err := kvoSvr.AddDocument(c, mid, moduleKey, data, ts, checkSum, time.Now())
if err != nil {
if ecode.Cause(err) != ecode.NotModified {
log.Error("kvoSvr.AddDocument(%v,%v,%v,%v,%v) error(%v)", mid, moduleKey, data, ts, checkSum, err)
}
c.JSON(nil, err)
return
}
c.JSON(resp, nil)
}

View File

@@ -0,0 +1,49 @@
package http
import (
"net/http"
"go-common/app/interface/main/kvo/conf"
"go-common/app/interface/main/kvo/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/auth"
)
var (
kvoSvr *service.Service
authSvr *auth.Auth
)
// Init init http
func Init(c *conf.Config) {
kvoSvr = service.New(c)
authSvr = auth.New(c.Auth)
// init outer router
engineOut := bm.DefaultServer(c.BM)
outerRouter(engineOut)
if err := engineOut.Start(); err != nil {
log.Error("engineOut.Start error(%v)", err)
panic(err)
}
}
func outerRouter(e *bm.Engine) {
e.Ping(ping)
group := e.Group("/x/kvo", bm.CORS())
{
group.GET("/web/doc/get", authSvr.UserWeb, doc)
group.POST("/web/doc/add", authSvr.UserWeb, addDoc)
group.GET("/app/doc/get", authSvr.UserMobile, doc)
group.POST("/app/doc/add", authSvr.UserMobile, addDoc)
}
}
// ping check server ok.
func ping(c *bm.Context) {
var err error
if err = kvoSvr.Ping(c); err != nil {
log.Error("kvo service ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -0,0 +1,31 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["model.go"],
importpath = "go-common/app/interface/main/kvo/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/main/kvo/model/module:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,15 @@
package model
// UserConf user configruation
type UserConf struct {
ModuleKey int `json:"module_key,omitempty"`
Mid int64 `json:"mid,omitempty"`
CheckSum int64 `json:"check_sum"`
Timestamp int64 `json:"timestamp"`
}
// Document data store
type Document struct {
CheckSum int64 `json:"check_sum"`
Doc string `json:"doc"`
}

View File

@@ -0,0 +1,32 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"module.go",
"player.go",
"web_player.go",
],
importpath = "go-common/app/interface/main/kvo/model/module",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,88 @@
package module
import (
"encoding/json"
"fmt"
"hash/crc32"
)
// Setting ModuleConf
type Setting struct {
Timestamp int64 `json:"timestamp"`
CheckSum int64 `json:"check_sum"`
Data json.RawMessage `json:"data"`
}
const (
_playerID = 1
_playerKey = "player"
_webPlayerID = 2
_webPlayerKey = "web_player"
)
var _moduleMap = map[string]int{
_playerKey: _playerID,
_webPlayerKey: _webPlayerID,
}
// VerifyModuleKey verify key
func VerifyModuleKey(key string) int {
return _moduleMap[key]
}
// Result get module message
func Result(moduleKeyID int, data string) (rm json.RawMessage, checkSum int64, err error) {
var (
bs []byte
)
switch moduleKeyID {
case _playerID:
player := &Player{}
playerSha1 := &PlayerSha1{}
err = json.Unmarshal([]byte(data), player)
if err != nil {
return
}
bs, err = json.Marshal(player)
if err != nil {
return
}
rm = json.RawMessage(bs)
// check_sum
err = json.Unmarshal([]byte(data), playerSha1)
if err != nil {
return
}
bs, err = json.Marshal(playerSha1)
if err != nil {
return
}
checkSum = int64(crc32.ChecksumIEEE(bs))
return
case _webPlayerID:
player := &WebPlayer{}
playerSha1 := &WebPlayerSha1{}
err = json.Unmarshal([]byte(data), player)
if err != nil {
return
}
bs, err = json.Marshal(player)
if err != nil {
return
}
rm = json.RawMessage(bs)
// check_sum
err = json.Unmarshal([]byte(data), playerSha1)
if err != nil {
return
}
bs, err = json.Marshal(playerSha1)
if err != nil {
return
}
checkSum = int64(crc32.ChecksumIEEE(bs))
return
}
err = fmt.Errorf("module_key_id not found: %v", moduleKeyID)
return
}

View File

@@ -0,0 +1,61 @@
package module
// PlayerSha1 one module for sha1
type PlayerSha1 struct {
// special fields
PlayerWebDanmakuAutoscaling bool `json:"player_web_danmaku_autoscaling,omitempty"`
PlayerWebHTML5DanmakuRenderingtype string `json:"player_web_html5_danmaku_renderingtype,omitempty"`
PlayerAppPlaybackMode int `json:"player_app_playback_mode,omitempty"`
PlayerAppPlaybackBackground bool `json:"player_app_playback_background,omitempty"`
PlayerAppDanmakuStrokewidth float64 `json:"player_app_danmaku_strokewidth,omitempty"`
// common fileds
PlayerDanmakuOpacity float64 `json:"player_danmaku_opacity,omitempty"`
PlayerDanmakuSpeed float64 `json:"player_danmaku_speed,omitempty"`
PlayerDanmakuDensity int `json:"player_danmaku_density,omitempty"`
PlayerDanmakuScalingfactor float64 `json:"player_danmaku_scalingfactor,omitempty"`
PlayerDanmakuStrokestyle int `json:"player_danmaku_strokestyle,omitempty"`
PlayerDanmakuFontname string `json:"player_danmaku_fontname,omitempty"`
PlayerDanmakuFontbold bool `json:"player_danmaku_fontbold,omitempty"`
PlayerDanmakuDefensivebottom bool `json:"player_danmaku_defensivebottom,omitempty"`
PlayerDanmakuEnableblocklist bool `json:"player_danmaku_enableblocklist,omitempty"`
PlayerDanmakuBlockrepeat bool `json:"player_danmaku_blockrepeat,omitempty"`
PlayerDanmakuBlocktop bool `json:"player_danmaku_blocktop,omitempty"`
PlayerDanmakuBlockscroll bool `json:"player_danmaku_blockscroll,omitempty"`
PlayerDanmakuBlockbottom bool `json:"player_danmaku_blockbottom,omitempty"`
PlayerDanmakuBlockcolorful bool `json:"player_danmaku_blockcolorful,omitempty"`
PlayerDanmakuBlockcommon bool `json:"player_danmaku_blockcommon,omitempty"`
PlayerDanmakuBlocksubtitle bool `json:"player_danmaku_blocksubtitle,omitempty"`
PlayerDanmakuBlockspecial bool `json:"player_danmaku_blockspecial,omitempty"`
PlayerDanmakuDomain float64 `json:"player_danmaku_domain,omitempty"`
PlayerSubtitleSwitch int `json:"player_subtitle_switch,omitempty"`
}
// Player one module return json
type Player struct {
// special fields
PlayerWebDanmakuAutoscaling bool `json:"player_web_danmaku_autoscaling"`
PlayerWebHTML5DanmakuRenderingtype string `json:"player_web_html5_danmaku_renderingtype"`
PlayerAppPlaybackMode int `json:"player_app_playback_mode"`
PlayerAppPlaybackBackground bool `json:"player_app_playback_background"`
PlayerAppDanmakuStrokewidth float64 `json:"player_app_danmaku_strokewidth"`
// common fileds
PlayerDanmakuOpacity float64 `json:"player_danmaku_opacity"`
PlayerDanmakuSpeed float64 `json:"player_danmaku_speed"`
PlayerDanmakuDensity int `json:"player_danmaku_density"`
PlayerDanmakuScalingfactor float64 `json:"player_danmaku_scalingfactor"`
PlayerDanmakuStrokestyle int `json:"player_danmaku_strokestyle"`
PlayerDanmakuFontname string `json:"player_danmaku_fontname"`
PlayerDanmakuFontbold bool `json:"player_danmaku_fontbold"`
PlayerDanmakuDefensivebottom bool `json:"player_danmaku_defensivebottom"`
PlayerDanmakuEnableblocklist bool `json:"player_danmaku_enableblocklist"`
PlayerDanmakuBlockrepeat bool `json:"player_danmaku_blockrepeat"`
PlayerDanmakuBlocktop bool `json:"player_danmaku_blocktop"`
PlayerDanmakuBlockscroll bool `json:"player_danmaku_blockscroll"`
PlayerDanmakuBlockbottom bool `json:"player_danmaku_blockbottom"`
PlayerDanmakuBlockcolorful bool `json:"player_danmaku_blockcolorful"`
PlayerDanmakuBlockcommon bool `json:"player_danmaku_blockcommon"`
PlayerDanmakuBlocksubtitle bool `json:"player_danmaku_blocksubtitle"`
PlayerDanmakuBlockspecial bool `json:"player_danmaku_blockspecial"`
PlayerDanmakuDomain float64 `json:"player_danmaku_domain"`
PlayerSubtitleSwitch int `json:"player_subtitle_switch"`
}

View File

@@ -0,0 +1,57 @@
package module
// WebPlayerSha1 one module for sha1
type WebPlayerSha1 struct {
// special fields
PlayerWebDanmakuAutoscaling bool `json:"player_web_danmaku_autoscaling,omitempty"`
PlayerWebHTML5DanmakuRenderingtype string `json:"player_web_html5_danmaku_renderingtype,omitempty"`
PlayerAppPlaybackMode int `json:"player_app_playback_mode,omitempty"`
PlayerAppPlaybackBackground bool `json:"player_app_playback_background,omitempty"`
PlayerAppDanmakuStrokewidth float64 `json:"player_app_danmaku_strokewidth,omitempty"`
// common fileds
PlayerDanmakuOpacity float64 `json:"player_danmaku_opacity,omitempty"`
PlayerDanmakuSpeed float64 `json:"player_danmaku_speed,omitempty"`
PlayerDanmakuDensity int `json:"player_danmaku_density,omitempty"`
PlayerDanmakuScalingfactor float64 `json:"player_danmaku_scalingfactor,omitempty"`
PlayerDanmakuStrokestyle int `json:"player_danmaku_strokestyle,omitempty"`
PlayerDanmakuFontname string `json:"player_danmaku_fontname,omitempty"`
PlayerDanmakuFontbold bool `json:"player_danmaku_fontbold,omitempty"`
PlayerDanmakuDefensivebottom bool `json:"player_danmaku_defensivebottom,omitempty"`
PlayerDanmakuEnableblocklist bool `json:"player_danmaku_enableblocklist,omitempty"`
PlayerDanmakuBlockrepeat bool `json:"player_danmaku_blockrepeat,omitempty"`
PlayerDanmakuBlocktop bool `json:"player_danmaku_blocktop,omitempty"`
PlayerDanmakuBlockscroll bool `json:"player_danmaku_blockscroll,omitempty"`
PlayerDanmakuBlockbottom bool `json:"player_danmaku_blockbottom,omitempty"`
PlayerDanmakuBlockcolorful bool `json:"player_danmaku_blockcolorful,omitempty"`
PlayerDanmakuBlockcommon bool `json:"player_danmaku_blockcommon,omitempty"`
PlayerDanmakuBlocksubtitle bool `json:"player_danmaku_blocksubtitle,omitempty"`
PlayerDanmakuBlockspecial bool `json:"player_danmaku_blockspecial,omitempty"`
}
// WebPlayer one module return json
type WebPlayer struct {
// special fields
PlayerWebDanmakuAutoscaling bool `json:"player_web_danmaku_autoscaling"`
PlayerWebHTML5DanmakuRenderingtype string `json:"player_web_html5_danmaku_renderingtype"`
PlayerAppPlaybackMode int `json:"player_app_playback_mode"`
PlayerAppPlaybackBackground bool `json:"player_app_playback_background"`
PlayerAppDanmakuStrokewidth float64 `json:"player_app_danmaku_strokewidth"`
// common fileds
PlayerDanmakuOpacity float64 `json:"player_danmaku_opacity"`
PlayerDanmakuSpeed float64 `json:"player_danmaku_speed"`
PlayerDanmakuDensity int `json:"player_danmaku_density"`
PlayerDanmakuScalingfactor float64 `json:"player_danmaku_scalingfactor"`
PlayerDanmakuStrokestyle int `json:"player_danmaku_strokestyle"`
PlayerDanmakuFontname string `json:"player_danmaku_fontname"`
PlayerDanmakuFontbold bool `json:"player_danmaku_fontbold"`
PlayerDanmakuDefensivebottom bool `json:"player_danmaku_defensivebottom"`
PlayerDanmakuEnableblocklist bool `json:"player_danmaku_enableblocklist"`
PlayerDanmakuBlockrepeat bool `json:"player_danmaku_blockrepeat"`
PlayerDanmakuBlocktop bool `json:"player_danmaku_blocktop"`
PlayerDanmakuBlockscroll bool `json:"player_danmaku_blockscroll"`
PlayerDanmakuBlockbottom bool `json:"player_danmaku_blockbottom"`
PlayerDanmakuBlockcolorful bool `json:"player_danmaku_blockcolorful"`
PlayerDanmakuBlockcommon bool `json:"player_danmaku_blockcommon"`
PlayerDanmakuBlocksubtitle bool `json:"player_danmaku_blocksubtitle"`
PlayerDanmakuBlockspecial bool `json:"player_danmaku_blockspecial"`
}

View File

@@ -0,0 +1,60 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["document_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/kvo/conf:go_default_library",
"//app/interface/main/kvo/model/module:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/container/pool:go_default_library",
"//library/database/sql:go_default_library",
"//library/net/netutil/breaker:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"document.go",
"service.go",
],
importpath = "go-common/app/interface/main/kvo/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/kvo/conf:go_default_library",
"//app/interface/main/kvo/dao:go_default_library",
"//app/interface/main/kvo/model:go_default_library",
"//app/interface/main/kvo/model/module:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,179 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/interface/main/kvo/model"
"go-common/app/interface/main/kvo/model/module"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
)
// Document get document
func (s *Service) Document(c context.Context, mid int64, moduleKey string, timestamp int64, checkSum int64) (setting *module.Setting, err error) {
var (
uc *model.UserConf
rm json.RawMessage
moduleKeyID int
)
if moduleKeyID = module.VerifyModuleKey(moduleKey); moduleKeyID == 0 {
err = ecode.RequestErr
return
}
uc, err = s.userConf(c, mid, moduleKeyID)
if err != nil {
return
}
if uc.CheckSum == 0 || uc.Timestamp == 0 {
err = ecode.NotModified
return
}
// 数据没有变动
if uc.CheckSum == checkSum && uc.Timestamp == timestamp {
err = ecode.NotModified
return
}
rm, err = s.document(c, uc.CheckSum)
if err != nil {
return
}
setting = &module.Setting{
Timestamp: uc.Timestamp,
CheckSum: uc.CheckSum,
Data: rm,
}
return
}
func (s *Service) userConf(c context.Context, mid int64, moduleKeyID int) (uc *model.UserConf, err error) {
uc, err = s.da.UserConfCache(c, mid, moduleKeyID)
if err != nil {
log.Error("service.userConf.UserConfCache(%v,%v) err:%v", mid, moduleKeyID, err)
}
if uc != nil {
s.sp.Incr("user_conf_cached")
return
}
uc, err = s.da.UserConf(c, mid, moduleKeyID)
if err != nil {
log.Error("service.userConf(%v,%v) err:%v", mid, moduleKeyID, err)
return
}
if uc == nil {
uc = &model.UserConf{
Mid: mid,
ModuleKey: moduleKeyID,
}
s.sp.Incr("default_user_conf")
}
s.sp.Incr("user_conf_missed")
s.updateUcCache(mid, moduleKeyID)
return
}
func (s *Service) document(c context.Context, checkSum int64) (rm json.RawMessage, err error) {
var (
doc *model.Document
)
rm, err = s.da.DocumentCache(c, checkSum)
if err != nil {
log.Error("service.document.DocumentCache(%v) err:%v", checkSum, err)
}
if rm != nil {
s.sp.Incr("document_cached")
return
}
doc, err = s.da.Document(c, checkSum)
if err != nil {
log.Error("service.document(%v) err:%v", checkSum, err)
return
}
if doc == nil {
err = ecode.NothingFound
s.sp.Incr("user_conf_document_error")
return
}
s.sp.Incr("document_missed")
rm = json.RawMessage(doc.Doc)
s.da.SetDocumentCache(c, checkSum, rm)
return
}
// AddDocument add a user document
func (s *Service) AddDocument(c context.Context, mid int64, moduleKey string, data string, timestamp int64, oldSum int64, now time.Time) (resp *model.UserConf, err error) {
var (
uc *model.UserConf
doc *model.Document
rm json.RawMessage
checkSum int64
tx *sql.Tx
moduleKeyID int
)
if moduleKeyID = module.VerifyModuleKey(moduleKey); moduleKeyID == 0 {
return nil, ecode.RequestErr
}
if rm, checkSum, err = module.Result(moduleKeyID, data); err != nil {
log.Error("service.GetModule(%v,%s) err:%v", moduleKey, data, err)
return nil, ecode.RequestErr
}
if len(rm) > s.docLimit {
err = ecode.KvoDataOverLimit
return
}
if uc, err = s.da.UserConf(c, mid, moduleKeyID); err != nil {
log.Error("service.AddDocument.UserConf(%v,%v) err:%v", mid, moduleKeyID, err)
return
}
s.updateUcCache(mid, moduleKeyID)
if uc != nil {
if uc.Timestamp != timestamp {
err = ecode.KvoTimestampErr
log.Error("service.AddDocument.CompareTimeStamp(%v,%v,%v) err:%v", mid, uc.Timestamp, timestamp, err)
return
}
if uc.CheckSum != oldSum {
err = ecode.KvoCheckSumErr
return
}
if uc.CheckSum == checkSum {
err = ecode.NotModified
return
}
}
// trans
tx, err = s.da.BeginTx(c)
if err != nil {
log.Error("s.da.BeginTx err:%v", err)
return
}
if err = s.da.TxUpUserConf(c, tx, mid, moduleKeyID, checkSum, now); err != nil {
log.Error("s.da.TxUpUserConf(%v,%v,%v) error(%v)", mid, moduleKeyID, checkSum, err)
tx.Rollback()
return
}
doc, err = s.da.Document(c, checkSum)
if err != nil {
tx.Rollback()
return
}
if doc == nil {
if err = s.da.TxUpDocuement(c, tx, checkSum, string(rm), now); err != nil {
log.Error("s.da.TxUpDocuement(%v,%v,%v) error(%v)", mid, moduleKeyID, checkSum, err)
tx.Rollback()
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit(), error(%v)", err)
}
resp = &model.UserConf{
CheckSum: checkSum,
Timestamp: now.Unix(),
}
s.updateUcCache(mid, moduleKeyID)
return
}

View File

@@ -0,0 +1,78 @@
package service
import (
"context"
"encoding/json"
"testing"
"time"
conf "go-common/app/interface/main/kvo/conf"
"go-common/app/interface/main/kvo/model/module"
"go-common/library/cache/memcache"
"go-common/library/container/pool"
"go-common/library/database/sql"
"go-common/library/net/netutil/breaker"
xtime "go-common/library/time"
. "github.com/smartystreets/goconvey/convey"
)
func getService() *Service {
s := New(&conf.Config{
Rule: &conf.Rule{DocLimit: 1024 * 1024 * 1024},
Memcache: &conf.KvoMemcache{
Kvo: &memcache.Config{
Config: &pool.Config{
Active: 10,
Idle: 4,
IdleTimeout: xtime.Duration(time.Second),
},
Name: "kvo",
Proto: "tcp",
Addr: "127.0.0.1:11211",
DialTimeout: xtime.Duration(time.Second),
ReadTimeout: xtime.Duration(time.Second),
WriteTimeout: xtime.Duration(time.Second),
},
Expire: xtime.Duration(time.Hour),
},
Mysql: &sql.Config{
Addr: "localhost:3306",
DSN: "root:123@tcp(localhost:3306)/bilibili?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4",
Active: 10,
Idle: 4,
IdleTimeout: xtime.Duration(time.Second),
QueryTimeout: xtime.Duration(time.Second),
ExecTimeout: xtime.Duration(time.Second),
TranTimeout: xtime.Duration(time.Second),
Breaker: &breaker.Config{
Window: xtime.Duration(time.Second),
Sleep: xtime.Duration(time.Second),
Bucket: 10,
Ratio: 0.5,
Request: 100,
},
},
})
return s
}
func TestAddDocument(t *testing.T) {
Convey("", t, func() {
s := getService()
p := &module.Player{
PlayerWebDanmakuAutoscaling: false,
}
bs, _ := json.Marshal(p)
_, err := s.AddDocument(context.Background(), 1, "player", string(bs), 0, 0, time.Now())
So(nil, ShouldEqual, err)
})
}
func TestDocument(t *testing.T) {
Convey("", t, func() {
s := getService()
_, err := s.Document(context.Background(), 1, "player", 1234, 12345)
So(nil, ShouldEqual, err)
})
}

View File

@@ -0,0 +1,67 @@
package service
import (
"context"
conf "go-common/app/interface/main/kvo/conf"
"go-common/app/interface/main/kvo/dao"
"go-common/library/log"
"go-common/library/stat/prom"
)
// Service kvo main service
type Service struct {
da *dao.Dao
docLimit int
sp *prom.Prom
cacheUcCh chan *cacheUc
}
type cacheUc struct {
mid int64
moduleKeyID int
}
// New get a kvo service
func New(c *conf.Config) *Service {
da := dao.New(c)
s := &Service{
da: da,
// limit data size
docLimit: c.Rule.DocLimit,
cacheUcCh: make(chan *cacheUc, 1024),
sp: prom.New().WithCounter("conf_cache", []string{"method"}),
}
go s.cacheUcProc()
return s
}
func (s *Service) updateUcCache(mid int64, moduleKeyID int) {
select {
case s.cacheUcCh <- &cacheUc{
mid: mid,
moduleKeyID: moduleKeyID,
}:
default:
log.Info("s.cacheUcCh is full")
}
}
func (s *Service) cacheUcProc() {
for cuc := range s.cacheUcCh {
uc, err := s.da.UserConf(context.Background(), cuc.mid, cuc.moduleKeyID)
if err != nil {
log.Error("service.cacheUcProc(%v,%v),err:%v", cuc.mid, cuc.moduleKeyID)
continue
}
if uc != nil {
s.da.SetUserConfCache(context.Background(), uc)
}
}
}
// Ping kvo service check
func (s *Service) Ping(ctx context.Context) (err error) {
return s.da.Ping(ctx)
}