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

22
app/job/live/gift/BUILD Normal file
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/job/live/gift/api:all-srcs",
"//app/job/live/gift/cmd:all-srcs",
"//app/job/live/gift/internal/conf:all-srcs",
"//app/job/live/gift/internal/dao:all-srcs",
"//app/job/live/gift/internal/model:all-srcs",
"//app/job/live/gift/internal/server/http:all-srcs",
"//app/job/live/gift/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
shenli01
# Author
# Reviewer

10
app/job/live/gift/OWNERS Normal file
View File

@@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- shenli01
labels:
- job
- job/live/gift
- live
options:
no_parent_owners: true

View File

@@ -0,0 +1,12 @@
# gift-job
## 项目简介
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/job/live/gift/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/job/live/gift/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/job/live/gift/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_d309cedea9eacff7, []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/job/live/gift/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/job/live/gift/api/api.proto", fileDescriptor_api_d309cedea9eacff7)
}
var fileDescriptor_api_d309cedea9eacff7 = []byte{
// 250 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0x2c, 0x28, 0xd0,
0xcf, 0xca, 0x4f, 0xd2, 0xcf, 0xc9, 0x2c, 0x4b, 0xd5, 0x4f, 0xcf, 0x4c, 0x2b, 0xd1, 0x4f, 0x2c,
0xc8, 0x04, 0x61, 0xbd, 0x82, 0xa2, 0xfc, 0x92, 0x7c, 0x21, 0xfe, 0x94, 0xd4, 0xdc, 0x7c, 0xbd,
0xe2, 0xd4, 0xa2, 0xb2, 0xcc, 0xe4, 0x54, 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, 0x7d, 0xee, 0x27, 0xd0, 0x29, 0x01, 0x00, 0x00,
}

View File

@@ -0,0 +1,29 @@
// 定义项目 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
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,44 @@
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/job/live/gift/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/internal/server/http:go_default_library",
"//app/job/live/gift/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"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,47 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/job/live/gift/internal/conf"
"go-common/app/job/live/gift/internal/server/http"
"go-common/app/job/live/gift/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("gift-job start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
svc := service.New(conf.Conf)
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()
log.Info("gift-job exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,70 @@
[mysql]
addr = "172.22.34.101:3312"
#dsn = "livetestuat:livetestuat20180711@tcp(172.22.34.101:3312)/live-ugift?timeout=200ms&readTimeout=200ms&writeTimeout=200ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
dsn = "live:oWni@ElNs0P0C(dphdj*F1y4@tcp(172.16.38.117:3312)/live-ugift?timeout=400ms&readTimeout=400ms&writeTimeout=400ms&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "800ms"
execTimeout = "800ms"
tranTimeout = "800ms"
[redis]
name = "gift-job"
proto = "tcp"
addr = "127.0.0.1:6379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "1m"
[memcache]
name = "gift-job"
proto = "tcp"
addr = ""
active = 50
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
[databus]
[databus.AddGift]
key = "ec4c0820d525d67b"
secret = "e20f8f664bf10722efeb6aac0cc16011"
group = "LiveAddGift-LiveLive-S"
topic = "LiveAddGift-T"
action = "sub"
name = "gift-job/addFreeGift"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 10
active = 10
dialTimeout = "10s"
readTimeout = "33s"
writeTimeout = "10s"
idleTimeout = "10s"
[consumer]
[consumer.AddGift]
num = 100
[infoc]
[infoc.bagLog]
taskID = "000736"
proto = "tcp"
addr = "172.18.33.124:15140"
chanSize = 10240
[infoc.giftAction]
taskID = "000579"
proto = "tcp"
addr = "172.18.33.124:15140"
chanSize = 10240
[log]
stdout = true

View File

@@ -0,0 +1,42 @@
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/job/live/gift/internal/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//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/trace:go_default_library",
"//library/queue/databus: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,107 @@
package conf
import (
"errors"
"flag"
"go-common/library/log/infoc"
"go-common/library/queue/databus"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"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
Redis *redis.Config
Memcache *memcache.Config
MySQL *sql.Config
Ecode *ecode.Config
Databus *Databus
Infoc map[string]*infoc.Config
Consumer *consumer
}
type consumer struct {
AddGift *consumeConfig
}
type consumeConfig struct {
Num int
}
//Databus Databus
type Databus struct {
AddGift *databus.Config
}
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",
"mysql.go",
"redis.go",
],
importpath = "go-common/app/job/live/gift/internal/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/internal/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/satori/go.uuid: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,42 @@
package dao
import (
"context"
"go-common/app/job/live/gift/internal/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
)
// Dao dao
type Dao struct {
c *conf.Config
mc *memcache.Pool
redis *redis.Pool
db *xsql.DB
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
mc: memcache.NewPool(c.Memcache),
redis: redis.NewPool(c.Redis),
db: xsql.NewMySQL(c.MySQL),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.redis.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)
}

