Initial commit

This commit is contained in:
Donny
2019-04-22 20:46:32 +08:00
commit 49ab8aadd1
25441 changed files with 4055000 additions and 0 deletions

32
app/service/BUILD Normal file
View File

@@ -0,0 +1,32 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/bbq:all-srcs",
"//app/service/ep:all-srcs",
"//app/service/live:all-srcs",
"//app/service/main:all-srcs",
"//app/service/openplatform:all-srcs",
"//app/service/ops/log-agent:all-srcs",
"//app/service/video/stream-mng/api/v1:all-srcs",
"//app/service/video/stream-mng/cmd:all-srcs",
"//app/service/video/stream-mng/common:all-srcs",
"//app/service/video/stream-mng/conf:all-srcs",
"//app/service/video/stream-mng/dao:all-srcs",
"//app/service/video/stream-mng/middleware:all-srcs",
"//app/service/video/stream-mng/model:all-srcs",
"//app/service/video/stream-mng/server/grpc:all-srcs",
"//app/service/video/stream-mng/server/http:all-srcs",
"//app/service/video/stream-mng/service:all-srcs",
],
tags = ["automanaged"],
)

5
app/service/OWNERS Normal file
View File

@@ -0,0 +1,5 @@
# See the OWNERS docs at https://go.k8s.io/owners
labels:
- new-project
- service

3
app/service/README.md Normal file
View File

@@ -0,0 +1,3 @@
# go-common/app/service
提供RPC内部服务

28
app/service/bbq/BUILD Normal file
View File

@@ -0,0 +1,28 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/bbq/cms:all-srcs",
"//app/service/bbq/comment:all-srcs",
"//app/service/bbq/common:all-srcs",
"//app/service/bbq/notice-service:all-srcs",
"//app/service/bbq/push:all-srcs",
"//app/service/bbq/recsys:all-srcs",
"//app/service/bbq/recsys-recall:all-srcs",
"//app/service/bbq/search:all-srcs",
"//app/service/bbq/sys-msg:all-srcs",
"//app/service/bbq/topic:all-srcs",
"//app/service/bbq/user:all-srcs",
"//app/service/bbq/video:all-srcs",
"//app/service/bbq/video-image:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,2 @@
# Owner
daiwei

8
app/service/bbq/OWNERS Normal file
View File

@@ -0,0 +1,8 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- daiwei
labels:
- bbq
- new-project
- service

20
app/service/bbq/cms/BUILD Normal file
View File

@@ -0,0 +1,20 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/bbq/cms/cmd:all-srcs",
"//app/service/bbq/cms/internal/dao:all-srcs",
"//app/service/bbq/cms/internal/model:all-srcs",
"//app/service/bbq/cms/internal/server/http:all-srcs",
"//app/service/bbq/cms/internal/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,2 @@
### v1.0.0
1. 上线功能cms-service

View File

@@ -0,0 +1,6 @@
# Owner
jiangdongqi
# Author
# Reviewer

View File

@@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- jiangdongqi
labels:
- bbq
- service
- service/bbq/cms
options:
no_parent_owners: true

View File

@@ -0,0 +1,12 @@
# cms-service
## 项目简介
1.
## 编译环境
## 依赖包
## 编译执行

View File

