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

View File

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

View File

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

View File

@@ -0,0 +1,10 @@
# Owner
fanzhenfei
zhaohailin
# Author
fanzhenfei
# Reviewer
fanzhenfei
zhaohailin

View File

@@ -0,0 +1,15 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- fanzhenfei
- zhaohailin
labels:
- live
- service
- service/live/xcaptcha
options:
no_parent_owners: true
reviewers:
- fanzhenfei
- liugang
- zhaohailin

View File

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

View File

@@ -0,0 +1,62 @@
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/live/xcaptcha/api/grpc/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"api.bm.go",
"client.go",
],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/live/xcaptcha/api/grpc/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding:go_default_library",
"//library/net/rpc/warden:go_default_library",
"@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"],
)

View File

@@ -0,0 +1,86 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api/grpc/v1/api.proto
/*
Package v1 is a generated blademaster stub package.
This code was generated with go-common/app/tool/bmgen/protoc-gen-bm v0.1.
It is generated from these files:
api/grpc/v1/api.proto
*/
package v1
import (
"context"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
var _ binding.StructValidator
// ==================
// XCaptcha Interface
// ==================
// XCaptcha
type XCaptcha interface {
// 创建验证码
Create(ctx context.Context, req *XCreateCaptchaReq) (resp *XCreateCaptchaResp, err error)
// 二次校验checkToken `internal:"true"`
Verify(ctx context.Context, req *XVerifyReq) (resp *XVerifyResp, err error)
// 验证码校验 `internal:"true"`
Check(ctx context.Context, req *CheckReq) (resp *CheckResp, err error)
}
var v1XCaptchaSvc XCaptcha
// @params XCreateCaptchaReq
// @router GET /xlive/xcaptcha/v1/xCaptcha/create
// @response XCreateCaptchaResp
func xCaptchaCreate(c *bm.Context) {
p := new(XCreateCaptchaReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1XCaptchaSvc.Create(c, p)
c.JSON(resp, err)
}
// @params XVerifyReq
// @router GET /xlive/internal/xcaptcha/v1/xCaptcha/verify
// @response XVerifyResp
func xCaptchaVerify(c *bm.Context) {
p := new(XVerifyReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1XCaptchaSvc.Verify(c, p)
c.JSON(resp, err)
}
// @params CheckReq
// @router GET /xlive/internal/xcaptcha/v1/xCaptcha/check
// @response CheckResp
func xCaptchaCheck(c *bm.Context) {
p := new(CheckReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1XCaptchaSvc.Check(c, p)
c.JSON(resp, err)
}
// RegisterV1XCaptchaService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1XCaptchaService(e *bm.Engine, svc XCaptcha, midMap map[string]bm.HandlerFunc) {
v1XCaptchaSvc = svc
e.GET("/xlive/xcaptcha/v1/xCaptcha/create", xCaptchaCreate)
e.GET("/xlive/internal/xcaptcha/v1/xCaptcha/verify", xCaptchaVerify)
e.GET("/xlive/internal/xcaptcha/v1/xCaptcha/check", xCaptchaCheck)
}

View File

@@ -0,0 +1,55 @@
## 创建验证码
`GET http://api.live.bilibili.com/xlive/xcaptcha/v1/captcha/create`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|type|否|integer||
|client_type|否|string||
|height|否|integer||
|width|否|integer||
|uid|否|integer||
|client_ip|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"type": 0,
"geetest": {
"gt": "",
"challenge": ""
},
"image": {
"tips": "",
"token": "",
"content": ""
}
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/xcaptcha/v1/captcha/verify`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|_anti|否|string||
|uid|否|integer||
|client_ip|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
syntax = "proto3";
package live.xcaptcha.v1;
option go_package = "v1";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
// XCaptcha
service XCaptcha {
// 创建验证码
rpc create (XCreateCaptchaReq) returns (XCreateCaptchaResp);
// 二次校验checkToken `internal:"true"`
rpc verify (XVerifyReq) returns (XVerifyResp);
// 验证码校验 `internal:"true"`
rpc check (CheckReq) returns (CheckResp);
}
message XCreateCaptchaReq {
int64 type = 1 [(gogoproto.moretags) = 'form:"type"'];
string client_type = 2 [(gogoproto.moretags) = 'form:"client_type"'];
int64 height = 3 [(gogoproto.moretags) = 'form:"height"'];
int64 width = 4 [(gogoproto.moretags) = 'form:"width"'];
int64 uid = 5 [(gogoproto.moretags) = 'form:"uid"'];
string client_ip = 6 [(gogoproto.moretags) = 'form:"client_ip"'];
}
message XCreateCaptchaResp{
int64 type = 1 [(gogoproto.jsontag) = "type"];
GeeTest geetest = 2 [(gogoproto.jsontag) = "geetest"];
Image image = 3 [(gogoproto.jsontag) = "image"];
}
message GeeTest{
string gt = 1 [(gogoproto.jsontag) = "gt"];
string challenge = 2 [(gogoproto.jsontag) = "challenge"];
}
message Image{
string tips = 1 [(gogoproto.jsontag) = "tips"];
string token = 2 [(gogoproto.jsontag) = "token"];
string content = 3 [(gogoproto.jsontag) = "content"];
}
message XVerifyReq {
string _anti = 1 [(gogoproto.moretags) = 'form:"_anti" validate:"required"'];
int64 uid = 2 [(gogoproto.moretags) = 'form:"uid" validate:"required"'];
string client_ip = 3 [(gogoproto.moretags) = 'form:"client_ip"'];
int64 room_id = 4 [(gogoproto.moretags) = 'form:"room_id"'];
}
message XVerifyResp{
}
message CheckReq{
string anti = 1 [(gogoproto.moretags) = 'form:"anti" validate:"required"'];
int64 uid = 2 [(gogoproto.moretags) = 'form:"uid" validate:"required"'];
string client_ip = 3 [(gogoproto.moretags) = 'form:"client_ip"'];
}
message CheckResp{
int64 type = 1 [(gogoproto.jsontag) = "type"];
string token = 2 [(gogoproto.jsontag) = "token"];
}

View File

@@ -0,0 +1,79 @@
## 创建验证码
`GET http://api.live.bilibili.com/xlive/xcaptcha/v1/xCaptcha/create`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|type|否|integer||
|client_type|否|string||
|height|否|integer||
|width|否|integer||
|uid|否|integer||
|client_ip|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"type": 0,
"geetest": {
"gt": "",
"challenge": ""
},
"image": {
"tips": "",
"token": "",
"content": ""
}
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/xcaptcha/v1/xCaptcha/verify`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|_anti|是|string||
|uid|是|integer||
|client_ip|否|string||
|room_id|否|integer||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```
##
`GET http://api.live.bilibili.com/xlive/internal/xcaptcha/v1/xCaptcha/check`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|anti|是|string||
|uid|是|integer||
|client_ip|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
"type": 0,
"token": ""
}
}
```

View File

@@ -0,0 +1,27 @@
package v1
import (
"context"
"go-common/library/net/rpc/warden"
"google.golang.org/grpc"
)
// AppID 服务app_id
const AppID = "live.xcaptcha"
// Client grpc xcaptcha
type Client struct {
XCaptchaClient
}
// NewClient new resource grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (*Client, error) {
client := warden.NewClient(cfg, opts...)
conn, err := client.Dial(context.Background(), "discovery://default/"+AppID)
if err != nil {
return nil, err
}
cli := &Client{}
cli.XCaptchaClient = NewXCaptchaClient(conn)
return cli, nil
}

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 = ["http.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/live/xcaptcha/api/http/v1",
proto = ":v1_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["http.bm.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/live/xcaptcha/api/http/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto: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,54 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: api/http/v1/http.proto
/*
Package v1 is a generated blademaster stub package.
This code was generated with go-common/app/tool/bmgen/protoc-gen-bm v0.1.
It is generated from these files:
api/http/v1/http.proto
*/
package v1
import (
"context"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
var _ binding.StructValidator
// =================
// Captcha Interface
// =================
// XCaptcha
type Captcha interface {
// 验证码校验 `internal:"true"`
Verify(ctx context.Context, req *XVerifyReq) (resp *XVerifyResp, err error)
}
var v1CaptchaSvc Captcha
// @params XVerifyReq
// @router GET /xlive/internal/xcaptcha/v1/captcha/verify
// @response XVerifyResp
func captchaVerify(c *bm.Context) {
p := new(XVerifyReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1CaptchaSvc.Verify(c, p)
c.JSON(resp, err)
}
// RegisterV1CaptchaService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1CaptchaService(e *bm.Engine, svc Captcha, midMap map[string]bm.HandlerFunc) {
v1CaptchaSvc = svc
e.GET("/xlive/internal/xcaptcha/v1/captcha/verify", captchaVerify)
}

View File

@@ -0,0 +1,21 @@
##
`GET http://api.live.bilibili.com/xlive/internal/xcaptcha/v1/captcha/verify`
### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|_anti|是|string||
|uid|是|integer||
|client_ip|否|string||
```json
{
"code": 0,
"message": "ok",
"data": {
}
}
```

View File

@@ -0,0 +1,552 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: api/http/v1/http.proto
package v1
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
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 XVerifyReq struct {
XAnti string `protobuf:"bytes,1,opt,name=_anti,json=Anti,proto3" json:"_anti,omitempty" form:"_anti" validate:"required"`
Uid int64 `protobuf:"varint,2,opt,name=uid,proto3" json:"uid,omitempty" form:"uid" validate:"required"`
ClientIp string `protobuf:"bytes,3,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty" form:"client_ip"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *XVerifyReq) Reset() { *m = XVerifyReq{} }
func (m *XVerifyReq) String() string { return proto.CompactTextString(m) }
func (*XVerifyReq) ProtoMessage() {}
func (*XVerifyReq) Descriptor() ([]byte, []int) {
return fileDescriptor_http_6086dd8d3a71844a, []int{0}
}
func (m *XVerifyReq) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *XVerifyReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_XVerifyReq.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 *XVerifyReq) XXX_Merge(src proto.Message) {
xxx_messageInfo_XVerifyReq.Merge(dst, src)
}
func (m *XVerifyReq) XXX_Size() int {
return m.Size()
}
func (m *XVerifyReq) XXX_DiscardUnknown() {
xxx_messageInfo_XVerifyReq.DiscardUnknown(m)
}
var xxx_messageInfo_XVerifyReq proto.InternalMessageInfo
func (m *XVerifyReq) GetXAnti() string {
if m != nil {
return m.XAnti
}
return ""
}
func (m *XVerifyReq) GetUid() int64 {
if m != nil {
return m.Uid
}
return 0
}
func (m *XVerifyReq) GetClientIp() string {
if m != nil {
return m.ClientIp
}
return ""
}
type XVerifyResp struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *XVerifyResp) Reset() { *m = XVerifyResp{} }
func (m *XVerifyResp) String() string { return proto.CompactTextString(m) }
func (*XVerifyResp) ProtoMessage() {}
func (*XVerifyResp) Descriptor() ([]byte, []int) {
return fileDescriptor_http_6086dd8d3a71844a, []int{1}
}
func (m *XVerifyResp) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *XVerifyResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_XVerifyResp.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 *XVerifyResp) XXX_Merge(src proto.Message) {
xxx_messageInfo_XVerifyResp.Merge(dst, src)
}
func (m *XVerifyResp) XXX_Size() int {
return m.Size()
}
func (m *XVerifyResp) XXX_DiscardUnknown() {
xxx_messageInfo_XVerifyResp.DiscardUnknown(m)
}
var xxx_messageInfo_XVerifyResp proto.InternalMessageInfo
func init() {
proto.RegisterType((*XVerifyReq)(nil), "live.xcaptcha.v1.XVerifyReq")
proto.RegisterType((*XVerifyResp)(nil), "live.xcaptcha.v1.XVerifyResp")
}
func (m *XVerifyReq) 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 *XVerifyReq) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.XAnti) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintHttp(dAtA, i, uint64(len(m.XAnti)))
i += copy(dAtA[i:], m.XAnti)
}
if m.Uid != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintHttp(dAtA, i, uint64(m.Uid))
}
if len(m.ClientIp) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintHttp(dAtA, i, uint64(len(m.ClientIp)))
i += copy(dAtA[i:], m.ClientIp)
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
return i, nil
}
func (m *XVerifyResp) 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 *XVerifyResp) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
return i, nil
}
func encodeVarintHttp(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 *XVerifyReq) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.XAnti)
if l > 0 {
n += 1 + l + sovHttp(uint64(l))
}
if m.Uid != 0 {
n += 1 + sovHttp(uint64(m.Uid))
}
l = len(m.ClientIp)
if l > 0 {
n += 1 + l + sovHttp(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func (m *XVerifyResp) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovHttp(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozHttp(x uint64) (n int) {
return sovHttp(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *XVerifyReq) 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 ErrIntOverflowHttp
}
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: XVerifyReq: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: XVerifyReq: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field XAnti", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHttp
}
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 ErrInvalidLengthHttp
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.XAnti = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Uid", wireType)
}
m.Uid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHttp
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Uid |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ClientIp", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowHttp
}
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 ErrInvalidLengthHttp
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ClientIp = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipHttp(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthHttp
}
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 (m *XVerifyResp) 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 ErrIntOverflowHttp
}
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: XVerifyResp: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: XVerifyResp: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
default:
iNdEx = preIndex
skippy, err := skipHttp(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthHttp
}
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 skipHttp(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, ErrIntOverflowHttp
}
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, ErrIntOverflowHttp
}
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, ErrIntOverflowHttp
}
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, ErrInvalidLengthHttp
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowHttp
}
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 := skipHttp(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 (
ErrInvalidLengthHttp = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowHttp = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("api/http/v1/http.proto", fileDescriptor_http_6086dd8d3a71844a) }
var fileDescriptor_http_6086dd8d3a71844a = []byte{
// 287 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0x2c, 0xc8, 0xd4,
0xcf, 0x28, 0x29, 0x29, 0xd0, 0x2f, 0x33, 0x04, 0xd3, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42,
0x02, 0x39, 0x99, 0x65, 0xa9, 0x7a, 0x15, 0xc9, 0x89, 0x05, 0x25, 0xc9, 0x19, 0x89, 0x7a, 0x65,
0x86, 0x52, 0xba, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9,
0xe9, 0xf9, 0xfa, 0x60, 0x85, 0x49, 0xa5, 0x69, 0x60, 0x1e, 0x98, 0x03, 0x66, 0x41, 0x0c, 0x50,
0xda, 0xc0, 0xc8, 0xc5, 0x15, 0x11, 0x96, 0x5a, 0x94, 0x99, 0x56, 0x19, 0x94, 0x5a, 0x28, 0x64,
0xc9, 0xc5, 0x1a, 0x9f, 0x98, 0x57, 0x92, 0x29, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0xe9, 0xa4, 0xf2,
0xe9, 0x9e, 0xbc, 0x42, 0x5a, 0x7e, 0x51, 0xae, 0x95, 0x12, 0x58, 0x58, 0x49, 0xa1, 0x2c, 0x31,
0x27, 0x33, 0x25, 0xb1, 0x24, 0xd5, 0x4a, 0xa9, 0x28, 0xb5, 0xb0, 0x34, 0xb3, 0x28, 0x35, 0x45,
0x29, 0x88, 0xc5, 0x31, 0xaf, 0x24, 0x53, 0xc8, 0x84, 0x8b, 0xb9, 0x34, 0x33, 0x45, 0x82, 0x49,
0x81, 0x51, 0x83, 0xd9, 0x49, 0xe9, 0xd3, 0x3d, 0x79, 0x39, 0x88, 0xc6, 0xd2, 0xcc, 0x14, 0xec,
0xda, 0x40, 0xca, 0x85, 0x0c, 0xb9, 0x38, 0x93, 0x73, 0x32, 0x53, 0xf3, 0x4a, 0xe2, 0x33, 0x0b,
0x24, 0x98, 0xc1, 0x96, 0x8a, 0x7c, 0xba, 0x27, 0x2f, 0x00, 0xd1, 0x0b, 0x97, 0x52, 0x0a, 0xe2,
0x80, 0xb0, 0x3d, 0x0b, 0x94, 0x78, 0xb9, 0xb8, 0xe1, 0x2e, 0x2e, 0x2e, 0x30, 0x0a, 0xe0, 0x62,
0x77, 0x86, 0x78, 0x5f, 0xc8, 0x95, 0x8b, 0xad, 0x0c, 0x2c, 0x21, 0x24, 0xa3, 0x87, 0x1e, 0x30,
0x7a, 0x08, 0x5f, 0x4a, 0xc9, 0xe2, 0x91, 0x2d, 0x2e, 0x70, 0x12, 0x38, 0xf1, 0x48, 0x8e, 0xf1,
0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0xa3, 0x98, 0xca, 0x0c, 0x93, 0xd8, 0xc0, 0x81,
0x65, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x50, 0xf8, 0xd1, 0xfb, 0x87, 0x01, 0x00, 0x00,
}

View File

@@ -0,0 +1,21 @@
syntax = "proto3";
package live.xcaptcha.v1;
option go_package = "v1";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
// XCaptcha
service Captcha {
// 验证码校验 `internal:"true"`
rpc verify (XVerifyReq) returns (XVerifyResp);
}
message XVerifyReq {
string _anti = 1 [(gogoproto.moretags) = 'form:"_anti" validate:"required"'];
int64 uid = 2 [(gogoproto.moretags) = 'form:"uid" validate:"required"'];
string client_ip = 3 [(gogoproto.moretags) = 'form:"client_ip"'];
}
message XVerifyResp {
}

View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["test.toml"],
importpath = "go-common/app/service/live/xcaptcha/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/xcaptcha/conf:go_default_library",
"//app/service/live/xcaptcha/server/grpc:go_default_library",
"//app/service/live/xcaptcha/server/http:go_default_library",
"//app/service/live/xcaptcha/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,49 @@
package main
import (
"flag"
"go-common/app/service/live/xcaptcha/conf"
"go-common/app/service/live/xcaptcha/server/grpc"
"go-common/app/service/live/xcaptcha/server/http"
"go-common/app/service/live/xcaptcha/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("xcaptcha-service start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
svc := service.New(conf.Conf)
http.Init(conf.Conf)
grpc.Init(conf.Conf)
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("xcaptcha-service exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,53 @@
[redis]
name = "xcaptcha"
proto = "tcp"
addr = "127.0.0.1:6379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "1m"
[databus]
[databus.captchaAnti]
key = "ec4c0820d525d67b"
secret= "e20f8f664bf10722efeb6aac0cc16011"
group = "CaptchaAnti-LiveLive-P"
topic = "CaptchaAnti-T"
action = "pub"
buffer = 1024
name = "live.xcaptcha"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[geeTest]
on = 1
id = "902f4c9b1b89198603fd65bf5a72553e"
key = "1e37837a105a80fb52150ad2d72bc114"
Timeout = 500
Qps = 100
Slice = 10
[geeTest.Get]
Timeout = 400
KeepAlive = 60
[geeTest.Post]
Timeout = 50
KeepAlive = 60
[logStream]
LogId = "001741"
Token = "1234567844"
Address = "172.18.33.125:15140"
Capacity = 10240
Timeout = "5s"
[liverpc]
[liverpc.captcha]
Addr = "172.22.37.80:20825"
[log]
stdout = true

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 = ["conf.go"],
importpath = "go-common/app/service/live/xcaptcha/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/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc/liverpc:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,125 @@
package conf
import (
"errors"
"flag"
"github.com/BurntSushi/toml"
"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/rpc/liverpc"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"go-common/library/time"
)
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
LiveRpc map[string]*liverpc.ClientConfig
DataBus *DataBus
GeeTest *GeeTestConfig
LogStream *LogStream
}
// DataBus ...
type DataBus struct {
CaptchaAnti *databus.Config
}
// GeeTestConfig ...
type GeeTestConfig struct {
On int64 //是否开启极验
Id string //公钥
Key string //秘钥
Qps int64 //限制qps
Slice int64 //限制qps的key分几份
Get HttpMethod //get配置
Post HttpMethod //post配置
}
// HttpMethod config
type HttpMethod struct {
Timeout int64
KeepAlive int64
}
// LogStream config
type LogStream struct {
LogId string
Token string
Address string
Capacity int
Timeout time.Duration
}
// init
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,44 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"captchaAnti.go",
"dao.go",
"gee.go",
"liveCaptcha.go",
"redis.go",
],
importpath = "go-common/app/service/live/xcaptcha/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/captcha/api/liverpc:go_default_library",
"//app/service/live/captcha/api/liverpc/v0:go_default_library",
"//app/service/live/captcha/api/liverpc/v1:go_default_library",
"//app/service/live/xcaptcha/conf:go_default_library",
"//library/cache/redis:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc/liverpc:go_default_library",
"//library/queue/databus: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,26 @@
package dao
import (
"context"
"go-common/library/log"
"strconv"
)
// PubMessage pub to databus struct
type PubMessage struct {
RoomId int64 `json:"room_id"`
Uid int64 `json:"uid"`
Ip string `json:"ip"`
Action int `json:"action"` // 1create 2verify
ReqType int64 `json:"req_type"` // request captcha type 0image 1geetest
ResType int64 `json:"res_type"` // response captcha type 0image 1geetest
ResCode int64 `json:"res_code"` // 0success 1 failed
}
// Pub databus publish
func (d *Dao) Pub(ctx context.Context, message PubMessage) (err error) {
if err = d.captchaAnti.Send(ctx, strconv.FormatInt(message.Uid, 10), message); err != nil {
log.Error("[XCaptcha][DataBus] call for publish error, err:%v, msg:%v", err, message)
}
return
}

View File

@@ -0,0 +1,50 @@
package dao
import (
"context"
livecaptchaApi "go-common/app/service/live/captcha/api/liverpc"
"go-common/app/service/live/xcaptcha/conf"
"go-common/library/cache/redis"
"go-common/library/net/rpc/liverpc"
"go-common/library/queue/databus"
)
// Dao dao
type Dao struct {
c *conf.Config
redis *redis.Pool
geeClient *GeeClient
liveCaptcha *livecaptchaApi.Client
captchaAnti *databus.Databus
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
redis: redis.NewPool(c.Redis),
geeClient: NewGeeClient(c.GeeTest),
liveCaptcha: livecaptchaApi.New(getConf("captcha")),
captchaAnti: databus.New(c.DataBus.CaptchaAnti),
}
return
}
// getConf get liveRpc conf
func getConf(appName string) *liverpc.ClientConfig {
c := conf.Conf.LiveRpc
if c != nil {
return c[appName]
}
return nil
}
// Close close the resource.
func (d *Dao) Close() {
d.redis.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}

View File

@@ -0,0 +1,166 @@
package dao
import (
"context"
"crypto/tls"
"encoding/json"
"errors"
"go-common/app/service/live/xcaptcha/conf"
"io/ioutil"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
const (
_register = "http://api.geetest.com/register.php"
_validate = "http://api.geetest.com/validate.php"
)
//ValidateRes 验证返回值
type ValidateRes struct {
Seccode string `json:"seccode"`
}
// GeeClient ...
type GeeClient struct {
client *http.Client
clientPost *http.Client
}
// NewGeeClient new httpClient
func NewGeeClient(c *conf.GeeTestConfig) (client *GeeClient) {
client = &GeeClient{
client: NewHttpClient(c.Get.Timeout, c.Get.KeepAlive),
clientPost: NewHttpClient(c.Post.Timeout, c.Post.KeepAlive),
}
return client
}
// Register preprocessing the geetest and get to challenge
func (d *Dao) Register(c context.Context, ip, clientType string, newCaptcha int, captchaID string) (challenge string, err error) {
challenge = ""
var (
bs []byte
params url.Values
)
params = url.Values{}
params.Set("new_captcha", strconv.Itoa(newCaptcha))
params.Set("client_type", clientType)
params.Set("ip_address", ip)
params.Set("gt", captchaID)
if bs, err = d.Get(c, _register, params); err != nil {
return
}
if len(bs) != 32 {
return
}
challenge = string(bs)
return
}
// Validate recheck the challenge code and get to seccode
func (d *Dao) Validate(c context.Context, challenge string, seccode string, clientType string, ip string, mid int64, captchaID string) (res *ValidateRes, err error) {
var (
bs []byte
params url.Values
)
params = url.Values{}
params.Set("seccode", seccode)
params.Set("challenge", challenge)
params.Set("captchaid", captchaID)
params.Set("client_type", clientType)
params.Set("ip_address", ip)
params.Set("json_format", "1")
params.Set("sdk", "golang_3.0.0")
params.Set("user_id", strconv.FormatInt(mid, 10))
params.Set("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
res = &ValidateRes{}
if bs, err = d.Post(c, _validate, params); err != nil {
return
}
if err = json.Unmarshal(bs, &res); err != nil {
return
}
return
}
// NewRequest new a http request.
func NewRequest(method, uri string, params url.Values) (req *http.Request, err error) {
if method == "GET" {
req, err = http.NewRequest(method, uri+"?"+params.Encode(), nil)
} else {
req, err = http.NewRequest(method, uri, strings.NewReader(params.Encode()))
}
if err != nil {
return
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
return
}
// Do handler request
func (d *Dao) Do(c context.Context, req *http.Request, client *http.Client) (body []byte, err error) {
var res *http.Response
req = req.WithContext(c)
if res, err = client.Do(req); err != nil {
return
}
defer res.Body.Close()
if res.StatusCode >= http.StatusInternalServerError {
err = errors.New("http status code 5xx")
return
}
if body, err = ioutil.ReadAll(res.Body); err != nil {
return
}
return
}
// Get client.Get send GET request
func (d *Dao) Get(c context.Context, uri string, params url.Values) (body []byte, err error) {
req, err := NewRequest("GET", uri, params)
if err != nil {
return
}
body, err = d.Do(c, req, d.geeClient.client)
return
}
// Post client.Get send POST request
func (d *Dao) Post(c context.Context, uri string, params url.Values) (body []byte, err error) {
req, err := NewRequest("POST", uri, params)
if err != nil {
return
}
body, err = d.Do(c, req, d.geeClient.clientPost)
return
}
// NewHttpClient new a http client.
func NewHttpClient(timeout int64, keepAlive int64) (client *http.Client) {
var (
transport *http.Transport
dialer *net.Dialer
)
dialer = &net.Dialer{
Timeout: time.Duration(time.Duration(timeout) * time.Millisecond),
KeepAlive: time.Duration(time.Duration(keepAlive) * time.Second),
}
transport = &http.Transport{
DialContext: dialer.DialContext,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client = &http.Client{
Transport: transport,
}
return
}

View File

@@ -0,0 +1,54 @@
package dao
import (
"context"
"go-common/app/service/live/captcha/api/liverpc/v0"
"go-common/app/service/live/captcha/api/liverpc/v1"
"go-common/library/log"
)
// LiveCreate call liveRpc for create captcha
func (d *Dao) LiveCreate(ctx context.Context, width int64, height int64) (resp *v1.CaptchaCreateResp_Data, err error) {
resp = &v1.CaptchaCreateResp_Data{}
rpcReq := &v1.CaptchaCreateReq{
Width: width,
Height: height,
}
rpcResp, err := d.liveCaptcha.V1Captcha.Create(ctx, rpcReq)
if err != nil {
log.Error("[XCaptcha][Create][call liveCaptcha] call error, error:%s", err.Error())
return
}
if rpcResp.Data == nil {
log.Error("[XCaptcha][create][call liveCaptcha] return error, response.data is nil")
return
}
code := rpcResp.Code
msg := rpcResp.Msg
if code != 0 {
log.Error("[XCaptcha][Create][call liveCaptcha] create error, code:%s, msg:%s, data:%s", code, msg, resp)
return
}
resp = rpcResp.Data
return
}
// LiveCheck liveCaptcha check
func (d *Dao) LiveCheck(ctx context.Context, token string, phrase string) (resp int64, err error) {
resp = -400
rpcReq := &v0.CaptchaCheckReq{
Token: token,
Phrase: phrase,
}
rpcResp, err := d.liveCaptcha.V0Captcha.Check(ctx, rpcReq)
if err != nil {
log.Error("[XCaptcha][verify][call liveCaptcha] call error, error:%s", err.Error())
return
}
if rpcResp == nil {
log.Error("[XCaptcha][verify][call liveCaptcha] return error, response is nil")
return
}
resp = rpcResp.Code
return
}

View File

@@ -0,0 +1,72 @@
package dao
import (
"context"
"go-common/library/cache/redis"
"go-common/library/log"
)
// RedisIncr incr a key
func (d *Dao) RedisIncr(ctx context.Context, key string) (num int64, err error) {
num = 0
conn := d.redis.Get(ctx)
defer conn.Close()
err = conn.Send("INCR", key)
if err != nil {
log.Error("[XCaptcha][Redis][error] conn.Send error(%v)", err)
return
}
err = conn.Send("EXPIRE", key, 3)
if err != nil {
log.Error("[XCaptcha][Redis][error] conn.Send error(%v)", err)
return
}
err = conn.Flush()
if err != nil {
log.Error("[XCaptcha][Redis][error] conn.Flush error(%v)", err)
return
}
if num, err = redis.Int64(conn.Receive()); err != nil {
log.Error("[XCaptcha][Redis][error] INCR conn.Receive error(%v)", key, err)
return
}
if _, err = conn.Receive(); err != nil {
log.Error("[XCaptcha][Redis][error] EXPIRE conn.Receive error(%v)", key, err)
return
}
return
}
// RedisGet get a string
func (d *Dao) RedisGet(ctx context.Context, key string) (value int64, err error) {
value = 0
conn := d.redis.Get(ctx)
defer conn.Close()
if value, err = redis.Int64(conn.Do("GET", key)); err != nil {
log.Error("[XCaptcha][Redis][error] GET conn.do error(%v)", key, err)
return
}
return
}
// RedisSet Set a string and expire
func (d *Dao) RedisSet(ctx context.Context, key string, value int64, timeout int64) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if _, err = conn.Do("SET", key, value, "EX", timeout); err != nil {
log.Error("[XCaptcha][Redis][error] SET conn.do error(%v)", key, err)
return
}
return
}
// RedisDel delete a key
func (d *Dao) RedisDel(ctx context.Context, key string) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if _, err = conn.Do("DEL", key); err != nil {
log.Error("[XCaptcha][Redis][error] Delete conn.do error(%v)", key, err)
return
}
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/live/xcaptcha/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 = ["server.go"],
importpath = "go-common/app/service/live/xcaptcha/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/xcaptcha/api/grpc/v1:go_default_library",
"//app/service/live/xcaptcha/conf:go_default_library",
"//app/service/live/xcaptcha/service/v1: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,21 @@
package grpc
import (
pb "go-common/app/service/live/xcaptcha/api/grpc/v1"
"go-common/app/service/live/xcaptcha/conf"
svc "go-common/app/service/live/xcaptcha/service/v1"
"go-common/library/log"
"go-common/library/net/rpc/warden"
)
// Init gRpc Init
func Init(c *conf.Config) {
s := warden.NewServer(nil) // 酌情传入config
// 每个proto里定义的service添加一行
pb.RegisterXCaptchaServer(s.Server(), svc.NewXCaptchaService(c))
_, err := s.Start()
if err != nil {
log.Error("grpc Start error(%v)", err)
panic(err)
}
}

View File

@@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"xcaptcha.go",
],
importpath = "go-common/app/service/live/xcaptcha/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/xcaptcha/api/grpc/v1:go_default_library",
"//app/service/live/xcaptcha/conf:go_default_library",
"//app/service/live/xcaptcha/service:go_default_library",
"//app/service/live/xcaptcha/service/v1: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,57 @@
package http
import (
"go-common/app/service/live/xcaptcha/service/v1"
"net/http"
"go-common/app/service/live/xcaptcha/conf"
"go-common/app/service/live/xcaptcha/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
srv *service.Service
vfy *verify.Verify
xCaptchaService *v1.XCaptchaService
)
// Init init
func Init(c *conf.Config) {
srv = service.New(c)
vfy = verify.New(c.Verify)
engine := bm.DefaultServer(c.BM)
xCaptchaService = v1.NewXCaptchaService(c)
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/xcaptcha")
{
g.GET("/start", vfy.Verify, howToStart)
}
e.GET("/xlive/internal/xcaptcha/v1/xcaptcha/verify", captchaVerify)
}
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.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,16 @@
package http
import (
v12 "go-common/app/service/live/xcaptcha/api/grpc/v1"
"go-common/library/net/http/blademaster"
)
// captchaVerify
func captchaVerify(ctx *blademaster.Context) {
req := new(v12.XVerifyReq)
if err := ctx.Bind(req); err != nil {
return
}
resp, err := xCaptchaService.Verify(ctx, req)
ctx.JSON(resp, err)
}

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 = ["service.go"],
importpath = "go-common/app/service/live/xcaptcha/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/xcaptcha/conf:go_default_library",
"//app/service/live/xcaptcha/dao:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/live/xcaptcha/service/v1:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,33 @@
package service
import (
"context"
"go-common/app/service/live/xcaptcha/conf"
"go-common/app/service/live/xcaptcha/dao"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
}
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["xCaptcha.go"],
importpath = "go-common/app/service/live/xcaptcha/service/v1",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/live/rtc/common:go_default_library",
"//app/service/live/xcaptcha/api/grpc/v1:go_default_library",
"//app/service/live/xcaptcha/conf:go_default_library",
"//app/service/live/xcaptcha/dao:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/sync/pipeline/fanout: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,499 @@
package v1
import (
"context"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"go-common/app/service/live/rtc/common"
v1pb "go-common/app/service/live/xcaptcha/api/grpc/v1"
"go-common/app/service/live/xcaptcha/conf"
"go-common/app/service/live/xcaptcha/dao"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
"go-common/library/sync/pipeline/fanout"
"math/rand"
"strconv"
"time"
)
// XCaptchaService struct
type XCaptchaService struct {
conf *conf.Config
// optionally add other properties here, such as dao
dao *dao.Dao
task *fanout.Fanout
captchaLancer *common.LancerLogStream
}
var (
_geeCaptchaType = int64(1)
_liveImageType = int64(0)
_actionCreate = 1 // 创建行为
_actionValidate = 2 // 校验行为
_responseSuc = int64(0) // 返回成功
_responseFailed = int64(1) // 返回失败
_validateSuc = int64(0) // 校验成功
_validateFalid = int64(1) // 校验失败
_validateParamsErr = int64(3) // 参数非法
_xCaptchaCallGeeNum = "xcaptcha_call_gee_time:%d_num:%d" // qps计数分片减轻热key
_xCaptchaToken = "xcaptcha_type:%d_token:%s" // 二次验证的token缓存
)
// NewXCaptchaService init
func NewXCaptchaService(c *conf.Config) (s *XCaptchaService) {
s = &XCaptchaService{
conf: c,
dao: dao.New(c),
task: fanout.New("task", fanout.Worker(2), fanout.Buffer(10240)),
captchaLancer: common.NewLancerLogStream(c.LogStream.Address, c.LogStream.Capacity, time.Duration(c.LogStream.Timeout)),
}
return s
}
// xCaptcha 相关服务
// Create implementation
// 创建验证码
func (s *XCaptchaService) Create(ctx context.Context, req *v1pb.XCreateCaptchaReq) (resp *v1pb.XCreateCaptchaResp, err error) {
// lancer data
beginTime := time.Now().UnixNano()
resp = &v1pb.XCreateCaptchaResp{
Type: req.GetType(),
}
resp.Geetest = &v1pb.GeeTest{}
resp.Image = &v1pb.Image{}
dataBusM := &dao.PubMessage{
Uid: req.GetUid(),
Ip: req.GetClientIp(),
Action: _actionCreate,
ReqType: req.GetType(),
ResType: req.GetType(),
ResCode: _responseSuc,
}
// 校验是否call geeTest
callGee := false
var (
callGeeBegin int64
callGeeEnd int64
)
degrade := 0
if req.GetType() == _geeCaptchaType {
callGee = s.numCheck(ctx, req.GetUid())
if !callGee { // 触发极验qps限制
degrade = 1
}
}
// call liveCaptcha
if req.GetType() == _liveImageType || !callGee {
resp.Type = _liveImageType
dataBusM.ResType = _liveImageType
begin := time.Now().UnixNano()
resp.Image, err = s.liveCreate(ctx, req.GetWidth(), req.GetHeight())
end := time.Now().UnixNano()
if err != nil {
dataBusM.ResCode = _responseFailed
log.Error("[xCaptcha][Create][create liveCaptcha error] err:%v", err)
}
// 投递消息
s.syncPush(ctx, dataBusM, beginTime, int(end-begin), degrade)
return
}
// call geeTest
if req.GetType() == _geeCaptchaType && callGee {
var (
geeErr error
liveErr error
)
groupTimeout := time.Duration(500 * time.Millisecond)
wg := &errgroup.Group{}
wg.Go(func() error {
// call geeTest
callGeeBegin = time.Now().UnixNano()
cxtHttp, cancel := context.WithTimeout(ctx, groupTimeout)
resp.Geetest, geeErr = s.geeCreate(cxtHttp, req.GetClientType(), req.GetClientIp())
cancel()
callGeeEnd = time.Now().UnixNano()
return geeErr
})
wg.Go(func() error {
cxtLive, cancel := context.WithTimeout(ctx, groupTimeout)
// 创建live captcha
resp.Image, liveErr = s.liveCreate(cxtLive, req.GetWidth(), req.GetHeight())
cancel()
return liveErr
})
wg.Wait()
if geeErr != nil || resp.Geetest.Challenge == "" {
resp.Geetest = &v1pb.GeeTest{}
if liveErr != nil || resp.Image.Token == "" {
dataBusM.ResCode = _responseFailed
log.Error("[xCaptcha][Create][after geeTest error create liveCaptcha error] err:%v", liveErr)
err = ecode.Error(-400, "创建验证码失败,请重试~")
} else {
degrade = 2 // 极验失败时的降级
resp.Type = _liveImageType
dataBusM.ResType = _liveImageType
}
} else {
resp.Image = &v1pb.Image{}
dataBusM.ResType = _geeCaptchaType
}
s.syncPush(ctx, dataBusM, beginTime, int(callGeeEnd-callGeeBegin), degrade)
return
}
return
}
// reqAnti format verify requst
type reqAnti struct {
Type int64
Challenge string
Validate string
SecCode string
ClientType string
Token string
Phrase string
}
// Check implementation
// 验证码校验 `internal:"true"`
func (s *XCaptchaService) Check(ctx context.Context, req *v1pb.CheckReq) (resp *v1pb.CheckResp, err error) {
// lance
beginTime := time.Now().Nanosecond()
resp = &v1pb.CheckResp{}
antiStruct := &reqAnti{}
err = json.Unmarshal([]byte(req.GetAnti()), &antiStruct)
if err != nil {
log.Error("[XCaptcha][Verify][unmarshal request error] err: %v", err)
err = ecode.Error(-400, "校验失败,请重试~")
return
}
if (antiStruct.Type == _liveImageType && (antiStruct.Token == "" || antiStruct.Phrase == "")) ||
(antiStruct.Type == _geeCaptchaType &&
(antiStruct.Challenge == "" || antiStruct.SecCode == "" || antiStruct.Validate == "")) {
err = ecode.Error(-400, "校验失败,请重试~")
return
}
resp.Type = antiStruct.Type
message := &captchaLancerData{
uid: req.GetUid(),
clientIp: req.GetClientIp(),
action: _actionValidate,
reqType: antiStruct.Type,
resType: antiStruct.Type,
}
var (
callBegin int
callEnd int
)
if antiStruct.Type == _liveImageType {
callBegin = time.Now().Nanosecond()
err = s.liveCheck(ctx, antiStruct.Token, antiStruct.Phrase)
callEnd = time.Now().Nanosecond()
if err != nil {
message.resCode = 1
message.reqCost = callEnd - beginTime
message.relyCost = callEnd - callBegin
s.lancerData(ctx, message)
return
}
}
if antiStruct.Type == _geeCaptchaType {
slice := md5.Sum([]byte(s.conf.GeeTest.Key + "geetest" + antiStruct.Challenge))
if len(antiStruct.Validate) != 32 || antiStruct.Validate != hex.EncodeToString(slice[:]) {
err = ecode.Error(-400, "校验失败,请重试~")
return
}
callBegin = time.Now().Nanosecond()
err = s.geeVerify(ctx, antiStruct.Challenge, antiStruct.SecCode, antiStruct.ClientType, req.GetClientIp(), req.GetUid())
callEnd = time.Now().Nanosecond()
if err != nil {
message.resCode = 1
message.reqCost = callEnd - beginTime
message.relyCost = callEnd - callBegin
s.lancerData(ctx, message)
err = ecode.Error(-400, "校验失败,请重试~")
return
}
}
resp.Token, err = s.token(ctx, antiStruct.Type, antiStruct.Token)
if err != nil {
message.resCode = 1
err = ecode.Error(-400, "校验失败,请重试~")
}
message.reqCost = time.Now().Nanosecond() - beginTime
message.relyCost = callEnd - callBegin
s.lancerData(ctx, message)
return
}
// geeCreate geeCreate
func (s *XCaptchaService) geeCreate(ctx context.Context, clientType string, ip string) (resp *v1pb.GeeTest, err error) {
resp = &v1pb.GeeTest{}
id := conf.Conf.GeeTest.Id
privateKey := conf.Conf.GeeTest.Key
challenge, err := s.dao.Register(ctx, ip, clientType, 1, id)
if err != nil || challenge == "" {
log.Error("[xCaptcha][Create][call geetest error] err:%v", err)
err = ecode.Error(-400, "创建验证码失败,请重试~")
return
}
slice := md5.Sum([]byte(challenge + privateKey))
resp.Challenge = hex.EncodeToString(slice[:])
resp.Gt = id
return
}
// geeVerify geeTest verify
func (s *XCaptchaService) geeVerify(ctx context.Context, challenge string, seccode string, clientType string, ip string, mid int64) (err error) {
res, err := s.dao.Validate(ctx, clientType, seccode, clientType, ip, mid, s.conf.GeeTest.Id)
if err != nil {
log.Error("[xCaptcha][Verify][call geetest error] err:%v", err)
err = ecode.Error(1, "校验失败,请重试~")
return
}
seccodeMd5 := md5.Sum([]byte(seccode))
if res == nil || res.Seccode != hex.EncodeToString(seccodeMd5[:]) {
log.Error("[xCaptcha][Verify][call geetest error] err:%v, res.secCode:%v, seccode:%v", err, res.Seccode, seccode)
err = ecode.Error(-400, "校验失败,请重试~")
return
}
return
}
// liveCreate 创建直播验证码
func (s *XCaptchaService) liveCreate(ctx context.Context, width int64, height int64) (resp *v1pb.Image, err error) {
resp = &v1pb.Image{}
liveResp, err := s.dao.LiveCreate(ctx, width, height)
if err != nil || liveResp.Token == "" || liveResp.Image == "" {
err = ecode.Error(-400, "创建验证码失败,请重试~")
return
}
resp.Tips = "请输入验证码"
resp.Token = liveResp.Token
resp.Content = liveResp.Image
return
}
// liveCheck 校验直播验证码
func (s *XCaptchaService) liveCheck(ctx context.Context, token string, pharse string) (err error) {
liveResp, err := s.dao.LiveCheck(ctx, token, pharse)
if err != nil || liveResp != 0 {
err = ecode.Error(1, "校验失败,请重试~")
return
}
if liveResp != 0 {
err = ecode.Error(-400, "校验失败,请重试~")
return
}
return
}
// numCheck qps check
func (s *XCaptchaService) numCheck(ctx context.Context, uid int64) (check bool) {
check = false
if s.conf.GeeTest.On == 0 {
return
}
qps := s.conf.GeeTest.Qps
slice := s.conf.GeeTest.Slice
if qps <= 0 {
qps = 100
}
if slice <= 0 || slice > 10 {
slice = 5
}
each := int64(qps / slice)
rand.Seed(time.Now().UnixNano())
slot := rand.Intn(int(slice))
timestamp := time.Now().Unix()
key := fmt.Sprintf(_xCaptchaCallGeeNum, timestamp, slot)
count, err := s.dao.RedisIncr(ctx, key)
if err != nil {
return
}
if count < each {
check = true
}
return
}
// syncPush
func (s *XCaptchaService) syncPush(ctx context.Context, message *dao.PubMessage, reqBegin int64, relyCost int, degrade int) {
object := dao.PubMessage{
Uid: message.Uid,
Ip: message.Ip,
Action: message.Action,
ReqType: message.ReqType,
ResType: message.ResType,
ResCode: message.ResCode,
}
if reqBegin != 0 {
// 埋点
now := time.Now().UnixNano()
lancerData := &captchaLancerData{
uid: message.Uid,
clientIp: message.Ip,
action: message.Action,
reqType: message.ReqType,
resType: message.ResType,
resCode: message.ResCode,
reqCost: int(now - reqBegin),
relyCost: relyCost,
degrade: degrade,
}
s.lancerData(ctx, lancerData)
}
// sync push dataBus
f := func(ctx context.Context) {
err := s.dao.Pub(ctx, object)
if err == nil {
log.Info("[xCaptcha][PubMessage][success] message :%+v", object)
}
}
sync := s.task.Do(ctx, func(c context.Context) {
f(c)
})
if sync != nil {
log.Error("[xCaptcha][PubMessage][task Full] err:%v, message:%+v", sync, object)
f(ctx)
}
}
// XAnti token校验参数
type XAnti struct {
Type int64
Token string
}
// Verify implementation
// checkToken `internal:"true"`
func (s *XCaptchaService) Verify(ctx context.Context, req *v1pb.XVerifyReq) (resp *v1pb.XVerifyResp, err error) {
resp = &v1pb.XVerifyResp{}
dataBusM := &dao.PubMessage{
RoomId: req.GetRoomId(),
Uid: req.GetUid(),
Ip: req.GetClientIp(),
Action: _actionValidate,
}
antiBytes, err := base64.URLEncoding.DecodeString(req.GetXAnti())
if err != nil {
log.Error("[XCaptcha][TokenCheck][base64decode request error] err: %v", err)
err = ecode.Error(-400, "验证口令失败~")
dataBusM.ResCode = _validateParamsErr
s.syncPush(ctx, dataBusM, 0, 0, 0)
return
}
xAnti := &XAnti{}
err = json.Unmarshal(antiBytes, &xAnti)
if err != nil {
log.Error("[XCaptcha][TokenCheck][unmarshal request error] err: %v", err)
err = ecode.Error(-400, "验证口令失败~")
dataBusM.ResCode = _validateParamsErr
s.syncPush(ctx, dataBusM, 0, 0, 0)
return
}
dataBusM.ReqType = xAnti.Type
dataBusM.ResType = xAnti.Type
key := fmt.Sprintf(_xCaptchaToken, xAnti.Type, xAnti.Token)
value, err := s.dao.RedisGet(ctx, key)
if err != nil || value == 0 {
log.Error("[XCaptcha][TokenCheck][Token Wrong] err: %v", err)
err = ecode.Error(-400, "验证口令失败~")
dataBusM.ResCode = _validateFalid
s.syncPush(ctx, dataBusM, 0, 0, 0)
return
}
// 校验成功, 删除token
err = s.dao.RedisDel(ctx, key)
if err != nil {
log.Error("[XCaptcha][TokenCheck][Token Check Over del key] err: %v", err)
err = ecode.Error(-400, "验证口令失败~")
return
}
dataBusM.ResCode = _validateSuc
s.syncPush(ctx, dataBusM, 0, 0, 0)
return
}
func (s *XCaptchaService) token(ctx context.Context, cType int64, base string) (token string, err error) {
slice := md5.Sum([]byte(strconv.Itoa(int(cType)) + base))
token = hex.EncodeToString(slice[:])
err = s.dao.RedisSet(ctx, fmt.Sprintf(_xCaptchaToken, cType, token), 1, 300)
return
}
// captchaLancerData lancer 上报
type captchaLancerData struct {
uid int64
clientIp string
action int
reqType int64
resType int64
resCode int64
reqCost int
relyCost int
degrade int
}
func (s *XCaptchaService) lancerData(ctx context.Context, data *captchaLancerData) {
data.reqCost = int(data.reqCost / 1e6)
data.relyCost = int(data.relyCost / 1e6)
ld := s.captchaLancer.NewLancerData(s.conf.LogStream.LogId, s.conf.LogStream.Token)
ld.PutInt(data.uid)
ld.PutString(data.clientIp)
ld.PutInt(int64(data.action))
ld.PutInt(data.reqType)
ld.PutInt(data.resType)
ld.PutInt(data.resCode)
ld.PutInt(int64(data.reqCost))
ld.PutInt(int64(data.relyCost))
ld.PutInt(int64(data.degrade))
log.Info("[XCaptcha][lancerData][logStream] data:%+v", data)
if err := ld.Commit(); err != nil {
log.Error("[XCaptcha][lancerData][logStream] err: %v", err)
}
/**
f := func(ctx context.Context) {
log.Info("[XCaptcha][lancerData][info] data:%+v", data)
infocErr := s.captchaLancer.Info(data.uid, data.clientIp, data.action, data.reqType, data.resType, data.resCode, data.reqCost, data.relyCost, data.degrade)
if infocErr != nil {
log.Error("[XCaptcha][lancerData][infoc error] err: %v", infocErr)
}
}
sync := s.task.Do(ctx, func(c context.Context) {
f(c)
})
if sync != nil {
log.Error("[XCaptcha][lancerData][sync error] err: %v", sync)
}
**/
}