View File

@@ -0,0 +1,79 @@
package dao
import (
"context"
"crypto/md5"
"database/sql"
"encoding/hex"
"fmt"
"go-common/app/job/live/gift/internal/model"
"go-common/library/log"
"strconv"
)
var (
_getBag = "SELECT id,gift_num FROM user_gift_%s WHERE uid = ? AND gift_id = ? AND expireat = ? LIMIT 1"
_getBagByID = "SELECT id,gift_num FROM user_gift_%s WHERE id = ?"
_updateBagNum = "UPDATE user_gift_%s SET gift_num = gift_num + ? WHERE id = ?"
_insertBag = "INSERT INTO user_gift_%s (uid,gift_id,gift_num,expireat) VALUES (?,?,?,?)"
)
// GetBag GetBag
func (d *Dao) GetBag(ctx context.Context, uid, giftID, expireAt int64) (res *model.BagInfo, err error) {
log.Info("GetBag,uid:%d,giftID:%d,expireAt:%d", uid, giftID, expireAt)
row := d.db.QueryRow(ctx, fmt.Sprintf(_getBag, getPostFix(uid)), uid, giftID, expireAt)
res = &model.BagInfo{}
if err = row.Scan(&res.ID, &res.GiftNum); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("GetBag row.Scan error(%v)", err)
}
return
}
// UpdateBagNum UpdateBagNum
func (d *Dao) UpdateBagNum(ctx context.Context, uid, id, num int64) (affected int64, err error) {
log.Info("UpdateBagNum,uid:%d,id:%d,num:%d", uid, id, num)
res, err := d.db.Exec(ctx, fmt.Sprintf(_updateBagNum, getPostFix(uid)), num, id)
if err != nil {
log.Error("UpdateBagNum error(%v)", err)
return
}
return res.RowsAffected()
}
// AddBag AddBag
func (d *Dao) AddBag(ctx context.Context, uid, giftID, giftNum, expireAt int64) (affected int64, err error) {
log.Info("AddBag,uid:%d,giftID:%d,giftNum:%d,expireAt:%d", uid, giftID, giftNum, expireAt)
res, err := d.db.Exec(ctx, fmt.Sprintf(_insertBag, getPostFix(uid)), uid, giftID, giftNum, expireAt)
if err != nil {
log.Error("AddBag error(%v)", err)
return
}
return res.LastInsertId()
}
// GetBagByID GetBagByID
func (d *Dao) GetBagByID(ctx context.Context, uid, id int64) (res *model.BagInfo, err error) {
log.Info("GetBagByID,uid:%d,id:%d", uid, id)
row := d.db.QueryRow(ctx, fmt.Sprintf(_getBagByID, getPostFix(uid)), id)
res = &model.BagInfo{}
if err = row.Scan(&res.ID, &res.GiftNum); err != nil {
if err == sql.ErrNoRows {
err = nil
return
}
log.Error("GetBagByID row.Scan error(%v)", err)
}
return
}
func getPostFix(uid int64) string {
uidStr := strconv.Itoa(int(uid))
h := md5.New()
h.Write([]byte(uidStr))
md5Str := hex.EncodeToString(h.Sum(nil))
return md5Str[0:1]
}