@@ -0,0 +1,42 @@
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"],
importpath = "go-common/app/service/bbq/cms/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/cms/internal/server/http:go_default_library",
"//app/service/bbq/cms/internal/service:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/ecode/tip: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,48 @@
package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/bbq/cms/internal/server/http"
"go-common/app/service/bbq/cms/internal/service"
"go-common/library/conf/paladin"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
)
func main() {
flag.Parse()
if err := paladin.Init(); err != nil {
panic(err)
}
log.Init(nil) // debug flag: log.dir={path}
defer log.Close()
log.Info("cms-service start")
ecode.Init(nil)
svc := service.New()
httpSrv := http.New(svc)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
ctx, _ := context.WithTimeout(context.Background(), 35*time.Second)
httpSrv.Shutdown(ctx)
log.Info("cms-service exit")
svc.Close()
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,2 @@
# This is a TOML document. Boom

View File

View File

@@ -0,0 +1,4 @@
[server]
addr = "0.0.0.0:8000"
timeout = "1s"

View File

@@ -0,0 +1,13 @@
demoExpire = "24h"
[demo]
name = "cms"
proto = "tcp"
addr = "127.0.0.1:11211"
active = 50
idle = 10
dialTimeout = "100ms"
readTimeout = "200ms"
writeTimeout = "300ms"
idleTimeout = "80s"

View File

@@ -0,0 +1,11 @@
[demo]
addr = "127.0.0.1:3306"
dsn = "{user}:{password}@tcp(127.0.0.1:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"
readDSN = ["{user}:{password}@tcp(127.0.0.2:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8","{user}:{password}@tcp(127.0.0.3:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "200ms"
execTimeout = "300ms"
tranTimeout = "400ms"

View File

@@ -0,0 +1,13 @@
demoExpire = "24h"
[demo]
name = "cms"
proto = "tcp"
addr = "127.0.0.1:6389"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"

View File

@@ -0,0 +1,36 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/service/bbq/cms/internal/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/time: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,96 @@
package dao
import (
"context"
"time"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf/paladin"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
// Dao dao.
type Dao struct {
db *sql.DB
redis *redis.Pool
redisExpire int32
mc *memcache.Pool
mcExpire int32
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
// New new a dao and return.
func New() (dao *Dao) {
var (
dc struct {
Demo *sql.Config
}
rc struct {
Demo *redis.Config
DemoExpire xtime.Duration
}
mc struct {
Demo *memcache.Config
DemoExpire xtime.Duration
}
)
checkErr(paladin.Get("mysql.toml").UnmarshalTOML(&dc))
checkErr(paladin.Get("redis.toml").UnmarshalTOML(&rc))
checkErr(paladin.Get("memcache.toml").UnmarshalTOML(&mc))
dao = &Dao{
// mysql
db: sql.NewMySQL(dc.Demo),
// redis
redis: redis.NewPool(rc.Demo),
redisExpire: int32(time.Duration(rc.DemoExpire) / time.Second),
// memcache
mc: memcache.NewPool(mc.Demo),
mcExpire: int32(time.Duration(mc.DemoExpire) / time.Second),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.redis.Close()
d.db.Close()
}
// Ping ping the resource.
func (d *Dao) Ping(ctx context.Context) (err error) {
if err = d.pingMC(ctx); err != nil {
return
}
if err = d.pingRedis(ctx); err != nil {
return
}
return d.db.Ping(ctx)
}
func (d *Dao) pingMC(ctx context.Context) (err error) {
conn := d.mc.Get(ctx)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil {
log.Error("conn.Set(PING) error(%v)", err)
}
return
}
func (d *Dao) pingRedis(ctx context.Context) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if _, err = conn.Do("SET", "ping", "pong"); err != nil {
log.Error("conn.Set(PING) error(%v)", err)
}
return
}

View File

@@ -0,0 +1,28 @@
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/service/bbq/cms/internal/model",
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 @@
package model

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/service/bbq/cms/internal/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/cms/internal/service:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify: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,61 @@
package http
import (
"net/http"
"go-common/app/service/bbq/cms/internal/service"
"go-common/library/conf/paladin"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
svc *service.Service
)
// New new a bm server.
func New(s *service.Service) (engine *bm.Engine) {
var(
hc struct {
Server *bm.ServerConfig
}
)
if err := paladin.Get("http.toml").UnmarshalTOML(&hc); err != nil {
if err != paladin.ErrNotExist {
panic(err)
}
}
svc = s
engine = bm.DefaultServer(hc.Server)
initRouter(engine, verify.New(nil))
if err := engine.Start(); err != nil {
panic(err)
}
return
}
func initRouter(e *bm.Engine, v *verify.Verify) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/cms")
{
g.GET("/start", v.Verify, howToStart)
}
}
func ping(ctx *bm.Context) {
if err := svc.Ping(ctx); err != nil {
log.Error("ping error(%v)", err)
ctx.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}
// example for http request handler.
func howToStart(c *bm.Context) {
c.String(0, "Golang 大法好 !!!")
}

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 = ["service.go"],
importpath = "go-common/app/service/bbq/cms/internal/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/cms/internal/dao:go_default_library",
"//library/conf/paladin: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,37 @@
package service
import (
"context"
"go-common/app/service/bbq/cms/internal/dao"
"go-common/library/conf/paladin"
)
// Service service.
type Service struct {
ac *paladin.Map
dao *dao.Dao
}
// New new a service and return.
func New() (s *Service) {
var ac = new(paladin.TOML)
if err := paladin.Watch("application.toml", ac); err != nil {
panic(err)
}
s = &Service{
ac: ac,
dao: dao.New(),
}
return s
}
// Ping ping the resource.
func (s *Service) Ping(ctx context.Context) (err error) {
return s.dao.Ping(ctx)
}
// Close close the resource.
func (s *Service) Close() {
s.dao.Close()
}

View File

@@ -0,0 +1,22 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/bbq/comment/api:all-srcs",
"//app/service/bbq/comment/cmd:all-srcs",
"//app/service/bbq/comment/internal/dao:all-srcs",
"//app/service/bbq/comment/internal/model:all-srcs",
"//app/service/bbq/comment/internal/server/grpc:all-srcs",
"//app/service/bbq/comment/internal/server/http:all-srcs",
"//app/service/bbq/comment/internal/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,2 @@
### v1.0.0
1. 上线功能xxx

View File

@@ -0,0 +1,6 @@
# Owner
daiwei
# Author
# Reviewer

View File

@@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- daiwei
labels:
- bbq
- service
- service/bbq/comment
options:
no_parent_owners: true

View File

@@ -0,0 +1,12 @@
# comment-service
## 项目简介
1.
## 编译环境
## 依赖包
## 编译执行

View File

@@ -0,0 +1,63 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "api_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
deps = [
"@com_google_protobuf//:empty_proto",
"@gogo_special_proto//github.com/gogo/protobuf/gogoproto",
],
)
go_proto_library(
name = "api_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/bbq/comment/api",
proto = ":api_proto",
tags = ["automanaged"],
deps = [
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
go_library(
name = "go_default_library",
srcs = ["generate.go"],
embed = [":api_go_proto"],
importpath = "go-common/app/service/bbq/comment/api",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context: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,424 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: app/service/bbq/comment/api/api.proto
package api
/*
package 命名使用 {discovery_id}.{version} 的方式, version 形如 v1, v2, v1beta ..
NOTE: 不知道的 discovery_id 请询问大佬, 新项目找大佬申请 discovery_id先到先得抢注
e.g. account.service.v1
*/
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import empty "github.com/golang/protobuf/ptypes/empty"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
type HelloReq struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty" form:"name" validate:"required"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HelloReq) Reset() { *m = HelloReq{} }
func (m *HelloReq) String() string { return proto.CompactTextString(m) }
func (*HelloReq) ProtoMessage() {}
func (*HelloReq) Descriptor() ([]byte, []int) {
return fileDescriptor_api_5f2390e391fdee70, []int{0}
}
func (m *HelloReq) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *HelloReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_HelloReq.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (dst *HelloReq) XXX_Merge(src proto.Message) {
xxx_messageInfo_HelloReq.Merge(dst, src)
}
func (m *HelloReq) XXX_Size() int {
return m.Size()
}
func (m *HelloReq) XXX_DiscardUnknown() {
xxx_messageInfo_HelloReq.DiscardUnknown(m)
}
var xxx_messageInfo_HelloReq proto.InternalMessageInfo
func init() {
proto.RegisterType((*HelloReq)(nil), "demo.service.v1.HelloReq")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// DemoClient is the client API for Demo service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type DemoClient interface {
SayHello(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*empty.Empty, error)
}
type demoClient struct {
cc *grpc.ClientConn
}
func NewDemoClient(cc *grpc.ClientConn) DemoClient {
return &demoClient{cc}
}
func (c *demoClient) SayHello(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*empty.Empty, error) {
out := new(empty.Empty)
err := c.cc.Invoke(ctx, "/demo.service.v1.Demo/SayHello", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// DemoServer is the server API for Demo service.
type DemoServer interface {
SayHello(context.Context, *HelloReq) (*empty.Empty, error)
}
func RegisterDemoServer(s *grpc.Server, srv DemoServer) {
s.RegisterService(&_Demo_serviceDesc, srv)
}
func _Demo_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HelloReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DemoServer).SayHello(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/demo.service.v1.Demo/SayHello",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DemoServer).SayHello(ctx, req.(*HelloReq))
}
return interceptor(ctx, in, info, handler)
}
var _Demo_serviceDesc = grpc.ServiceDesc{
ServiceName: "demo.service.v1.Demo",
HandlerType: (*DemoServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "SayHello",
Handler: _Demo_SayHello_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/service/bbq/comment/api/api.proto",
}
func (m *HelloReq) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *HelloReq) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Name) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintApi(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
return i, nil
}
func encodeVarintApi(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *HelloReq) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + sovApi(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovApi(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozApi(x uint64) (n int) {
return sovApi(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *HelloReq) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApi
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: HelloReq: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: HelloReq: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApi
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthApi
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipApi(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthApi
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipApi(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApi
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApi
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApi
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthApi
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApi
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipApi(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowApi = fmt.Errorf("proto: integer overflow")
)
func init() {
proto.RegisterFile("app/service/bbq/comment/api/api.proto", fileDescriptor_api_5f2390e391fdee70)
}
var fileDescriptor_api_5f2390e391fdee70 = []byte{
// 251 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4d, 0x2c, 0x28, 0xd0,
0x2f, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0xd5, 0x4f, 0x4a, 0x2a, 0xd4, 0x4f, 0xce, 0xcf, 0xcd,
0x4d, 0xcd, 0x2b, 0xd1, 0x4f, 0x2c, 0xc8, 0x04, 0x61, 0xbd, 0x82, 0xa2, 0xfc, 0x92, 0x7c, 0x21,
0xfe, 0x94, 0xd4, 0xdc, 0x7c, 0x3d, 0xa8, 0x3a, 0xbd, 0x32, 0x43, 0x29, 0xdd, 0xf4, 0xcc, 0x92,
0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xf4, 0xfc, 0xf4, 0x7c, 0x7d, 0xb0, 0xba, 0xa4,
0xd2, 0x34, 0x30, 0x0f, 0xcc, 0x01, 0xb3, 0x20, 0xfa, 0xa5, 0xa4, 0xd3, 0xf3, 0xf3, 0xd3, 0x73,
0x52, 0x11, 0xaa, 0x52, 0x73, 0x0b, 0x4a, 0x2a, 0x21, 0x92, 0x4a, 0xce, 0x5c, 0x1c, 0x1e, 0xa9,
0x39, 0x39, 0xf9, 0x41, 0xa9, 0x85, 0x42, 0xe6, 0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c,
0x0a, 0x8c, 0x1a, 0x9c, 0x4e, 0xca, 0x9f, 0xee, 0xc9, 0xcb, 0xa7, 0xe5, 0x17, 0xe5, 0x5a, 0x29,
0x81, 0x44, 0x95, 0x14, 0xca, 0x12, 0x73, 0x32, 0x53, 0x12, 0x4b, 0x52, 0xad, 0x94, 0x8a, 0x52,
0x0b, 0x4b, 0x33, 0x8b, 0x52, 0x53, 0x94, 0x82, 0xc0, 0x1a, 0x8c, 0x5c, 0xb9, 0x58, 0x5c, 0x52,
0x73, 0xf3, 0x85, 0x6c, 0xb9, 0x38, 0x82, 0x13, 0x2b, 0xc1, 0xe6, 0x09, 0x49, 0xea, 0xa1, 0x39,
0x5b, 0x0f, 0x66, 0x8f, 0x94, 0x98, 0x1e, 0xc4, 0x45, 0x7a, 0x30, 0x17, 0xe9, 0xb9, 0x82, 0x5c,
0xe4, 0x24, 0x7a, 0xe2, 0xa1, 0x1c, 0xc3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e,
0x78, 0x24, 0xc7, 0x18, 0xc5, 0x9c, 0x58, 0x90, 0x99, 0xc4, 0x06, 0x56, 0x66, 0x0c, 0x08, 0x00,
0x00, 0xff, 0xff, 0xe5, 0xbd, 0x3d, 0x4d, 0x2f, 0x01, 0x00, 0x00,
}

View File

@@ -0,0 +1,37 @@
// 定义项目 API 的 proto 文件 可以同时描述 gRPC 和 HTTP API
// protobuf 文件参考:
// - https://developers.google.com/protocol-buffers/
// - http://info.bilibili.co/display/documentation/gRPC+Proto
// protobuf 生成 HTTP 工具:
// - http://git.bilibili.co/platform/go-common/tree/master/app/tool/protoc-gen-bm
// gRPC Golang Model:
// - http://info.bilibili.co/display/documentation/gRPC+Golang+Model
// gRPC Golang Warden Gen:
// - http://info.bilibili.co/display/documentation/gRPC+Golang+Warden+Gen
// gRPC http 调试工具(无需pb文件):
// - http://info.bilibili.co/pages/viewpage.action?pageId=12877366
// grpc 命令行调试工具(无需pb文件):
// - http://info.bilibili.co/pages/viewpage.action?pageId=11869411
syntax = "proto3";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "google/protobuf/empty.proto";
// package 命名使用 {discovery_id}.{version} 的方式, version 形如 v1, v2, v1beta ..
// NOTE: 不知道的 discovery_id 请询问大佬, 新项目找大佬申请 discovery_id先到先得抢注
// e.g. account.service.v1
package demo.service.v1;
// NOTE: 最后请删除这些无用的注释 (゜-゜)つロ
option go_package = "api";
// do not generate getXXX() method
option (gogoproto.goproto_getters_all) = false;
service Demo {
rpc SayHello (HelloReq) returns (.google.protobuf.Empty);
}
message HelloReq {
string name = 1 [(gogoproto.moretags)='form:"name" validate:"required"'];
}

View File

@@ -0,0 +1,4 @@
package api
// 生成 gRPC 代码
//go:generate $GOPATH/src/go-common/app/tool/warden/protoc.sh

View File

@@ -0,0 +1,43 @@
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"],
importpath = "go-common/app/service/bbq/comment/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/comment/internal/server/grpc:go_default_library",
"//app/service/bbq/comment/internal/server/http:go_default_library",
"//app/service/bbq/comment/internal/service:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/ecode/tip: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,51 @@
package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/bbq/comment/internal/server/grpc"
"go-common/app/service/bbq/comment/internal/server/http"
"go-common/app/service/bbq/comment/internal/service"
"go-common/library/conf/paladin"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
)
func main() {
flag.Parse()
if err := paladin.Init(); err != nil {
panic(err)
}
log.Init(nil) // debug flag: log.dir={path}
defer log.Close()
log.Info("comment-service start")
ecode.Init(nil)
svc := service.New()
grpcSrv := grpc.New(svc)
httpSrv := http.New(svc)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
ctx, cancel := context.WithTimeout(context.Background(), 35*time.Second)
defer cancel()
grpcSrv.Shutdown(ctx)
httpSrv.Shutdown(ctx)
log.Info("comment-service exit")
svc.Close()
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,2 @@
# This is a TOML document. Boom

View File

@@ -0,0 +1,4 @@
[server]
addr = "0.0.0.0:9000"
timeout = "1s"

View File

@@ -0,0 +1,4 @@
[server]
addr = "0.0.0.0:8000"
timeout = "1s"

View File

@@ -0,0 +1,13 @@
demoExpire = "24h"
[demo]
name = "comment"
proto = "tcp"
addr = "127.0.0.1:11211"
active = 50
idle = 10
dialTimeout = "100ms"
readTimeout = "200ms"
writeTimeout = "300ms"
idleTimeout = "80s"

View File

@@ -0,0 +1,11 @@
[demo]
addr = "127.0.0.1:3306"
dsn = "{user}:{password}@tcp(127.0.0.1:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"
readDSN = ["{user}:{password}@tcp(127.0.0.2:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8","{user}:{password}@tcp(127.0.0.3:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "200ms"
execTimeout = "300ms"
tranTimeout = "400ms"

View File

@@ -0,0 +1,13 @@
demoExpire = "24h"
[demo]
name = "comment"
proto = "tcp"
addr = "127.0.0.1:6389"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"

View File

@@ -0,0 +1,36 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/service/bbq/comment/internal/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/time: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 @@
package dao
import (
"context"
"time"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf/paladin"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
// Dao dao.
type Dao struct {
db *sql.DB
redis *redis.Pool
redisExpire int32
mc *memcache.Pool
mcExpire int32
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
// New new a dao and return.
func New() (dao *Dao) {
var (
dc struct {
Demo *sql.Config
}
rc struct {
Demo *redis.Config
DemoExpire xtime.Duration
}
mc struct {
Demo *memcache.Config
DemoExpire xtime.Duration
}
)
checkErr(paladin.Get("mysql.toml").UnmarshalTOML(&dc))
checkErr(paladin.Get("redis.toml").UnmarshalTOML(&rc))
checkErr(paladin.Get("memcache.toml").UnmarshalTOML(&mc))
dao = &Dao{
// mysql
db: sql.NewMySQL(dc.Demo),
// redis
redis: redis.NewPool(rc.Demo),
redisExpire: int32(time.Duration(rc.DemoExpire) / time.Second),
// memcache
mc: memcache.NewPool(mc.Demo),
mcExpire: int32(time.Duration(mc.DemoExpire) / time.Second),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.redis.Close()
d.db.Close()
}
// Ping ping the resource.
func (d *Dao) Ping(ctx context.Context) (err error) {
if err = d.pingMC(ctx); err != nil {
return
}
if err = d.pingRedis(ctx); err != nil {
return
}
return d.db.Ping(ctx)
}
func (d *Dao) pingMC(ctx context.Context) (err error) {
conn := d.mc.Get(ctx)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil {
log.Error("conn.Set(PING) error(%v)", err)
}
return
}
func (d *Dao) pingRedis(ctx context.Context) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if _, err = conn.Do("SET", "ping", "pong"); err != nil {
log.Error("conn.Set(PING) error(%v)", err)
}
return
}

View File

@@ -0,0 +1,28 @@
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/service/bbq/comment/internal/model",
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 @@
package model

View File

@@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/bbq/comment/internal/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/comment/api:go_default_library",
"//app/service/bbq/comment/internal/service:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/net/rpc/warden: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,27 @@
package grpc
import (
pb "go-common/app/service/bbq/comment/api"
"go-common/app/service/bbq/comment/internal/service"
"go-common/library/conf/paladin"
"go-common/library/net/rpc/warden"
)
// New new a grpc server.
func New(svc *service.Service) *warden.Server {
var rc struct {
Server *warden.ServerConfig
}
if err := paladin.Get("grpc.toml").UnmarshalTOML(&rc); err != nil {
if err != paladin.ErrNotExist {
panic(err)
}
}
ws := warden.NewServer(rc.Server)
pb.RegisterDemoServer(ws.Server(), svc)
ws, err := ws.Start()
if err != nil {
panic(err)
}
return ws
}

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/service/bbq/comment/internal/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/comment/internal/service:go_default_library",
"//library/conf/paladin:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify: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,61 @@
package http
import (
"net/http"
"go-common/app/service/bbq/comment/internal/service"
"go-common/library/conf/paladin"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
svc *service.Service
)
// New new a bm server.
func New(s *service.Service) (engine *bm.Engine) {
var (
hc struct {
Server *bm.ServerConfig
}
)
if err := paladin.Get("http.toml").UnmarshalTOML(&hc); err != nil {
if err != paladin.ErrNotExist {
panic(err)
}
}
svc = s
engine = bm.DefaultServer(hc.Server)
initRouter(engine, verify.New(nil))
if err := engine.Start(); err != nil {
panic(err)
}
return
}
func initRouter(e *bm.Engine, v *verify.Verify) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/comment")
{
g.GET("/start", v.Verify, howToStart)
}
}
func ping(ctx *bm.Context) {
if err := svc.Ping(ctx); err != nil {
log.Error("ping error(%v)", err)
ctx.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}
// example for http request handler.
func howToStart(c *bm.Context) {
c.String(0, "Golang 大法好 !!!")
}

View File

@@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["service.go"],
importpath = "go-common/app/service/bbq/comment/internal/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/comment/api:go_default_library",
"//app/service/bbq/comment/internal/dao:go_default_library",
"//library/conf/paladin:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
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,48 @@
package service
import (
"context"
"fmt"
pb "go-common/app/service/bbq/comment/api"
"go-common/app/service/bbq/comment/internal/dao"
"go-common/library/conf/paladin"
"github.com/golang/protobuf/ptypes/empty"
)
// Service service.
type Service struct {
ac *paladin.Map
dao *dao.Dao
}
// New new a service and return.
func New() (s *Service) {
var ac = new(paladin.TOML)
if err := paladin.Watch("application.toml", ac); err != nil {
panic(err)
}
s = &Service{
ac: ac,
dao: dao.New(),
}
return s
}
// SayHello grpc demo func.
func (s *Service) SayHello(ctx context.Context, req *pb.HelloReq) (reply *empty.Empty, err error) {
reply = new(empty.Empty)
fmt.Printf("hello %s", req.Name)
return
}
// Ping ping the resource.
func (s *Service) Ping(ctx context.Context) (err error) {
return s.dao.Ping(ctx)
}
// Close close the resource.
func (s *Service) Close() {
s.dao.Close()
}

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 = ["video_state.go"],
importpath = "go-common/app/service/bbq/common",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//library/xstr:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/bbq/common/db/bbq:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,5 @@
# v1.0.1
新增状态,同时修改注释
# v1.0.0
1. 上线功能xxx

View File

@@ -0,0 +1,11 @@
# Owner
luxiaowei
jiangdongqi
# Author
luxiaowei
jiangdongqi
# Reviewer
luxiaowei
jiangdongqi

View File

@@ -0,0 +1,14 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- jiangdongqi
- luxiaowei
labels:
- bbq
- common
- service/bbq/common
options:
no_parent_owners: true
reviewers:
- jiangdongqi
- luxiaowei

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["video_bvc.go"],
importpath = "go-common/app/service/bbq/common/db/bbq",
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,12 @@
package bbq
//VideoBvc ..
type VideoBvc struct {
SVID int64 `json:"svid"`
Path string `json:"path"`
ResolutionRetio string `json:"resolution_retio"`
CodeRate int16 `json:"code_rate"`
VideoCode string `json:"video_code"`
FileSize int64 `json:"file_size"`
Duration int64 `json:"duration"`
}

View File

@@ -0,0 +1,166 @@
package common
import "go-common/library/xstr"
/*
https://www.tapd.cn/66539426/prong/stories/view/1166539426001102539
state:
视频的状态有以下几种,如何选取合适的状态是该部分的关键
我们拆出了两个层次:业务层&详情层先通过业务层获取svid再从详情层获取svid的详情
详情层根据svid获取相应的视频base信息、play信息、user信息等
业务层根据不同的业务设置相应的state集合根据state去获取相应的svid当然这里也有两种业务层区分在于从其他服务获取svid这里还需要做个后过滤保证视频展示是正确的还是在video-c中获取
也就是说state的选出在于业务层而不是详情层需要业务层自己去保护而详情层在这里仅仅做一次较宽松的保证也就是完全不可见视频的过滤如下架状态
仅自己可见的状态说明:该状态可能在同一个业务场景出现主客态区分
个人空间根据是否主客态选择select的state
通知中心:选择所有可见视频,再根据当前视频是否属于自己可见进行过滤
//点赞列表:暂时不区分主客态
业务说明:
个人空间页:作品列表区分主客态
关注页:除自己可见外的所有状态
搜索:
推荐feed页
通知中心,含详情中转页:
评论
点赞
分享
*/
//视频状态集合
const (
//VideoStRecommend 精选在APP端加权露出
VideoStRecommend = 5
//VideoStHighGrade 优质回查被选为优质在APP端普通露出
VideoStHighGrade = 4
//VideoStCanPlay 回查可放出在APP端普通露出
VideoStCanPlay = 3
//VideoStCheckBack 待冷启动回查在APP端部分区域露出
VideoStCheckBack = 2
//VideoStPassReview 新鲜安全审核通过在APP端普通露出
VideoStPassReview = 1
//VideoStPendingPassReview 新鲜未安全审核在APP端普通露出
VideoStPendingPassReview = 0
//VideoStPassReviewReject 待安全审核在APP端仅自见
VideoStPassReviewReject = -1
//VideoStCheckBackPatialPlay 回查不放出在APP部分放出
VideoStCheckBackPatialPlay = -2
//VideoInActive 安全审核不通过在APP端不可见待物理删除
VideoInActive = -3
//VideoDeleted Up主删除在APP端不可见待物理删除
VideoDeleted = -4
)
//SvAllOutState APP全部可露出状态
var SvAllOutState = []int16{
VideoStPendingPassReview,
VideoStPassReview,
VideoStCanPlay,
VideoStHighGrade,
VideoStRecommend,
}
/*
以下用于最后根据svid获取详情时的过滤用于那些从其他服务获取svid的业务推荐页、搜索页、点赞列表等
*/
// IsSvStateAvailable 广义上是否可见包含用户自见state用于获取详情当前和owner available一致
func IsSvStateAvailable(state int64) (available bool) {
return IsSvStateOwnerAvailable(state)
}
// IsSvStateGuestAvailable 客态可见的视频状态
func IsSvStateGuestAvailable(state int64) (available bool) {
_, available = svGuestAvailableState[state]
return
}
// IsSvStateOwnerAvailable 主态可见的视频状态
func IsSvStateOwnerAvailable(state int64) (available bool) {
if state == VideoStPassReviewReject {
return true
}
return IsSvStateGuestAvailable(state)
}
// IsRecommendSvStateAvailable 推荐页中的状态过滤
func IsRecommendSvStateAvailable(state int64) (available bool) {
_, available = svRecommendAvailableState[state]
return
}
// IsSearchSvStateAvailable 搜索页中的状态过滤
func IsSearchSvStateAvailable(state int64) (available bool) {
// 暂时复用推荐
return IsRecommendSvStateAvailable(state)
}
// IsTopicSvStateAvailable 话题页中的状态过滤
func IsTopicSvStateAvailable(state int64) (available bool) {
// 暂时复用推荐
return IsRecommendSvStateAvailable(state)
}
var svGuestAvailableState = map[int64]bool{
VideoStCheckBackPatialPlay: true,
VideoStPendingPassReview: true,
VideoStPassReview: true,
VideoStCanPlay: true,
VideoStHighGrade: true,
VideoStRecommend: true,
VideoStCheckBack: true,
}
var svRecommendAvailableState = map[int64]bool{
VideoStPendingPassReview: true,
VideoStPassReview: true,
VideoStCanPlay: true,
VideoStHighGrade: true,
VideoStRecommend: true,
}
/*
以下用于业务逻辑在select语句中state in用于video-c服务中自己进行选取svid的业务关注页、个人空间页
*/
// FeedStates .
var FeedStates = xstr.JoinInts(svFeedOutStates)
// SpaceOwnerStates .
var SpaceOwnerStates = xstr.JoinInts(svSpaceOwnerOutStates)
// SpaceFanStates .
var SpaceFanStates = xstr.JoinInts(svSpaceFanOutStates)
// svFeedOutStates .
var svFeedOutStates = []int64{
VideoStCheckBackPatialPlay,
VideoStPendingPassReview,
VideoStPassReview,
VideoStCanPlay,
VideoStHighGrade,
VideoStRecommend,
VideoStCheckBack,
}
// svSpaceOwnerOutStates .
var svSpaceOwnerOutStates = []int64{
VideoStPassReviewReject,
VideoStCheckBackPatialPlay,
VideoStPendingPassReview,
VideoStPassReview,
VideoStCanPlay,
VideoStHighGrade,
VideoStRecommend,
VideoStCheckBack,
}
// svSpaceFanOutStates .
var svSpaceFanOutStates = []int64{
VideoStCheckBackPatialPlay,
VideoStPendingPassReview,
VideoStPassReview,
VideoStCanPlay,
VideoStHighGrade,
VideoStRecommend,
VideoStCheckBack,
}

View File

@@ -0,0 +1,23 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/bbq/notice-service/api/v1:all-srcs",
"//app/service/bbq/notice-service/cmd:all-srcs",
"//app/service/bbq/notice-service/internal/conf:all-srcs",
"//app/service/bbq/notice-service/internal/dao:all-srcs",
"//app/service/bbq/notice-service/internal/model:all-srcs",
"//app/service/bbq/notice-service/internal/server/grpc:all-srcs",
"//app/service/bbq/notice-service/internal/server/http:all-srcs",
"//app/service/bbq/notice-service/internal/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,21 @@
### v1.0.6
后台审核通知不发送push
### v1.0.5
推送文案修改
### v1.0.4
push schema -> shceme
### v1.0.3
把create_notice的接口改成form格式
### v1.0.2
1. fix 系统消息推送通知
### v1.0.1
1. 第三方推送接口超时,改用异步
### v1.0.0
1. BBQ通知中心
2. BBQ消息推送

View File

@@ -0,0 +1,7 @@
# Owner
luxiaowei
daiwei
# Author
# Reviewer

View File

@@ -0,0 +1,11 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- daiwei
- luxiaowei
labels:
- bbq
- service
- service/bbq/notice-service
options:
no_parent_owners: true

View File

@@ -0,0 +1,12 @@
# notice-service-service
## 项目简介
1.
## 编译环境
## 依赖包
## 编译执行

View File

@@ -0,0 +1,65 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "v1_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
deps = [
"@com_google_protobuf//:empty_proto",
"@gogo_special_proto//github.com/gogo/protobuf/gogoproto",
],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/bbq/notice-service/api/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
go_library(
name = "go_default_library",
srcs = ["common.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/bbq/notice-service/api/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context: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"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,113 @@
syntax = "proto3";
package bbq.service.notice.v1;
import "google/protobuf/empty.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
message GetUnreadInfoRequest {
// 用户mid
int64 mid = 1 [(gogoproto.jsontag) = "mid", (gogoproto.moretags)='form:"mid" validate:"required"'];
}
message UnreadInfo {
// 用户mid
repeated UnreadItem list = 1[(gogoproto.jsontag) = "list,omitempty"];
}
message UnreadItem {
int32 notice_type = 1 [(gogoproto.jsontag) = "notice_type"];
int64 unread_num = 2[(gogoproto.jsontag) = "unread_num"];
}
message ListNoticesReq {
// 用户mid
int64 mid = 1 [(gogoproto.jsontag) = "mid", (gogoproto.moretags)='form:"mid" validate:"required"'];
int32 notice_type = 2 [(gogoproto.jsontag) = "notice_type", (gogoproto.moretags)='form:"notice_type" validate:"required"'];
int64 cursor_id = 3 [(gogoproto.jsontag) = "cursor_id", (gogoproto.moretags)='form:"cursor_id"'];
}
message ListNoticesReply {
// 用户mid
int64 mid = 1 [(gogoproto.jsontag) = "mid"];
repeated NoticeBase list = 2[(gogoproto.jsontag) = "list,omitempty"];
}
message NoticeBase {
int64 id = 1 [(gogoproto.jsontag) = "id"];
int64 mid = 2 [(gogoproto.jsontag) = "mid", (gogoproto.moretags)='form:"mid" validate:"required"'];
int64 action_mid = 3 [(gogoproto.jsontag) = "action_mid", (gogoproto.moretags)='form:"action_mid"'];
int64 sv_id = 4 [(gogoproto.jsontag) = "svid", (gogoproto.moretags)='form:"svid"'];
string title = 5 [(gogoproto.jsontag) = "title", (gogoproto.moretags)='form:"title"'];
string text = 6 [(gogoproto.jsontag) = "text", (gogoproto.moretags)='form:"text"'];
string jump_url = 7 [(gogoproto.jsontag) = "jump_url", (gogoproto.moretags)='form:"jump_url"'];
int32 notice_type = 8 [(gogoproto.jsontag) = "notice_type", (gogoproto.moretags)='form:"notice_type" validate:"required"'];
int32 biz_type = 9 [(gogoproto.jsontag) = "biz_type", (gogoproto.moretags)='form:"biz_type"'];
int64 biz_id = 10 [(gogoproto.jsontag) = "biz_id", (gogoproto.moretags)='form:"biz_id"'];
int64 notice_time = 11 [(gogoproto.jsontag) = "notice_time", (gogoproto.casttype) = "go-common/library/time.Time"];
string buvid = 12 [(gogoproto.jsontag) = "buvid", (gogoproto.moretags)='form:"buvid"'];
}
message CreateNoticesReq {
repeated NoticeBase notices = 1 [(gogoproto.jsontag) = "notices", (gogoproto.moretags)='form:"notices" validate:"required"'];
}
message CreateNoticesReply {
// 失败的列表
repeated int64 fail_list = 2 [(gogoproto.jsontag) = "fail_list"];
}
message PushCallbackRequest {
string tid = 1 [(gogoproto.jsontag) = "tid", (gogoproto.moretags)='form:"tid" validate:"required"'];
string nid = 2 [(gogoproto.jsontag) = "nid", (gogoproto.moretags)='form:"nid" validate:"required"'];
int64 mid = 3 [(gogoproto.jsontag) = "mid", (gogoproto.moretags)='form:"mid"'];
string buvid = 4 [(gogoproto.jsontag) = "buvid", (gogoproto.moretags)='form:"buvid"'];
}
message UserPushDev {
int64 id = 1 [(gogoproto.jsontag) = "id"];
int64 mid = 2 [(gogoproto.jsontag) = "mid", (gogoproto.moretags)='form:"mid"'];
string register_id = 3 [(gogoproto.jsontag) = "register_id", (gogoproto.moretags)='form:"register_id"'];
string buvid = 4 [(gogoproto.jsontag) = "buvid", (gogoproto.moretags)='form:"buvid"'];
int32 sdk = 5 [(gogoproto.jsontag) = "sdk", (gogoproto.moretags)='form:"sdk"', (gogoproto.casttype) = "int8"];
int32 platform = 6 [(gogoproto.jsontag) = "platform", (gogoproto.moretags)='form:"platform"', (gogoproto.casttype) = "int8"];
int32 state = 7 [(gogoproto.jsontag) = "state", (gogoproto.moretags)='form:"state"', (gogoproto.casttype) = "int8"];
int64 last_login_time = 8 [(gogoproto.jsontag) = "last_login_time", (gogoproto.moretags)='form:"last_login_time"', (gogoproto.casttype) = "go-common/library/time.Time"];
int64 ctime = 9 [(gogoproto.jsontag) = "ctime", (gogoproto.casttype) = "go-common/library/time.Time"];
int64 mtime = 10[(gogoproto.jsontag) = "mtime", (gogoproto.casttype) = "go-common/library/time.Time"];
}
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
//还记得那年大明湖畔的东起吗
service Notice {
// 获取所有通知类型的未读数
rpc GetUnreadInfo(GetUnreadInfoRequest) returns (UnreadInfo);
// 获取通知列表
rpc ListNotices(ListNoticesReq) returns (ListNoticesReply);
// 批量创建消息
rpc CreateNotice(NoticeBase) returns (.google.protobuf.Empty);
// 推送回调
rpc PushCallback(PushCallbackRequest) returns (.google.protobuf.Empty);
// Push的login接口
rpc PushLogin(UserPushDev) returns (.google.protobuf.Empty);
// Push的logout接口
rpc PushLogout(UserPushDev) returns (.google.protobuf.Empty);
}

View File

@@ -0,0 +1,17 @@
package v1
// 通知的业务类型
const (
NoticeBizTypeSv = 1
NoticeBizTypeComment = 2
NoticeBizTypeUser = 3
NoticeBizTypeAudit = 4
)
// 通知类型
const (
NoticeTypeLike = 1
NoticeTypeComment = 2
NoticeTypeFan = 3
NoticeTypeSysMsg = 4
)

View File

@@ -0,0 +1,48 @@
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 = ["test.toml"],
importpath = "go-common/app/service/bbq/notice-service/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/notice-service/internal/conf:go_default_library",
"//app/service/bbq/notice-service/internal/server/grpc:go_default_library",
"//app/service/bbq/notice-service/internal/server/http:go_default_library",
"//app/service/bbq/notice-service/internal/service:go_default_library",
"//library/ecode/tip: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",
"//app/service/bbq/notice-service/cmd/client:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "client",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
importpath = "go-common/app/service/bbq/notice-service/cmd/client",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/notice-service/api/v1:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/time: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,51 @@
package main
import (
"context"
"flag"
"fmt"
"log"
"time"
"go-common/app/service/bbq/notice-service/api/v1"
"go-common/library/net/rpc/warden"
xtime "go-common/library/time"
)
var (
addr string
)
func init() {
flag.StringVar(&addr, "addr", "127.0.0.1:9003", "server addr")
}
func main() {
flag.Parse()
cfg := &warden.ClientConfig{
Dial: xtime.Duration(time.Second * 3),
Timeout: xtime.Duration(time.Second * 3),
}
cc, err := warden.NewClient(cfg).Dial(context.Background(), addr)
if err != nil {
log.Fatalf("new client failed!err:=%v", err)
return
}
client := v1.NewNoticeClient(cc)
req := &v1.NoticeBase{
Mid: 69121924,
ActionMid: 111001917,
SvId: 0,
Title: "关注了你",
Text: "",
JumpUrl: "",
NoticeType: 3,
BizType: 3,
BizId: 0,
NoticeTime: xtime.Time(time.Now().Unix()),
Buvid: "XYDEB30D9F184E3F3EE7536645CB7188E7143",
}
resp, err := client.CreateNotice(context.Background(), req)
fmt.Println(resp, err)
}

View File

@@ -0,0 +1,51 @@
package main
import (
"context"
"flag"
"go-common/app/service/bbq/notice-service/internal/server/grpc"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/bbq/notice-service/internal/conf"
"go-common/app/service/bbq/notice-service/internal/server/http"
"go-common/app/service/bbq/notice-service/internal/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("notice-service-service start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
svc := service.New(conf.Conf)
grpcServ := grpc.New(conf.Conf.GRPC, svc)
http.Init(conf.Conf, svc)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
svc.Close()
grpcServ.Shutdown(context.Background())
log.Info("notice-service-service exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,84 @@
[log]
stdout = true
# dir = "./log/bbq"
v = 5
[grpc]
timeout = "500ms"
addr = "0.0.0.0:9003"
[bm]
addr = "0.0.0.0:8802"
timeout = "2s"
[mysql]
addr = "172.16.38.91:3306"
dsn = "root:123456@tcp(172.16.38.91:3306)/bbq?allowNativePasswords=true&timeout=800ms&readTimeout=1200ms&writeTimeout=800ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
readDSN = ["root:123456@tcp(172.16.38.91:3306)/bbq?allowNativePasswords=true&timeout=800ms&readTimeout=1200ms&writeTimeout=800ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "2000ms"
execTimeout = "2000ms"
tranTimeout = "3000ms"
[redis]
name = "bbq-web"
proto = "tcp"
addr = "172.16.38.91:6379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "1m"
[gRPCClient]
[gRPCClient.push]
addr = "172.16.38.91:9093"
[gRPCClient.push.wardenconf]
dial = "100ms"
timeout = "500ms"
[l1PushStrategy]
[l1PushStrategy.like]
t = 1
a = -1
b = -1
[l1PushStrategy.comment]
t = 1
a = -1
b = -1
[l1PushStrategy.follow]
t = 1
a = -1
b = -1
[l1PushStrategy.sysmsg]
t = -1
a = -1
b = -1
[l2PushStrategy]
[l2PushStrategy.like]
t = 1
a = -1
b = 5
[l2PushStrategy.comment]
t = 1
a = -1
b = 5
[l2PushStrategy.follow]
t = 1
a = -1
b = 5
[l2PushStrategy.sysmsg]
t = 1
a = -1
b = -1
[infoc]
taskID = "001730"
proto = "tcp"
addr = "172.18.33.124:15140"
chanSize = 10240

View File

@@ -0,0 +1,41 @@
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/service/bbq/notice-service/internal/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace: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,106 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/log/infoc"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Verify *verify.Config
Tracer *trace.Config
MySQL *sql.Config
Redis *redis.Config
Ecode *ecode.Config
GRPC *warden.ServerConfig
GRPCClient map[string]*GRPCClientConfig
L1PushStrategy map[string]*PushStrategy
L2PushStrategy map[string]*PushStrategy
Infoc *infoc.Config
}
// GRPCClientConfig .
type GRPCClientConfig struct {
WardenConf *warden.ClientConfig
Addr string
}
// PushStrategy .
type PushStrategy struct {
T int
A int
B int
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
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,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"push.go",
"user.go",
],
importpath = "go-common/app/service/bbq/notice-service/internal/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/notice-service/api/v1:go_default_library",
"//app/service/bbq/notice-service/internal/conf:go_default_library",
"//app/service/bbq/push/api/grpc/v1:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc/warden: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,184 @@
package dao
import (
"context"
"fmt"
"go-common/app/service/bbq/notice-service/api/v1"
"go-common/app/service/bbq/notice-service/internal/conf"
push "go-common/app/service/bbq/push/api/grpc/v1"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
"go-common/library/log"
"go-common/library/net/rpc/warden"
)
const (
_listSQL = "select id, mid, action_mid, svid, notice_type, title, text, jump_url, biz_type, biz_id, ctime from notice_%02d where mid = ? and notice_type = ? and id < ? order by id desc limit %d"
_insertSQL = "insert into notice_%02d (mid, action_mid, svid, notice_type, title, text, jump_url, biz_type, biz_id) values (?,?,?,?,?,?,?,?,?)"
_noticeLen = 10
_redisUnreadKey = "notice:unread:%d"
_redisExpireTime = 7776000 // 90days
)
// Dao dao
type Dao struct {
c *conf.Config
db *xsql.DB
redis *redis.Pool
pushClient push.PushClient
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
db: xsql.NewMySQL(c.MySQL),
redis: redis.NewPool(c.Redis),
pushClient: newPushClient(c.GRPCClient["push"]),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(ctx context.Context) error {
// TODO: add mc,redis... if you use
return d.db.Ping(ctx)
}
func getTableIndex(id int64) int64 {
return id % 100
}
// newPushClient .
func newPushClient(cfg *conf.GRPCClientConfig) push.PushClient {
cc, err := warden.NewClient(cfg.WardenConf).Dial(context.Background(), cfg.Addr)
if err != nil {
panic(err)
}
return push.NewPushClient(cc)
}
// ListNotices 获取通知列表
func (d *Dao) ListNotices(ctx context.Context, mid, cursorID int64, noticeType int32) (list []*v1.NoticeBase, err error) {
querySQL := fmt.Sprintf(_listSQL, getTableIndex(mid), _noticeLen)
log.V(1).Infov(ctx, log.KV("mid", mid), log.KV("mid", mid), log.KV("notice_type", noticeType), log.KV("cursor_id", cursorID), log.KV("sql", querySQL))
rows, err := d.db.Query(ctx, querySQL, mid, noticeType, cursorID)
if err != nil {
log.Errorv(ctx, log.KV("log", "query mysql notice list fail"), log.KV("sql", querySQL), log.KV("mid", mid), log.KV("biz_type", noticeType), log.KV("cursor_id", cursorID))
return
}
defer rows.Close()
for rows.Next() {
var notice v1.NoticeBase
if err = rows.Scan(&notice.Id, &notice.Mid, &notice.ActionMid, &notice.SvId, &notice.NoticeType, &notice.Title, &notice.Text, &notice.JumpUrl, &notice.BizType, &notice.BizId, &notice.NoticeTime); err != nil {
log.Errorv(ctx, log.KV("log", "scan mysql notice list fail"), log.KV("sql", querySQL), log.KV("mid", mid), log.KV("biz_type", noticeType), log.KV("mid", mid), log.KV("cursor_id", cursorID))
return
}
list = append(list, &notice)
}
// 只要用户读取数据,即清理未读数
conn := d.redis.Get(ctx)
defer conn.Close()
redisKey := fmt.Sprintf(_redisUnreadKey, mid)
if _, tmpErr := conn.Do("HSET", redisKey, noticeType, 0); tmpErr != nil {
log.Warnv(ctx, log.KV("log", "clear unread info redis fail: key="+redisKey))
}
log.V(1).Infov(ctx, log.KV("req_size", _noticeLen), log.KV("rsp_size", len(list)))
return
}
// CreateNotice 创建通知
func (d *Dao) CreateNotice(ctx context.Context, notice *v1.NoticeBase) (id int64, err error) {
querySQL := fmt.Sprintf(_insertSQL, getTableIndex(notice.Mid))
res, err := d.db.Exec(ctx, querySQL, notice.Mid, notice.ActionMid, notice.SvId, notice.NoticeType, notice.Title, notice.Text, notice.JumpUrl, notice.BizType, notice.BizId)
if err != nil {
log.Errorv(ctx, log.KV("log", "exec mysql fail: create notice"), log.KV("sql", querySQL))
return
}
id, _ = res.LastInsertId()
return
}
// IncreaseUnread 增加未读
func (d *Dao) IncreaseUnread(ctx context.Context, mid int64, noticeType int32, num int64) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
redisKey := fmt.Sprintf(_redisUnreadKey, mid)
expireResult, _ := redis.Int(conn.Do("EXPIRE", redisKey, _redisExpireTime))
if expireResult == 0 {
log.Infov(ctx, log.KV("log", "expire fail: key="+redisKey))
}
_, err = conn.Do("HINCRBY", redisKey, noticeType, num)
if err != nil {
log.Errorv(ctx, log.KV("log", "HINCRBY notice unread fail: err="+err.Error()))
return
}
log.V(1).Infov(ctx, log.KV("log", "hincrby notice unread : key="+redisKey), log.KV("notice_type", noticeType), log.KV("num", num))
return
}
// ClearUnread 清理未读
func (d *Dao) ClearUnread(ctx context.Context, mid int64, noticeType int32) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
redisKey := fmt.Sprintf(_redisUnreadKey, mid)
expireResult, _ := redis.Int(conn.Do("EXPIRE", redisKey, _redisExpireTime))
if expireResult == 0 {
log.Infov(ctx, log.KV("log", "expire fail and return: key="+redisKey))
return
}
_, err = conn.Do("HSET", redisKey, noticeType, 0)
if err != nil {
log.Errorv(ctx, log.KV("log", "HSET notice unread fail: err="+err.Error()))
return
}
log.V(1).Infov(ctx, log.KV("log", "HSET clear notice unread : key="+redisKey), log.KV("notice_type", noticeType))
// 清理推送用户
err = d.ClearPushActionMid(ctx, mid, noticeType)
if err != nil {
log.Errorv(ctx, log.KV("log", "ClearPushActionMid fail: err="+err.Error()))
return
}
return
}
// GetUnreadInfo 获取未读情况
func (d *Dao) GetUnreadInfo(ctx context.Context, mid int64) (list []*v1.UnreadItem, err error) {
redisKey := fmt.Sprintf(_redisUnreadKey, mid)
conn := d.redis.Get(ctx)
defer conn.Close()
expireResult, _ := redis.Int(conn.Do("EXPIRE", redisKey, _redisExpireTime))
if expireResult == 0 {
log.V(1).Infov(ctx, log.KV("log", "expire fail: key="+redisKey))
return
}
result, err := redis.Int64s(conn.Do("HMGET", redisKey, 1, 2, 3, 4))
if err != nil {
log.Errorv(ctx, log.KV("log", "hmget notice unread fail: err="+err.Error()))
return
}
for i, val := range result {
var item v1.UnreadItem
item.NoticeType = int32(i + 1)
item.UnreadNum = val
list = append(list, &item)
}
return
}

View File

@@ -0,0 +1,225 @@
package dao
import (
"context"
"database/sql"
"fmt"
"strconv"
"strings"
"time"
"go-common/app/service/bbq/notice-service/api/v1"
push "go-common/app/service/bbq/push/api/grpc/v1"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_queryUserPushDev = "select `reg_id`, `sdk`, `platform` from `user_push_device` where `mid` = ? and `state` = 0 order by `last_login_time` desc limit 1;"
_queryUserName = "select `uname` from `user_base` where mid in %s;"
)
// PushNotice .
func (d *Dao) PushNotice(c context.Context, req *push.NotificationRequest) (result []*push.PushResult, err error) {
resp, err := d.pushClient.AsyncNotification(c, req)
if err != nil {
log.Errorv(c, log.KV("log", "push notification error"), log.KV("error", err))
return
}
result = resp.Result
for _, item := range result {
if item.Error != nil {
log.Errorv(c, log.KV("log", "push device notifiaction error"), log.KV("error", item.Error))
}
}
return
}
// PushMessage .
func (d *Dao) PushMessage(c context.Context, req *push.MessageRequest) (result []*push.PushResult, err error) {
resp, err := d.pushClient.AsyncMessage(c, req)
if err != nil {
log.Errorv(c, log.KV("log", "push message error"), log.KV("error", err))
return
}
result = resp.Result
for _, item := range result {
if item.Error != nil {
log.Errorv(c, log.KV("log", "push device message error"), log.KV("error", item.Error))
}
}
return nil, err
}
// FetchPushDev .
func (d *Dao) FetchPushDev(c context.Context, mid int64) (result *push.Device, err error) {
result = &push.Device{}
err = d.db.QueryRow(c, _queryUserPushDev, mid).Scan(&result.RegisterID, &result.SDK, &result.Platform)
if err == sql.ErrNoRows {
err = nil
log.Warnw(c, "log", "no row in push", "sql", _queryUserPushDev, "mid", mid)
}
return
}
// IncrDailyPushCount .
func (d *Dao) IncrDailyPushCount(c context.Context, mid int64) (count int, err error) {
dt := time.Now().Format("20060102")
key := fmt.Sprintf("bbq:push:u:%d:%s:count", mid, dt)
conn := d.redis.Get(c)
defer conn.Close()
count, err = redis.Int(conn.Do("INCR", key, 1))
if err != nil {
return
}
_, err = conn.Do("EXPIRE", 86400)
return
}
// IncrHourPushAction .
func (d *Dao) IncrHourPushAction(c context.Context, mid int64, noticeType int32, t int) (count int, err error) {
dt := time.Now().Format("2006010215")
key := fmt.Sprintf("bbq:push:u:%d:%s:action:%d", mid, dt, noticeType)
conn := d.redis.Get(c)
defer conn.Close()
count, err = redis.Int(conn.Do("INCR", key))
if err != nil {
return
}
_, err = conn.Do("EXPIRE", t)
return
}
// ClearHourPushAction .
func (d *Dao) ClearHourPushAction(c context.Context, mid int64, noticeType int32) error {
dt := time.Now().Format("2006010215")
key := fmt.Sprintf("bbq:push:u:%d:%s:action:%d", mid, dt, noticeType)
conn := d.redis.Get(c)
defer conn.Close()
_, err := conn.Do("DEL", key)
return err
}
// SetPushActionMid .
func (d *Dao) SetPushActionMid(c context.Context, mid int64, actionMid int64, noticeType int32) error {
dt := time.Now().Format("2006010215")
key := fmt.Sprintf("bbq:v1:push:u:%d:%s:action:%d", mid, dt, noticeType)
conn := d.redis.Get(c)
defer conn.Close()
values, _ := redis.Values(conn.Do("HGETALL", key))
if len(values) >= 4 {
return nil
}
_, err := conn.Do("HMSET", key, actionMid, actionMid)
return err
}
// GetPushActionMid .
func (d *Dao) GetPushActionMid(c context.Context, mid int64, noticeType int32) ([]int64, error) {
dt := time.Now().Format("2006010215")
key := fmt.Sprintf("bbq:v1:push:u:%d:%s:action:%d", mid, dt, noticeType)
conn := d.redis.Get(c)
defer conn.Close()
m, err := redis.Int64Map(conn.Do("HGETALL", key))
if err != nil {
return nil, err
}
result := make([]int64, 0)
for _, v := range m {
result = append(result, v)
}
return result, nil
}
// ClearPushActionMid .
func (d *Dao) ClearPushActionMid(c context.Context, mid int64, noticeType int32) error {
conn := d.redis.Get(c)
defer conn.Close()
dt := time.Now().Format("2006010215")
key := fmt.Sprintf("bbq:v1:push:u:%d:%s:action:%d", mid, dt, noticeType)
_, err := conn.Do("DEL", key)
return err
}
// GetUserName .
func (d *Dao) GetUserName(c context.Context, midList []int64, count int) (names []string, err error) {
mids := []string{}
list := midList
if len(midList) > count {
list = midList[:count]
}
for _, v := range list {
mids = append(mids, strconv.Itoa(int(v)))
}
where := "(" + strings.Join(mids, ",") + ")"
row, err := d.db.Query(c, fmt.Sprintf(_queryUserName, where))
if err != nil {
return
}
for row.Next() {
n := ""
err = row.Scan(&n)
if err != nil {
return
}
names = append(names, n)
}
return
}
// FetchUserPushDev .
func (d *Dao) FetchUserPushDev(c context.Context, mid int64, buvid string) (result *v1.UserPushDev, err error) {
querySQL := "select `id` from `user_push_device` where `mid` = ? and `buvid` = ?"
row := d.db.QueryRow(c, querySQL, mid, buvid)
result = &v1.UserPushDev{}
row.Scan(&result.Id)
return
}
// InsertUserPushDev .
func (d *Dao) InsertUserPushDev(c context.Context, req *v1.UserPushDev) (int64, error) {
_insertUserPushDev := "insert into `user_push_device` (`mid`, `reg_id`, `buvid`, `sdk`, `platform`) values (?, ?, ?, ?, ?);"
result, err := d.db.Exec(c, _insertUserPushDev, req.Mid, req.RegisterId, req.Buvid, req.Sdk, req.Platform)
if err != nil {
return 0, err
}
return result.LastInsertId()
}
// UpdateUserPushDev .
func (d *Dao) UpdateUserPushDev(c context.Context, req *v1.UserPushDev) (int64, error) {
_updateUserPushDev := "update `user_push_device` set `reg_id`=?,`sdk`=?,`platform`=?,`state`=?,`last_login_time`=now() where `mid`=? and `buvid`=?"
result, err := d.db.Exec(c, _updateUserPushDev, req.RegisterId, req.Sdk, req.Platform, req.State, req.Mid, req.Buvid)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
// DeleteUserPushDev .
func (d *Dao) DeleteUserPushDev(c context.Context, req *v1.UserPushDev) (int64, error) {
_updateUserPushDev := "update `user_push_device` set `state`=1 where `mid`=? and `buvid`=?"
result, err := d.db.Exec(c, _updateUserPushDev, req.Mid, req.Buvid)
if err != nil {
return 0, err
}
return result.RowsAffected()
}

View File

@@ -0,0 +1,16 @@
package dao
import (
"context"
)
const (
_queryUserFansNum = "select `fan_total` from `user_statistics` where mid = ?;"
)
// FetchUserFansNum .
func (d *Dao) FetchUserFansNum(c context.Context, mid int64) (num int, err error) {
row := d.db.QueryRow(c, _queryUserFansNum, mid)
err = row.Scan(&num)
return
}

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",
"push.go",
],
importpath = "go-common/app/service/bbq/notice-service/internal/model",
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 @@
package model

View File

@@ -0,0 +1,34 @@
package model
// 推送消息类型
const (
NoticeTypeLike = 1
NoticeTypeComment = 2
NoticeTypeFan = 3
NoticeTypeSysMsg = 4
)
// 推送业务类型
const (
NoticeBizTypeSv = 1
NoticeBizTypeComment = 2
NoticeBizTypeUser = 3
NoticeBizTypeCmsReview = 4
)
// 推送文案
const (
PushMsgVideoLike = "%s%s赞了你的作品"
PushMsgVideoComment = "%s%s评论了你的作品"
PushMsgCommentLike = "%s%s赞了你的评论"
PushMsgCommentReply = "%s%s回复了你的评论"
PushMsgFollow = "%s%s关注了你"
)
// 推送跳转schema
const (
PushSchemaVideo = "qing://videoplayer?svid=%d"
PushSchemaComment = "qing://commentdetail?svid=%d&rootid=%s"
PushSchemaUser = "qing://profile?mid=%d"
PushSchemaNotice = "qing://notification?type=%d"
)

View File

@@ -0,0 +1,33 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/bbq/notice-service/internal/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/notice-service/api/v1:go_default_library",
"//app/service/bbq/notice-service/internal/service:go_default_library",
"//library/net/rpc/warden: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,18 @@
package grpc
import (
pb "go-common/app/service/bbq/notice-service/api/v1"
"go-common/app/service/bbq/notice-service/internal/service"
"go-common/library/net/rpc/warden"
)
// New new warden rpc server
func New(c *warden.ServerConfig, svc *service.Service) *warden.Server {
ws := warden.NewServer(c)
pb.RegisterNoticeServer(ws.Server(), svc)
ws, err := ws.Start()
if err != nil {
panic(err)
}
return ws
}

View File

@@ -0,0 +1,37 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/service/bbq/notice-service/internal/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/notice-service/api/v1:go_default_library",
"//app/service/bbq/notice-service/internal/conf:go_default_library",
"//app/service/bbq/notice-service/internal/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//vendor/github.com/pkg/errors: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,106 @@
package http
import (
"net/http"
"github.com/pkg/errors"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/app/service/bbq/notice-service/api/v1"
"go-common/app/service/bbq/notice-service/internal/conf"
"go-common/app/service/bbq/notice-service/internal/service"
)
var (
vfy *verify.Verify
svc *service.Service
)
// Init init
func Init(c *conf.Config, s *service.Service) {
svc = s
vfy = verify.New(c.Verify)
engine := bm.DefaultServer(c.BM)
route(engine)
if err := engine.Start(); err != nil {
log.Error("bm Start error(%v)", err)
panic(err)
}
}
func route(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/notice-service")
{
g.GET("/notice/list", listNotices)
g.GET("/notice/unread", unreadInfo)
g.POST("/notice/create", createNotice)
g.POST("/push/login", login)
g.POST("/push/logout", logout)
}
}
func ping(ctx *bm.Context) {
if err := svc.Ping(ctx); err != nil {
log.Error("ping error(%v)", err)
ctx.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}
func createNotice(c *bm.Context) {
arg := &v1.NoticeBase{}
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
resp, err := svc.CreateNotice(c, arg)
c.JSON(resp, err)
}
func listNotices(c *bm.Context) {
arg := &v1.ListNoticesReq{}
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
resp, err := svc.ListNotices(c, arg)
c.JSON(resp, err)
}
func unreadInfo(c *bm.Context) {
arg := &v1.GetUnreadInfoRequest{}
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
resp, err := svc.GetUnreadInfo(c, arg)
c.JSON(resp, err)
}
func login(c *bm.Context) {
arg := &v1.UserPushDev{}
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
resp, err := svc.PushLogin(c, arg)
c.JSON(resp, err)
}
func logout(c *bm.Context) {
arg := &v1.UserPushDev{}
if err := c.Bind(arg); err != nil {
errors.Wrap(err, "参数验证失败")
return
}
resp, err := svc.PushLogout(c, arg)
c.JSON(resp, err)
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"push.go",
"service.go",
],
importpath = "go-common/app/service/bbq/notice-service/internal/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/bbq/notice-service/api/v1:go_default_library",
"//app/service/bbq/notice-service/internal/conf:go_default_library",
"//app/service/bbq/notice-service/internal/dao:go_default_library",
"//app/service/bbq/notice-service/internal/model:go_default_library",
"//app/service/bbq/push/api/grpc/v1:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/net/trace:go_default_library",
"//vendor/github.com/json-iterator/go:go_default_library",
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
],
)
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,210 @@
package service
import (
"context"
"fmt"
"strings"
"time"
"github.com/json-iterator/go"
"go-common/app/service/bbq/notice-service/api/v1"
"go-common/app/service/bbq/notice-service/internal/conf"
"go-common/app/service/bbq/notice-service/internal/model"
push "go-common/app/service/bbq/push/api/grpc/v1"
"go-common/library/log"
"go-common/library/net/trace"
)
func (s *Service) needPush(c context.Context, notice *v1.NoticeBase) bool {
// TODO: 获取粉丝数量
F, err := s.dao.FetchUserFansNum(c, notice.Mid)
if err != nil {
log.Errorv(c, log.KV("log", "FetchUserFansNum error"), log.KV("error", err))
}
var strategyMap *map[string]*conf.PushStrategy
if F <= 1000 {
strategyMap = &s.c.L1PushStrategy
} else {
strategyMap = &s.c.L2PushStrategy
}
var strategy *conf.PushStrategy
switch notice.NoticeType {
case model.NoticeTypeLike:
strategy = (*strategyMap)["like"]
case model.NoticeTypeComment:
strategy = (*strategyMap)["comment"]
case model.NoticeTypeFan:
strategy = (*strategyMap)["follow"]
case model.NoticeTypeSysMsg:
strategy = (*strategyMap)["sysmsg"]
}
// A = -1 and B = -1 无限制
if strategy.A == -1 && strategy.B == -1 {
return true
}
// A = -1 触发无限制
if strategy.A != -1 {
count, err := s.dao.IncrHourPushAction(c, notice.Mid, notice.NoticeType, strategy.T)
if count < strategy.A || err != nil {
return false
}
}
// B = -1 全天无限制
if strategy.B != -1 {
count, err := s.dao.IncrDailyPushCount(c, notice.Mid)
if count > strategy.B || err != nil {
return false
}
}
// 推送触发条件T小时内触发A次且当日推送次数小于等于B
return true
}
func (s *Service) pushNotification(c context.Context, nid int64, notice *v1.NoticeBase) (err error) {
// redis push action_mid
err = s.dao.SetPushActionMid(c, notice.Mid, notice.ActionMid, notice.NoticeType)
if err != nil {
log.Errorv(c, log.KV("log", "SetPushActionMid error"), log.KV("error", err))
return
}
if !s.needPush(c, notice) {
return
}
var title, content string
switch notice.NoticeType {
case model.NoticeTypeLike:
if notice.BizType == model.NoticeBizTypeSv {
// 视频点赞
content = model.PushMsgVideoLike
} else if notice.BizType == model.NoticeBizTypeComment {
// 评论点赞
content = model.PushMsgCommentLike
}
case model.NoticeTypeComment:
if notice.BizType == model.NoticeBizTypeSv {
// 视频评论
content = model.PushMsgVideoComment
} else if notice.BizType == model.NoticeBizTypeComment {
// 评论回复
content = model.PushMsgCommentReply
}
case model.NoticeTypeFan:
// 关注
content = model.PushMsgFollow
case model.NoticeTypeSysMsg:
// 系统消息
// return s.pushMessage(c, nid, notice)
if notice.BizType == model.NoticeBizTypeCmsReview {
// 审核类通知不推送
return
}
content = notice.Text
}
// 填写内容详情
midList, err := s.dao.GetPushActionMid(c, notice.Mid, notice.NoticeType)
if err != nil || len(midList) == 0 {
log.Errorv(c, log.KV("log", "GetPushActionMid error"), log.KV("error", err))
return
}
nameList, err := s.dao.GetUserName(c, midList, 2)
if err != nil {
log.Errorv(c, log.KV("log", "GetUserName error"), log.KV("error", err))
return
}
unreadInfo, err := s.dao.GetUnreadInfo(c, notice.Mid)
if err != nil {
log.Errorv(c, log.KV("log", "GetUnreadInfo error"), log.KV("error", err))
return
}
if len(nameList) > 1 {
tmp := fmt.Sprintf("等%d人", unreadInfo[int(notice.NoticeType)-1].UnreadNum)
content = fmt.Sprintf(content, strings.Join(nameList, ","), tmp)
} else {
content = fmt.Sprintf(content, strings.Join(nameList, ","), "")
}
schema := fmt.Sprintf(model.PushSchemaNotice, notice.NoticeType)
ext := make(map[string]string)
ext["scheme"] = schema
extStr, _ := jsoniter.Marshal(ext)
dev, err := s.dao.FetchPushDev(c, notice.Mid)
if err != nil {
log.Errorv(c, log.KV("log", "FetchPushDev error"), log.KV("error", err))
return
}
dev.SendNo = nid
devs := []*push.Device{dev}
body := &push.NotificationBody{
Title: title,
Content: content,
Extra: string(extStr),
}
req := &push.NotificationRequest{
Dev: devs,
Body: body,
}
result, err := s.dao.PushNotice(c, req)
if err != nil {
log.Errorv(c, log.KV("log", "PushNotice error"), log.KV("error", err), log.KV("result", result))
return
}
err = s.dao.ClearHourPushAction(c, notice.Mid, notice.NoticeType)
if err != nil {
log.Errorv(c, log.KV("log", "hour push action clear error"), log.KV("error", err), log.KV("notice_type", notice.NoticeType))
}
// 埋点
tracer, _ := trace.FromContext(c)
s.Infoc.Info(tracer, notice.Mid, notice.Buvid, nid, notice.NoticeType, notice.BizId, notice.BizType, time.Now().Unix(), result)
return
}
// func (s *Service) pushMessage(c context.Context, nid int64, notice *v1.NoticeBase) (err error) {
// dev, err := s.dao.FetchPushDev(c, notice.Mid)
// if err != nil {
// return
// }
// dev.SendNo = nid
// devs := []*push.Device{dev}
// schema := fmt.Sprintf(model.PushSchemaNotice, notice.NoticeType)
// ext := make(map[string]string)
// ext["shcema"] = schema
// extStr, _ := jsoniter.Marshal(ext)
// body := &push.MessageBody{
// Title: notice.Title,
// Content: notice.Text,
// ContentType: "text",
// Extra: string(extStr),
// }
// req := &push.MessageRequest{
// Dev: devs,
// Body: body,
// }
// result, err := s.dao.PushMessage(c, req)
// if err != nil {
// log.Errorv(c, log.KV("log", "PushMessage error"), log.KV("error", err), log.KV("result", result))
// return
// }
// err = s.dao.ClearHourPushAction(c, notice.Mid, notice.NoticeType)
// if err != nil {
// log.Errorv(c, log.KV("log", "hour push action clear error"), log.KV("error", err), log.KV("notice_type", notice.NoticeType))
// }
// // 埋点
// tracer, _ := trace.FromContext(c)
// s.Infoc.Info(tracer, notice.Mid, notice.Buvid, nid, notice.NoticeType, notice.BizId, notice.BizType, time.Now().Unix(), result)
// return
// }

View File

@@ -0,0 +1,140 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/service/bbq/notice-service/api/v1"
"go-common/app/service/bbq/notice-service/internal/conf"
"go-common/app/service/bbq/notice-service/internal/dao"
"go-common/library/log"
"go-common/library/log/infoc"
"github.com/golang/protobuf/ptypes/empty"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
Infoc *infoc.Infoc
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
Infoc: infoc.New(c.Infoc),
}
return s
}
// Ping Service
func (s *Service) Ping(ctx context.Context) (err error) {
return s.dao.Ping(ctx)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}
// ListNotices 获取通知列表
func (s *Service) ListNotices(c context.Context, req *v1.ListNoticesReq) (res *v1.ListNoticesReply, err error) {
res = new(v1.ListNoticesReply)
res.Mid = req.Mid
res.List, err = s.dao.ListNotices(c, req.Mid, req.CursorId, req.NoticeType)
if err != nil {
log.Errorv(c, log.KV("log", "get list notice fail"))
return
}
// 清理未读数
s.dao.ClearUnread(c, req.Mid, req.NoticeType)
return
}
// CreateNotice 创建消息
func (s *Service) CreateNotice(c context.Context, req *v1.NoticeBase) (res *empty.Empty, err error) {
res = new(empty.Empty)
id, err := s.dao.CreateNotice(c, req)
if err != nil {
log.Warnv(c, log.KV("log", "create notice fail"))
return
}
// 未读数+1
err = s.dao.IncreaseUnread(c, req.Mid, req.NoticeType, 1)
if err != nil {
log.Warnv(c, log.KV("log", "increase notice unread fail: req="+req.String()))
err = nil
}
// TODO:推送
s.pushNotification(c, id, req)
return
}
// GetUnreadInfo 获取未读情况
func (s *Service) GetUnreadInfo(ctx context.Context, req *v1.GetUnreadInfoRequest) (res *v1.UnreadInfo, err error) {
res = new(v1.UnreadInfo)
res.List, err = s.dao.GetUnreadInfo(ctx, req.Mid)
if err != nil {
log.Warnv(ctx, log.KV("log", "get notice unread info fail"), log.KV("req", req.String()))
return
}
log.V(1).Infov(ctx, log.KV("log", "get unread info: res="+res.String()))
return
}
// PushCallback 推送回调
func (s *Service) PushCallback(ctx context.Context, req *v1.PushCallbackRequest) (res *empty.Empty, err error) {
res = new(empty.Empty)
// 埋点
s.Infoc.Info(req.Tid, req.Mid, req.Buvid, req.Nid, "", "", "", time.Now().Unix(), "")
return
}
// PushLogout 推送回调
func (s *Service) PushLogout(ctx context.Context, req *v1.UserPushDev) (res *empty.Empty, err error) {
res = new(empty.Empty)
var rowsAffected int64
if rowsAffected, err = s.dao.DeleteUserPushDev(ctx, req); err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("delete user push dev fail: req=%s", req.String())))
return
}
if rowsAffected == 0 {
log.Warnv(ctx, log.KV("log", fmt.Sprintf("delete user push dev fail due to affected rows is zero: req=%s", req.String())))
}
return
}
// PushLogin login
func (s *Service) PushLogin(ctx context.Context, req *v1.UserPushDev) (res *empty.Empty, err error) {
res = new(empty.Empty)
// 获取数据库是否存在当前的mid & buvid
dev, err := s.dao.FetchUserPushDev(ctx, req.Mid, req.Buvid)
if err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("fetch user push dev fail: req=%s, err=%s", req.String(), err.Error())))
return
}
// 插入user_push_device
if dev.Id == 0 {
if _, err = s.dao.InsertUserPushDev(ctx, req); err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("insert user push dev fail: req=%s", req.String())))
return
}
} else {
// 更新user_push_device
if _, err = s.dao.UpdateUserPushDev(ctx, req); err != nil {
log.Errorv(ctx, log.KV("log", fmt.Sprintf("insert user push dev fail: req=%s", req.String())))
return
}
}
return
}

View File

@@ -0,0 +1,26 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/bbq/push/api/grpc/v1:all-srcs",
"//app/service/bbq/push/api/http/v1:all-srcs",
"//app/service/bbq/push/cmd:all-srcs",
"//app/service/bbq/push/conf:all-srcs",
"//app/service/bbq/push/dao:all-srcs",
"//app/service/bbq/push/model:all-srcs",
"//app/service/bbq/push/server/grpc:all-srcs",
"//app/service/bbq/push/server/http:all-srcs",
"//app/service/bbq/push/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,11 @@
# v1.0.3
1. 推送Extra schema fix
# v1.0.2
1. 推送增加异步接口
# v1.0.1
1. 推送功能重构
# v1.0.0
1. 上线功能bbq push

View File

@@ -0,0 +1,8 @@
# Owner
daiwei
# Author
daiwei
# Reviewer
daiwei

View File

@@ -0,0 +1,12 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- daiwei
labels:
- bbq
- service
- service/bbq/push
options:
no_parent_owners: true
reviewers:
- daiwei

View File

@@ -0,0 +1,12 @@
# push-service
# 项目简介
1.bbq push
# 编译环境
# 依赖包
# 编译执行

View File

@@ -0,0 +1,56 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "v1_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/bbq/push/api/grpc/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/bbq/push/api/grpc/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context: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"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
syntax = "proto3";
package bbq.service.push.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "v1";
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
message Device {
string register_id = 1 [(gogoproto.jsontag) = "register_id",(gogoproto.moretags) = "form:\"register_id\"",(gogoproto.customname) = "RegisterID"];
int32 platform = 2 [(gogoproto.jsontag) = "platform",(gogoproto.moretags) = "form:\"platform\"",(gogoproto.customname) = "Platform"];
int32 sdk = 3 [(gogoproto.jsontag) = "sdk",(gogoproto.moretags) = "form:\"sdk\"",(gogoproto.customname) = "SDK"];
int64 send_no = 4 [(gogoproto.jsontag) = "send_no",(gogoproto.moretags) = "form:\"send_no\"",(gogoproto.customname) = "SendNo"];
}
message Extra {
string token = 1 [(gogoproto.jsontag) = "token",(gogoproto.moretags) = "form:\"token\"",(gogoproto.customname) = "Token"];
string schema = 2 [(gogoproto.jsontag) = "schema",(gogoproto.moretags) = "form:\"schema\"",(gogoproto.customname) = "Schema"];
}
message NotificationBody {
string title = 1 [(gogoproto.jsontag) = "title",(gogoproto.moretags) = "form:\"title\"",(gogoproto.customname) = "Title"];
string content = 2 [(gogoproto.jsontag) = "content",(gogoproto.moretags) = "form:\"content\"",(gogoproto.customname) = "Content"];
string sound = 3 [(gogoproto.jsontag) = "sound",(gogoproto.moretags) = "form:\"sound\"",(gogoproto.customname) = "Sound"];
int32 badge = 4 [(gogoproto.jsontag) = "badge",(gogoproto.moretags) = "form:\"badge\"",(gogoproto.customname) = "Badge"];
string extra = 5 [(gogoproto.jsontag) = "extra",(gogoproto.moretags) = "form:\"extra\"",(gogoproto.customname) = "Extra"];
}
message MessageBody {
string title = 1 [(gogoproto.jsontag) = "title",(gogoproto.moretags) = "form:\"title\"",(gogoproto.customname) = "Title"];
string content = 2 [(gogoproto.jsontag) = "content",(gogoproto.moretags) = "form:\"content\"",(gogoproto.customname) = "Content"];
string content_type = 3 [(gogoproto.jsontag) = "content_type",(gogoproto.moretags) = "form:\"content_type\"",(gogoproto.customname) = "ContentType"];
string extra = 4 [(gogoproto.jsontag) = "extra",(gogoproto.moretags) = "form:\"extra\"",(gogoproto.customname) = "Extra"];
}
message NotificationRequest {
repeated Device dev = 1 [(gogoproto.jsontag) = "dev",(gogoproto.moretags) = "form:\"dev\"",(gogoproto.customname) = "Dev"];
NotificationBody body = 2 [(gogoproto.jsontag) = "body",(gogoproto.moretags) = "form:\"body\"",(gogoproto.customname) = "Body"];
}
message PushResult {
string send_no = 1 [(gogoproto.jsontag) = "sendno,omitempty",(gogoproto.moretags) = "form:\"sendno\"",(gogoproto.customname) = "SendNo"];
string msg_id = 2 [(gogoproto.jsontag) = "msg_id,omitempty",(gogoproto.moretags) = "form:\"msg_id\"",(gogoproto.customname) = "MsgID"];
PushError err = 3 [(gogoproto.jsontag) = "error,omitempty",(gogoproto.moretags) = "form:\"error\"",(gogoproto.customname) = "Error"];
}
message PushError {
string msg = 1 [(gogoproto.jsontag) = "message",(gogoproto.moretags) = "form:\"message\"",(gogoproto.customname) = "Message"];
int32 code = 2 [(gogoproto.jsontag) = "code",(gogoproto.moretags) = "form:\"code\"",(gogoproto.customname) = "Code"];
}
message NotificationResponse {
repeated PushResult result = 1 [(gogoproto.jsontag) = "result",(gogoproto.moretags) = "form:\"result\"",(gogoproto.customname) = "Result"];
}
message MessageRequest {
repeated Device dev = 1 [(gogoproto.jsontag) = "dev",(gogoproto.moretags) = "form:\"dev\"",(gogoproto.customname) = "Dev"];
MessageBody body = 2 [(gogoproto.jsontag) = "body",(gogoproto.moretags) = "form:\"body\"",(gogoproto.customname) = "Body"];
}
message MessageResponse {
repeated PushResult result = 1 [(gogoproto.jsontag) = "result",(gogoproto.moretags) = "form:\"result\"",(gogoproto.customname) = "Result"];
}
service Push {
rpc Notification(NotificationRequest) returns (NotificationResponse);
rpc Message(MessageRequest) returns (MessageResponse);
rpc AsyncNotification(NotificationRequest) returns (NotificationResponse);
rpc AsyncMessage(MessageRequest) returns (MessageResponse);
}

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["api.go"],
importpath = "go-common/app/service/bbq/push/api/http/v1",
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"],
)

Some files were not shown because too many files have changed in this diff Show More