View File

@@ -0,0 +1,110 @@
package dao
import (
"context"
"fmt"
"go-common/library/cache/redis"
"go-common/library/log"
"time"
"github.com/satori/go.uuid"
)
func bagIDCache(uid, giftID, expireAt int64) string {
return fmt.Sprintf("bag_id:%d:%d:%d", uid, giftID, expireAt)
}
// SetBagIDCache SetBagIDCache
func (d *Dao) SetBagIDCache(ctx context.Context, uid, giftID, expireAt, bagID, expire int64) (err error) {
key := bagIDCache(uid, giftID, expireAt)
conn := d.redis.Get(ctx)
defer conn.Close()
_, err = conn.Do("SETEX", key, expire, bagID)
if err != nil {
log.Error("conn.Do(SETEX, %s) error(%v)", key, err)
}
return
}
func bagListKey(uid int64) string {
return fmt.Sprintf("bag_list:%d", uid)
}
// ClearBagListCache ClearBagListCache
func (d *Dao) ClearBagListCache(ctx context.Context, uid int64) (err error) {
key := bagListKey(uid)
conn := d.redis.Get(ctx)
defer conn.Close()
_, err = conn.Do("DEL", key)
if err != nil {
log.Error("conn.Do(DEL, %s) error(%v)", key, err)
}
return
}
// GetBagIDCache GetBagIDCache
func (d *Dao) GetBagIDCache(ctx context.Context, uid, giftID, expireAt int64) (bagID int64, err error) {
key := bagIDCache(uid, giftID, expireAt)
conn := d.redis.Get(ctx)
defer conn.Close()
bagID, err = redis.Int64(conn.Do("GET", key))
if err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(GET, %s) error(%v)", key, err)
}
return
}
return
}
func bagNumKey(uid, giftID, expireAt int64) string {
return fmt.Sprintf("bag_num:%d:%d:%d", uid, giftID, expireAt)
}
// SetBagNumCache SetBagNumCache
func (d *Dao) SetBagNumCache(ctx context.Context, uid, giftID, expireAt, giftNum, expire int64) (err error) {
key := bagNumKey(uid, giftID, expireAt)
conn := d.redis.Get(ctx)
defer conn.Close()
_, err = conn.Do("SETEX", key, expire, giftNum)
if err != nil {
log.Error("conn.Do(SETEX, %s) error(%v)", key, err)
}
return
}
//Lock Lock
func (d *Dao) Lock(ctx context.Context, key string, ttl int, retry int, retryDelay int) (gotLock bool, lockValue string, err error) {
if retry <= 0 {
retry = 1
}
lockValue = uuid.NewV4().String()
retryTimes := 0
conn := d.redis.Get(ctx)
defer conn.Close()
realKey := lockKey(key)
for ; retryTimes < retry; retryTimes++ {
var res interface{}
res, err = conn.Do("SET", realKey, lockValue, "PX", ttl, "NX")
if err != nil {
log.Error("redis_lock failed:%s:%v", realKey, err)
break
}
if res != nil {
gotLock = true
break
}
time.Sleep(time.Duration(retryDelay) * time.Millisecond)
}
return
}
func lockKey(key string) string {
return fmt.Sprintf("gift_job_lock:%s", key)
}

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/job/live/gift/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,17 @@
package model
//AddFreeGift AddFreeGift
type AddFreeGift struct {
UID int64 `json:"uid"`
GiftID int64 `json:"gift_id"`
GiftNum int64 `json:"gift_num"`
ExpireAt int64 `json:"expire_at"`
Source string `json:"source"`
MsgID string `json:"msg_id"`
}
// BagInfo BagInfo
type BagInfo struct {
ID int64 `json:"id"`
GiftNum int64 `json:"gift_num"`
}

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/job/live/gift/internal/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/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",
],
)
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,53 @@
package http
import (
"net/http"
"go-common/app/job/live/gift/internal/conf"
"go-common/app/job/live/gift/internal/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
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/gift")
{
g.GET("/start", vfy.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,60 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"infoc.go",
"package.go",
"service.go",
],
importpath = "go-common/app/job/live/gift/internal/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/live/gift/api:go_default_library",
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/internal/dao:go_default_library",
"//app/job/live/gift/internal/model:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/queue/databus:go_default_library",
"//library/sync/errgroup: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"],
)
go_test(
name = "go_default_test",
srcs = [
"infoc_test.go",
"package_test.go",
"service_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/job/live/gift/internal/conf:go_default_library",
"//app/job/live/gift/internal/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,121 @@
package service
import (
"go-common/library/log"
"go-common/library/log/infoc"
"strconv"
"time"
)
var inCh = make(chan interface{}, 10240)
const maxInt = int(^uint(0) >> 1)
type bagLogInfoc struct {
id string
uid string
bagID string
giftID string
num string
afterNum string
source string
infoType string
ctime string
}
type giftActionInfoc struct {
uid int64
roomid int64
item int64
value int64
change int64
describe string
extra string
ts int64
platform string
clientver string
buvid string
ua string
referer string
}
// bagLogInfoc 包裹日志打点
func (s *Service) bagLogInfoc(uid, bagID, giftID, num, afterNum int64, source string) {
s.infoc(bagLogInfoc{
id: MakeID(uid),
uid: strconv.FormatInt(uid, 10),
bagID: strconv.FormatInt(bagID, 10),
giftID: strconv.FormatInt(giftID, 10),
num: strconv.FormatInt(num, 10),
afterNum: strconv.FormatInt(afterNum, 10),
source: source,
infoType: "1",
ctime: time.Now().Format("2006-01-02 15:04:05"),
})
}
//giftActionInfoc 道具打点
func (s *Service) giftActionInfoc(uid, roomid, item, value, change int64, describe, platform string) {
s.infoc(giftActionInfoc{
uid: uid,
roomid: roomid,
item: item,
value: value,
change: change,
describe: describe,
extra: "",
ts: time.Now().Unix(),
platform: platform,
clientver: "",
buvid: "",
ua: "",
referer: "",
})
}
// MakeID MakeID
func MakeID(uid int64) string {
prefix := strconv.FormatInt(uid%10, 10)
postfix := strconv.Itoa(maxInt - int(time.Now().Unix()*10000))
uidStr := strconv.FormatInt(uid, 10)
l := len(uidStr)
var middle string
if l >= 10 {
middle = uidStr
} else {
var s string
for i := 0; i < (10 - l); i++ {
s += "0"
}
middle = s + uidStr
}
return prefix + middle + postfix
}
//infoc
func (s *Service) infoc(i interface{}) {
select {
case inCh <- i:
default:
log.Warn("infocproc chan full")
}
}
// infocproc
func (s *Service) infocproc() {
var bl = infoc.New(s.c.Infoc["bagLog"])
var ga = infoc.New(s.c.Infoc["giftAction"])
for {
i := <-inCh
switch v := i.(type) {
case bagLogInfoc:
err := bl.Info(v.id, v.uid, v.bagID, v.giftID, v.num, v.afterNum, v.source, v.infoType, v.ctime)
log.Info("bagLogInfoc info %v,ret:%v", v, err)
case giftActionInfoc:
err := ga.Info(v.uid, v.roomid, v.item, v.value, v.change, v.describe, v.extra, v.ts, v.platform, v.clientver, v.buvid, v.ua, v.referer)
log.Info("giftActionInfoc info %v,ret:%v", v, err)
default:
log.Warn("infocproc can't process the type")
}
}
}

View File

@@ -0,0 +1,58 @@
package service
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestServicebagLogInfoc(t *testing.T) {
convey.Convey("bagLogInfoc", t, func(ctx convey.C) {
var (
uid = int64(0)
bagID = int64(0)
giftID = int64(0)
num = int64(0)
afterNum = int64(0)
source = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
s.bagLogInfoc(uid, bagID, giftID, num, afterNum, source)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestServicegiftActionInfoc(t *testing.T) {
convey.Convey("giftActionInfoc", t, func(ctx convey.C) {
var (
uid = int64(0)
roomid = int64(0)
item = int64(0)
value = int64(0)
change = int64(0)
describe = ""
platform = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
s.giftActionInfoc(uid, roomid, item, value, change, describe, platform)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestServiceMakeID(t *testing.T) {
convey.Convey("MakeID", t, func(ctx convey.C) {
var (
uid = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
p1 := MakeID(uid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,99 @@
package service
import (
"context"
"errors"
"go-common/app/job/live/gift/internal/model"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// AddGift AddGift
func (s *Service) AddGift(ctx context.Context, m *model.AddFreeGift) (bagId int64, err error) {
uid := m.UID
giftID := m.GiftID
giftNum := m.GiftNum
expireAt := m.ExpireAt
source := m.Source
if uid == 0 || giftID == 0 || giftNum == 0 {
log.Error("add gift params error,uid:%d,giftID:%d,giftNum:%d", uid, giftID, giftNum)
err = errors.New("params error")
return
}
bagID, err := s.GetBagID(ctx, uid, giftID, expireAt)
if err != nil {
return
}
var (
affectNum int64
isUpdate = false
eg, _ = errgroup.WithContext(ctx)
)
if bagID != 0 {
isUpdate = true
affectNum, _ = s.dao.UpdateBagNum(ctx, uid, bagID, giftNum)
} else {
affectNum, _ = s.dao.AddBag(ctx, uid, giftID, giftNum, expireAt)
bagID = affectNum
eg.Go(
func() error {
s.dao.SetBagIDCache(ctx, uid, giftID, expireAt, bagID, 14400)
return nil
})
}
newNum := giftNum
if affectNum > 0 {
eg.Go(
func() error {
s.dao.ClearBagListCache(ctx, uid)
return nil
})
if isUpdate {
res, _ := s.dao.GetBagByID(ctx, uid, bagID)
newNum = res.GiftNum
//上报lancer TODO
s.bagLogInfoc(uid, bagID, giftID, giftNum, newNum, source)
}
}
// 更新免费礼物数量缓存
eg.Go(
func() error {
s.UpdateFreeGiftCache(ctx, uid, giftID, expireAt, newNum)
return nil
})
eg.Wait()
return
}
// GetBagID GetBagID
func (s *Service) GetBagID(ctx context.Context, uid, giftID, expireAt int64) (id int64, err error) {
id, err = s.dao.GetBagIDCache(ctx, uid, giftID, expireAt)
if err != nil {
return
}
if id == 0 {
//queryDB
var r *model.BagInfo
r, err = s.dao.GetBag(ctx, uid, giftID, expireAt)
if err != nil {
return
}
id = r.ID
}
// 缓存或数据库本身有,再更新缓存
if id != 0 {
s.dao.SetBagIDCache(ctx, uid, giftID, expireAt, id, 14400)
}
return
}
// UpdateFreeGiftCache UpdateFreeGiftCache
func (s *Service) UpdateFreeGiftCache(ctx context.Context, uid, giftID, expireAt, num int64) {
//giftInfo := s.GetGiftInfoByID(ctx, giftID)
//if giftInfo.Id == 0 || giftInfo.Type != 3 {
// return
//}
//s.dao.SetBagNumCache(ctx, uid, giftID, expireAt, num, 14400)
}

View File

@@ -0,0 +1,66 @@
package service
import (
"context"
"go-common/app/job/live/gift/internal/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestServiceAddGift(t *testing.T) {
convey.Convey("AddGift", t, func(c convey.C) {
var (
ctx = context.Background()
m = &model.AddFreeGift{
UID: 1,
GiftID: 1,
GiftNum: 1,
ExpireAt: 0,
Source: "test",
}
)
c.Convey("When everything gose positive", func(c convey.C) {
bagId, err := s.AddGift(ctx, m)
c.Convey("Then err should be nil.bagId should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(bagId, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceGetBagID(t *testing.T) {
convey.Convey("GetBagID", t, func(c convey.C) {
var (
ctx = context.Background()
uid = int64(1)
giftID = int64(1)
expireAt = int64(0)
)
c.Convey("When everything gose positive", func(c convey.C) {
id, err := s.GetBagID(ctx, uid, giftID, expireAt)
c.Convey("Then err should be nil.id should not be nil.", func(c convey.C) {
c.So(err, convey.ShouldBeNil)
c.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestServiceUpdateFreeGiftCache(t *testing.T) {
convey.Convey("UpdateFreeGiftCache", t, func(c convey.C) {
var (
ctx = context.Background()
uid = int64(0)
giftID = int64(0)
expireAt = int64(0)
num = int64(0)
)
c.Convey("When everything gose positive", func(c convey.C) {
s.UpdateFreeGiftCache(ctx, uid, giftID, expireAt, num)
c.Convey("No return values", func(ctx convey.C) {
})
})
})
}

View File

@@ -0,0 +1,95 @@
package service
import (
"context"
"encoding/json"
"fmt"
"sync"
"go-common/app/job/live/gift/internal/model"
"go-common/library/log"
"go-common/library/queue/databus"
pb "go-common/app/job/live/gift/api"
"go-common/app/job/live/gift/internal/conf"
"go-common/app/job/live/gift/internal/dao"
"github.com/golang/protobuf/ptypes/empty"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
addFreeGift *databus.Databus
waiter sync.WaitGroup
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
addFreeGift: databus.New(c.Databus.AddGift),
}
go s.infocproc()
for i := 0; i < c.Consumer.AddGift.Num; i++ {
s.waiter.Add(1)
go s.addGiftConsumeProc()
}
return s
}
func (s *Service) addGiftConsumeProc() {
defer s.waiter.Done()
var err error
for {
msg, ok := <-s.addFreeGift.Messages()
if !ok {
log.Error("s.addFreeGift.Messages channel closed")
return
}
m := &model.AddFreeGift{}
if err = json.Unmarshal(msg.Value, &m); err != nil {
log.Error("json.Unmarshal(%v) error(%v)", msg, err)
continue
}
ctx := context.Background()
// 消息幂等
if m.MsgID != "" {
key := m.MsgID + m.Source
gotLock, _, errLock := s.dao.Lock(ctx, key, 3600000, 0, 0)
if errLock != nil {
continue
}
if !gotLock {
log.Error("msg has been processed,%v", m)
continue
}
}
s.AddGift(ctx, m)
// 打点上报
s.giftActionInfoc(m.UID, 0, m.GiftID, 0, m.GiftNum, m.Source, "")
log.Info("consume addFreeGift topic:%s, Key:%s, Value:%s ", msg.Topic, msg.Key, msg.Value)
if err = msg.Commit(); err != nil {
log.Error("commit msg(%v) error(%v)", msg, err)
}
}
}
// 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 Service
func (s *Service) Ping(ctx context.Context) (err error) {
return s.dao.Ping(ctx)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}

View File

@@ -0,0 +1,34 @@
package service
import (
"flag"
"go-common/app/job/live/gift/internal/conf"
"os"
"testing"
)
var (
s *Service
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "")
flag.Set("conf_token", "")
flag.Set("tree_id", "")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
os.Exit(m.Run())
}