Create & Init Project...

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

View File

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

View File

@@ -0,0 +1,195 @@
### location-service
#### Version 6.1.1
> 1.account grpc
#### Version 6.1.0
> 1.迁移gRPC目录
#### Version 6.0.0
> 1.使用IPIP的IPv4库
> 2.使用IPIP的IPv6库
> 3.去掉rpc的Zone、Zones、Info2接口
#### Version 5.8.6
> 1.删除dao层无用代码
> 2.VPN匿名库去掉本地文件逻辑
> 3.重构authByPids(旧接口已无调用)
#### Version 5.8.5
> 1.单IP查询接口判断nil
#### Version 5.8.4
> 1.IP查询接口增加country_code
#### Version 5.8.3
> 1.视频云IP库和旧库的加载逻辑对齐
#### Version 5.8.2
> 1.live zk空配置不注册
#### Version 5.8.1 - 2018.09.29
###### Features
> 1.判断IP是否为VPN地址
> 2.增加批量查询gid权限接口
#### Version 5.8.0 - 2018.08.14
###### Features
> 1.优先使用二进制IP库
#### Version 4.8.0 - 2018.08.08
###### Features
> 1.identify为grpc切换verify
#### Version 4.7.4 - 2018.07.10
###### BugFix
> 1.修复grpc方法的返回值是nil导致的panic
#### Version 4.7.3 - 2018.07.09
###### Features
> 1.grpc增加注册liveZK逻辑
#### Version 4.7.2 - 2018.07.03
###### Features
> 1.增加grpc接口
#### Version 4.7.1 - 2018.06.05
###### Features
> 1.policy_item、policy_group表增加软删除过滤
#### Version 4.7.0 - 2018.05.03
###### Features
> 1.http切bm
#### Version 4.6.0 - 2018.04.24
###### Features
> 1.rpc lient 增加discovery new方法
#### Version 4.5.2 - 2018.04.12
###### Features
> 1.接discovery添加register接口
#### Version 4.5.1 - 2018.03.25
###### Features
> 1.使用account-service v7
#### Version 4.5.0 - 2018.03.12
###### Features
> 1.添加archive2接口(http和rpc)
#### Version 4.4.0 - 2018.03.07
###### Features
> 1.添加AuthPIDs接口判断ipaddr是否符合规则pids
#### Version 4.3.1 - 2017.10.22
###### Features
> 1.archive和group接口如果传的是局域网IP使用CDNIP
#### Version 4.3.0 - 2017.09.27
###### Features
> 1.重构zone和check的http、rpc接口第一版写的什么辣鸡玩意儿)
> 2.删除dat格式IP库的解析逻辑
> 3.删除下载IP库文件接口
> 4.删除获取IP库全部数据的rpc接口
> 5.去掉ecode初始化
#### Version 4.2.0 - 2017.09.08
###### Features
> 1.添加根据pids和ip获取稿件权限的RPC和HTTP接口
#### Version 4.1.0 - 2017.09.08
###### Features
> 1.添加根据pids和ip获取稿件权限的RPC和HTTP接口
#### Version 4.0.0 - 2017.07.21
###### Features
> 1.business/model/location移到项目目录中(business/service/main/location/model)
> 2.添加CONTRIBUTORS.md和CHANGELOG.md
#### Version 3.0.0
###### Features
> 1.location-service meger into Kratos/business/service
#### Version 2.0.0
###### Features
> 1.更新go-common v7.0.0
> 2.去掉go-business 依赖
> 3.添加rpc方法Info2和Infos2查询IP信息并返回完整zoned_id组
#### Version 1.4.4
###### Features
> 1.完善prom监控
#### Version 1.4.3
###### Features
> 1.添加prom监控
#### Version 1.4.1
###### Features
> 1.修改http层Verify初始化方法
#### Version 1.4.0
###### Features
> 1.重新接新版配置中心
> 2.添加获取指定aid的地区限制规则API
> 3.添加获取指定规则组的地区限制规则API
#### Version 1.3.9
###### Features
> 1.暂时改回旧版配置中心
#### Version 1.3.8
###### Features
> 1.接新配置中心
> 2.更新了rpc的调用
#### Version 1.3.6
###### Features
> 1.逻辑重构
> 2.单IP查询接口
> 3.多IP查询接口
> 4.规则查询接口(根据ip、aid、policy_id、group_id)
> 5.是否可观看查询接口
> 6.根据group_id批量查询可观看的zone_ids
> 7.添加强制刷新规则缓存接口
> 8.添加管理接口,自动下载(运维提供地址)IP库文件并重新加载(只支持.dat文件)
> 9.添加.dat和.txt双IP库文件识别根据不同IP库文件调用不同的加载方法和查询方法
#### Version 1.3.3
###### Features
> 1.多IP查询接口
#### Version 1.3.1
###### Features
> 1.升级go-common v6.2.4,go-business v2.4.3, golang v2.9.1
#### Version 1.3.0
###### Features
> 1.增加zone 接口代替check接口.
> 2.升级go-common v5.2.2,go-business location, golang v2.6.0
#### Version 1.2.0
###### Features
> 1.接入配置中心和CI系统.
#### Version 1.1.0
###### Features
> 1.升级go-common v5.0.0,golang v2.6.0,go-business v2.2.1
#### Version 1.0.0
###### Features
> 1.升级go-common v4.4.1,golang v2.5.3,go-business v2.1.0
> 2.增加下载IP库
#### Version 0.1.0
###### Features
> 1.接入配置中心
> 2.go-common develop分支
###### Bug Fixes
> 1.修复查找算法
#### Version 0.0.1
###### Features
> 1.查询IP接口
> 2.支持vendor

View File

@@ -0,0 +1,11 @@
# Owner
peiyifei
liweijia
haoguanwei
# Author
yujia
# Reviewer
haoguanwei
peiyifei

View File

@@ -0,0 +1,21 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- haoguanwei
- liweijia
- peiyifei
- yujia
- liangkai
- zhangshengchao
labels:
- main
- service
- service/main/location
options:
no_parent_owners: true
reviewers:
- haoguanwei
- peiyifei
- yujia
- liangkai
- zhangshengchao

View File

@@ -0,0 +1,24 @@
#### location-service
##### 项目简介
> 1.提供IP信息查询的接口
> 2.提供各种不同应用场景的关于IP与稿件地区限制规则的查询接口
##### 编译环境
> 请只用golang v1.7.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common
##### 编译执行
> 在主目录执行go build。
> 编译后可执行 ./location -conf location-example.toml 使用项目本地配置文件启动服务。
> 也可执行 ./location -conf_appid=location-service -conf_version=v2.1.0 -conf_host=172.16.33.134:9011 -conf_path=/data/conf/location-service -conf_env=10 -conf_token=J8MnvX8woVZmdwQ78HIFe26QOgleuxd4 使用配置中心测试环境配置启动服务如无法启动可检查token是否正确。
##### RPC测试
> 具体的测试内容可修改rpc/rpc_test.go文件。
> 在rpc目录执行go test测试rpc接口。
##### 特别说明
> 1.model目录可能会被其他项目引用请谨慎请改并通知各方。
> 2.http接口文档可参考 http://syncsvn.bilibili.co/platform/doc/blob/master/api/location-service/v3.md

View File

@@ -0,0 +1,54 @@
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"],
)
go_proto_library(
name = "api_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_grpc"],
importpath = "go-common/app/service/main/location/api",
proto = ":api_proto",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
embed = [":api_go_proto"],
importpath = "go-common/app/service/main/location/api",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/rpc/warden:go_default_library",
"@com_github_golang_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,803 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: app/service/main/location/api/v1/api.proto
/*
Package v1 is a generated protocol buffer package.
It is generated from these files:
app/service/main/location/api/v1/api.proto
It has these top-level messages:
InfoReply
InfoReq
*/
package api
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import context "golang.org/x/net/context"
import grpc "google.golang.org/grpc"
import binary "encoding/binary"
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.ProtoPackageIsVersion2 // please upgrade the proto package
type InfoReply struct {
Addr string `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"`
Country string `protobuf:"bytes,2,opt,name=country,proto3" json:"country,omitempty"`
Province string `protobuf:"bytes,3,opt,name=province,proto3" json:"province,omitempty"`
City string `protobuf:"bytes,4,opt,name=city,proto3" json:"city,omitempty"`
Isp string `protobuf:"bytes,5,opt,name=isp,proto3" json:"isp,omitempty"`
Latitude float64 `protobuf:"fixed64,6,opt,name=latitude,proto3" json:"latitude,omitempty"`
Longitude float64 `protobuf:"fixed64,7,opt,name=longitude,proto3" json:"longitude,omitempty"`
ZoneId int64 `protobuf:"varint,8,opt,name=zone_id,json=zoneId,proto3" json:"zoneId,omitempty"`
}
func (m *InfoReply) Reset() { *m = InfoReply{} }
func (m *InfoReply) String() string { return proto.CompactTextString(m) }
func (*InfoReply) ProtoMessage() {}
func (*InfoReply) Descriptor() ([]byte, []int) { return fileDescriptorApi, []int{0} }
func (m *InfoReply) GetAddr() string {
if m != nil {
return m.Addr
}
return ""
}
func (m *InfoReply) GetCountry() string {
if m != nil {
return m.Country
}
return ""
}
func (m *InfoReply) GetProvince() string {
if m != nil {
return m.Province
}
return ""
}
func (m *InfoReply) GetCity() string {
if m != nil {
return m.City
}
return ""
}
func (m *InfoReply) GetIsp() string {
if m != nil {
return m.Isp
}
return ""
}
func (m *InfoReply) GetLatitude() float64 {
if m != nil {
return m.Latitude
}
return 0
}
func (m *InfoReply) GetLongitude() float64 {
if m != nil {
return m.Longitude
}
return 0
}
func (m *InfoReply) GetZoneId() int64 {
if m != nil {
return m.ZoneId
}
return 0
}
type InfoReq struct {
Addr string `protobuf:"bytes,2,opt,name=addr,proto3" json:"addr,omitempty"`
}
func (m *InfoReq) Reset() { *m = InfoReq{} }
func (m *InfoReq) String() string { return proto.CompactTextString(m) }
func (*InfoReq) ProtoMessage() {}
func (*InfoReq) Descriptor() ([]byte, []int) { return fileDescriptorApi, []int{1} }
func (m *InfoReq) GetAddr() string {
if m != nil {
return m.Addr
}
return ""
}
func init() {
proto.RegisterType((*InfoReply)(nil), "location.service.InfoReply")
proto.RegisterType((*InfoReq)(nil), "location.service.InfoReq")
}
// 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
// Client API for Location service
type LocationClient interface {
// Info get ip info.
Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*InfoReply, error)
}
type locationClient struct {
cc *grpc.ClientConn
}
func NewLocationClient(cc *grpc.ClientConn) LocationClient {
return &locationClient{cc}
}
func (c *locationClient) Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*InfoReply, error) {
out := new(InfoReply)
err := grpc.Invoke(ctx, "/location.service.Location/Info", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Location service
type LocationServer interface {
// Info get ip info.
Info(context.Context, *InfoReq) (*InfoReply, error)
}
func RegisterLocationServer(s *grpc.Server, srv LocationServer) {
s.RegisterService(&_Location_serviceDesc, srv)
}
func _Location_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(InfoReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(LocationServer).Info(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/location.service.Location/Info",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(LocationServer).Info(ctx, req.(*InfoReq))
}
return interceptor(ctx, in, info, handler)
}
var _Location_serviceDesc = grpc.ServiceDesc{
ServiceName: "location.service.Location",
HandlerType: (*LocationServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Info",
Handler: _Location_Info_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "app/service/main/location/api/v1/api.proto",
}
func (m *InfoReply) 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 *InfoReply) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Addr) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintApi(dAtA, i, uint64(len(m.Addr)))
i += copy(dAtA[i:], m.Addr)
}
if len(m.Country) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintApi(dAtA, i, uint64(len(m.Country)))
i += copy(dAtA[i:], m.Country)
}
if len(m.Province) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintApi(dAtA, i, uint64(len(m.Province)))
i += copy(dAtA[i:], m.Province)
}
if len(m.City) > 0 {
dAtA[i] = 0x22
i++
i = encodeVarintApi(dAtA, i, uint64(len(m.City)))
i += copy(dAtA[i:], m.City)
}
if len(m.Isp) > 0 {
dAtA[i] = 0x2a
i++
i = encodeVarintApi(dAtA, i, uint64(len(m.Isp)))
i += copy(dAtA[i:], m.Isp)
}
if m.Latitude != 0 {
dAtA[i] = 0x31
i++
binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Latitude))))
i += 8
}
if m.Longitude != 0 {
dAtA[i] = 0x39
i++
binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Longitude))))
i += 8
}
if m.ZoneId != 0 {
dAtA[i] = 0x40
i++
i = encodeVarintApi(dAtA, i, uint64(m.ZoneId))
}
return i, nil
}
func (m *InfoReq) 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 *InfoReq) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Addr) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintApi(dAtA, i, uint64(len(m.Addr)))
i += copy(dAtA[i:], m.Addr)
}
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 *InfoReply) Size() (n int) {
var l int
_ = l
l = len(m.Addr)
if l > 0 {
n += 1 + l + sovApi(uint64(l))
}
l = len(m.Country)
if l > 0 {
n += 1 + l + sovApi(uint64(l))
}
l = len(m.Province)
if l > 0 {
n += 1 + l + sovApi(uint64(l))
}
l = len(m.City)
if l > 0 {
n += 1 + l + sovApi(uint64(l))
}
l = len(m.Isp)
if l > 0 {
n += 1 + l + sovApi(uint64(l))
}
if m.Latitude != 0 {
n += 9
}
if m.Longitude != 0 {
n += 9
}
if m.ZoneId != 0 {
n += 1 + sovApi(uint64(m.ZoneId))
}
return n
}
func (m *InfoReq) Size() (n int) {
var l int
_ = l
l = len(m.Addr)
if l > 0 {
n += 1 + l + sovApi(uint64(l))
}
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 *InfoReply) 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: InfoReply: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: InfoReply: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Addr", 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.Addr = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Country", 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.Country = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Province", 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.Province = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field City", 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.City = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Isp", 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.Isp = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 6:
if wireType != 1 {
return fmt.Errorf("proto: wrong wireType = %d for field Latitude", wireType)
}
var v uint64
if (iNdEx + 8) > l {
return io.ErrUnexpectedEOF
}
v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))
iNdEx += 8
m.Latitude = float64(math.Float64frombits(v))
case 7:
if wireType != 1 {
return fmt.Errorf("proto: wrong wireType = %d for field Longitude", wireType)
}
var v uint64
if (iNdEx + 8) > l {
return io.ErrUnexpectedEOF
}
v = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))
iNdEx += 8
m.Longitude = float64(math.Float64frombits(v))
case 8:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ZoneId", wireType)
}
m.ZoneId = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApi
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ZoneId |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
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
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *InfoReq) 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: InfoReq: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: InfoReq: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Addr", 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.Addr = 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
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipApi(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApi
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApi
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApi
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthApi
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowApi
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipApi(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowApi = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("app/service/main/location/api/v1/api.proto", fileDescriptorApi) }
var fileDescriptorApi = []byte{
// 281 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x50, 0x4d, 0x4a, 0xc4, 0x30,
0x18, 0x35, 0xd3, 0xda, 0x9f, 0x6f, 0x35, 0x04, 0xc1, 0x38, 0x6a, 0x29, 0xb3, 0x2a, 0x2e, 0x5a,
0x46, 0xf7, 0x2e, 0xdc, 0x8d, 0xb8, 0xea, 0xd2, 0x8d, 0xc4, 0x36, 0x4a, 0xa0, 0x26, 0x31, 0x93,
0x29, 0xd4, 0x93, 0x78, 0x24, 0x57, 0xe2, 0x11, 0xa4, 0x5e, 0x44, 0x92, 0x76, 0x3a, 0x20, 0xb8,
0xca, 0xfb, 0xc9, 0xf7, 0xe0, 0x3d, 0xb8, 0xa0, 0x4a, 0x15, 0x1b, 0xa6, 0x5b, 0x5e, 0xb1, 0xe2,
0x85, 0x72, 0x51, 0x34, 0xb2, 0xa2, 0x86, 0x4b, 0x51, 0x50, 0xc5, 0x8b, 0x76, 0x65, 0x9f, 0x5c,
0x69, 0x69, 0x24, 0x9e, 0xef, 0xac, 0x7c, 0x3c, 0x58, 0x7e, 0x22, 0x88, 0xd7, 0xe2, 0x49, 0x96,
0x4c, 0x35, 0x1d, 0xc6, 0xe0, 0xd3, 0xba, 0xd6, 0x04, 0xa5, 0x28, 0x8b, 0x4b, 0x87, 0x31, 0x81,
0xb0, 0x92, 0x5b, 0x61, 0x74, 0x47, 0x66, 0x4e, 0xde, 0x51, 0xbc, 0x80, 0x48, 0x69, 0xd9, 0x72,
0x51, 0x31, 0xe2, 0x39, 0x6b, 0xe2, 0x36, 0xa9, 0xe2, 0xa6, 0x23, 0xfe, 0x90, 0x64, 0x31, 0x9e,
0x83, 0xc7, 0x37, 0x8a, 0x1c, 0x3a, 0xc9, 0x42, 0x9b, 0xd0, 0x50, 0xc3, 0xcd, 0xb6, 0x66, 0x24,
0x48, 0x51, 0x86, 0xca, 0x89, 0xe3, 0x33, 0x88, 0x1b, 0x29, 0x9e, 0x07, 0x33, 0x74, 0xe6, 0x5e,
0xc0, 0xc7, 0x10, 0xbe, 0x49, 0xc1, 0x1e, 0x78, 0x4d, 0xa2, 0x14, 0x65, 0x5e, 0x19, 0x58, 0xba,
0xae, 0x97, 0xe7, 0x10, 0x0e, 0x7d, 0x5e, 0xa7, 0x36, 0xb3, 0x7d, 0x9b, 0xcb, 0x5b, 0x88, 0xee,
0xc6, 0x0d, 0xf0, 0x35, 0xf8, 0xf6, 0x2b, 0x3e, 0xc9, 0xff, 0xce, 0x92, 0x8f, 0x11, 0x8b, 0xd3,
0xff, 0x2c, 0xd5, 0x74, 0x37, 0x47, 0x1f, 0x7d, 0x82, 0xbe, 0xfa, 0x04, 0x7d, 0xf7, 0x09, 0x7a,
0xff, 0x49, 0x0e, 0xee, 0x67, 0xed, 0xea, 0x31, 0x70, 0x53, 0x5f, 0xfd, 0x06, 0x00, 0x00, 0xff,
0xff, 0x51, 0x4f, 0x85, 0x70, 0x98, 0x01, 0x00, 0x00,
}

View File

@@ -0,0 +1,28 @@
// +bili:type=service
// Code generated by warden.
syntax = "proto3";
package location.service;
option go_package = "api";
message InfoReply {
string addr = 1;
string country = 2;
string province = 3;
string city = 4;
string isp = 5;
double latitude = 6;
double longitude = 7;
int64 zone_id = 8;
}
message InfoReq {
string addr = 2;
}
service Location {
// Info get ip info.
rpc Info(InfoReq) returns(InfoReply);
}

View File

@@ -0,0 +1,22 @@
package api
import (
"context"
"go-common/library/net/rpc/warden"
"google.golang.org/grpc"
)
// AppID unique app id for service discovery
const AppID = "location.service"
// NewClient new member grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (LocationClient, error) {
client := warden.NewClient(cfg, opts...)
conn, err := client.Dial(context.Background(), "discovery://default/"+AppID)
if err != nil {
return nil, err
}
return NewLocationClient(conn), nil
}

View File

@@ -0,0 +1,49 @@
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 = [
"convey-test.toml",
"location-example.toml",
],
importpath = "go-common/app/service/main/location/cmd",
tags = ["automanaged"],
deps = [
"//app/service/main/location/conf:go_default_library",
"//app/service/main/location/rpc/server:go_default_library",
"//app/service/main/location/server/grpc:go_default_library",
"//app/service/main/location/server/http:go_default_library",
"//app/service/main/location/service:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/rpc/warden/resolver/livezk: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,114 @@
# This is a TOML document. Boom.
version = "2.1.0"
user = "nobody"
pid = "/tmp/location-service.pid"
dir = "./"
perf = "0.0.0.0:6290"
checkFile = "/data/www/location.html"
family = "location-service"
filePath = "../cmd/source"
fileName = "SinaIP.txt"
filterZone = ["共享地址","局域网","本机地址"]
[tracer]
family = "location-service"
proto = "unixgram"
addr = "172.16.33.46:5140"
[log]
dir = "/data/log/location-service/"
[db]
[db.zlimit]
name = "172.16.33.205:3308"
dsn = "test:test@tcp(172.16.33.205:3308)/bilibili_oversea?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[db.zlimit.breaker]
window ="3s"
sleep ="100ms"
bucket = 10
ratio = 0.5
request = 100
[redis]
[redis.zlimit]
name = "location-service"
proto = "tcp"
#addr = "172.16.33.54:6379"
addr = "172.18.33.61:6812"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "10s"
[identify]
whiteAccessKey = ""
whiteMid = 0
[identify.app]
key = "53e2fa226f5ad348"
secret = "3cf6bd1b0ff671021da5f424fea4b04a"
[identify.host]
auth = "http://passport.bilibili.com"
secret = "http://open.bilibili.com"
[identify.httpClient]
key = "53e2fa226f5ad348"
secret = "3cf6bd1b0ff671021da5f424fea4b04a"
dial = "30ms"
timeout = "100ms"
keepAlive = "60s"
[identify.httpClient.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[identify.httpClient.url]
"http://passport.bilibili.co/intranet/auth/tokenInfo" = {timeout = "100ms"}
"http://passport.bilibili.co/intranet/auth/cookieInfo" = {timeout = "100ms"}
"http://open.bilibili.co/api/getsecret" = {timeout = "500ms"}
[multiHTTP]
[multiHTTP.inner]
addrs = ["0.0.0.0:6291"]
[multiHTTP.local]
addrs = ["0.0.0.0:6292"]
[rpcServer2]
[[rpcServer2.servers]]
proto = "tcp"
addr = "0.0.0.0:6293"
weight = 10
[rpcServer2.zookeeper]
root = "/microservice/location-service/"
addrs = ["172.18.33.172:2181"]
timeout = "30s"
[accountRPC]
pullInterval = "10s"
group ="groupapp"
[accountRPC.client]
token="123456"
proto = "tcp"
addr = "172.16.33.56:6079"
timeout = "10s"
timer = 1000
[accountRPC.client.breaker]
window ="10s"
sleep ="10ms"
bucket = 10
ratio = 0.5
request = 100
[accountRPC.zookeeper]
root = "/microservice/account-service/"
addrs = ["172.18.33.172:2181"]
timeout = "30s"

View File

@@ -0,0 +1,87 @@
filePath = "./source"
ipv4Name = "mydata4vipday4.ipdb"
ipv6Name = "mydata6vipday4.ipdb"
anonymFileName = "GeoIP2-Anonymous-IP.mmdb"
anonymKey = "cOp1pc4JZRpf"
filterZone = ["共享地址","局域网","本机地址"]
[host]
maxmind = "https://download.maxmind.com"
bvcip = "http://bvc-nerve.bilibili.co"
[log]
dir = "/data/log/location-service/"
[db]
[db.zlimit]
name = "127.0.0.1:3306"
dsn = "root:test@tcp(127.0.0.1:3306)/bilibili_oversea?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 5
idleTimeout ="4h"
queryTimeout = "1s"
execTimeout = "1s"
tranTimeout = "1s"
[db.zlimit.breaker]
window ="3s"
sleep ="100ms"
bucket = 10
ratio = 0.5
request = 100
[redis]
[redis.zlimit]
name = "location-service"
proto = "tcp"
addr = "172.18.33.61:6812"
#addr = "172.16.33.54:6379"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "10s"
[bm]
[bm.inner]
addr = "0.0.0.0:6291"
timeout = "1s"
[bm.local]
addr = "0.0.0.0:6292"
timeout = "1s"
[rpcServer2]
[[rpcServer2.servers]]
proto = "tcp"
addr = "0.0.0.0:6293"
weight = 10
[rpcServer2.zookeeper]
root = "/microservice/location-service/"
addrs = ["172.18.33.172:2181"]
timeout = "30s"
[wardenServer]
addr = "0.0.0.0:9000"
timeout = "1s"
[liveZK]
addrs = ["172.22.33.130:2181"]
timeout = "30s"
[httpClient]
key = "e7482d29be4a95b8"
secret = "9e803791cdef756e75faee68e12b7442"
dial = "80ms"
timeout = "100ms"
keepAlive = "60s"
[httpClient.breaker]
window = "1s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.Host]
"api.live.bilibili.co" = {timeout = "200ms"}
[httpClient.url]
"http://api.bilibili.co/x/internal/v2/fav/video" = {timeout = "500ms"}

View File

@@ -0,0 +1,76 @@
package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/location/conf"
rpc "go-common/app/service/main/location/rpc/server"
"go-common/app/service/main/location/server/grpc"
"go-common/app/service/main/location/server/http"
"go-common/app/service/main/location/service"
"go-common/library/log"
"go-common/library/net/rpc/warden"
"go-common/library/net/rpc/warden/resolver/livezk"
"go-common/library/net/trace"
)
const (
discoveryID = "location.service"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
// init log
log.Init(conf.Conf.Log)
trace.Init(conf.Conf.Tracer)
defer trace.Close()
defer log.Close()
// service init
svr := service.New(conf.Conf)
rpcSvr := rpc.New(conf.Conf, svr)
// warden init
var err error
var cancelzk context.CancelFunc = func() {}
var grpcSvr *warden.Server
if conf.Conf.WardenServer != nil {
grpcSvr = grpc.New(conf.Conf.WardenServer, svr)
if conf.Conf.LiveZK != nil {
if cancelzk, err = livezk.Register(conf.Conf.LiveZK, conf.Conf.WardenServer.Addr, discoveryID); err != nil {
panic(err)
}
}
}
// http init
http.Init(conf.Conf, svr, rpcSvr)
log.Info("location-service start")
// init signal
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for s := range c {
log.Info("location-service get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
cancelzk()
if grpcSvr != nil {
grpcSvr.Shutdown(context.Background())
}
rpcSvr.Close()
time.Sleep(2 * time.Second)
log.Info("location-service exit")
return
case syscall.SIGHUP:
// TODO reload
default:
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 = ["conf.go"],
importpath = "go-common/app/service/main/location/conf",
tags = ["automanaged"],
deps = [
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/naming/livezk:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,128 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/naming/livezk"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
// Conf is global config
Conf *Config
)
// Config service config
type Config struct {
// base
// db
DB *DB
// redis
Redis *Redis
// xlog
Log *log.Config
// verify
Verify *verify.Config
// http
BM *BM
Account *warden.ClientConfig
// rpc server2
RPCServer *rpc.ServerConfig
// tracer
Tracer *trace.Config
// file
FilePath string
AnonymFileName string
// filter ip
FilterZone []string
// grpc server
WardenServer *warden.ServerConfig
LiveZK *livezk.Zookeeper
// Host
Host *Host
// AnonymKey
AnonymKey string
// new library
IPv4Name string
IPv6Name string
// httpClinet
HTTPClient *bm.ClientConfig
}
// BM http
type BM struct {
Inner *bm.ServerConfig
Local *bm.ServerConfig
}
// DB define MySQL config
type DB struct {
Zlimit *sql.Config
}
// Redis define Redis config
type Redis struct {
Zlimit *Zlimit
}
// Zlimit struct about zlimit
type Zlimit struct {
*redis.Config
Expire time.Duration
}
// Host url
type Host struct {
Maxmind string
Bvcip string
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init config
func Init() (err error) {
if confPath != "" {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
err = configCenter()
return
}
// configCenter ugc
func configCenter() (err error) {
var (
client *conf.Client
c string
ok bool
)
if client, err = conf.New(); err != nil {
panic(err)
}
if c, ok = client.Toml2(); !ok {
err = errors.New("load config center error")
return
}
_, err = toml.Decode(c, &Conf)
go func() {
for e := range client.Event() {
log.Error("get config from config center error(%v)", e)
}
}()
return
}

View File

@@ -0,0 +1,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"redis_test.go",
"zlimit_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/location/conf:go_default_library",
"//library/cache/redis:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"redis.go",
"zlimit.go",
],
importpath = "go-common/app/service/main/location/dao",
tags = ["automanaged"],
deps = [
"//app/service/main/location/conf:go_default_library",
"//app/service/main/location/model:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,259 @@
package dao
import (
"archive/tar"
"bytes"
"compress/gzip"
"context"
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"path"
"strings"
"time"
"go-common/app/service/main/location/conf"
"go-common/app/service/main/location/model"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
)
const (
_anonym = "/app/geoip_download"
_checkip = "/ipip/checkipipnetversion"
)
// Dao dao.
type Dao struct {
// mysql
c *conf.Config
db *sql.DB
client *http.Client
client2 *httpx.Client
// redis
redis *redis.Pool
expire int32
// host
anonym string
checkip string
}
// New new a dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: sql.NewMySQL(c.DB.Zlimit),
redis: redis.NewPool(c.Redis.Zlimit.Config),
expire: int32(time.Duration(c.Redis.Zlimit.Expire) / time.Second),
client: &http.Client{
Timeout: time.Second * 30,
},
anonym: c.Host.Maxmind + _anonym,
checkip: c.Host.Bvcip + _checkip,
client2: httpx.NewClient(c.HTTPClient),
}
return
}
// Ping ping a dao.
func (d *Dao) Ping(c context.Context) (err error) {
conn := d.redis.Get(c)
_, err = conn.Do("SET", "PING", "PONG")
conn.Close()
return
}
// Close close a dao.
func (d *Dao) Close() (err error) {
if d.redis != nil {
if err1 := d.redis.Close(); err1 != nil {
err = err1
}
}
if d.db != nil {
if err1 := d.db.Close(); err1 != nil {
err = err1
}
}
return
}
// DownloadAnonym download anonym file.
func (d *Dao) DownloadAnonym() (err error) {
// get file
var (
req *http.Request
resp *http.Response
)
params := url.Values{}
params.Set("edition_id", "GeoIP2-Anonymous-IP")
params.Set("date", "")
params.Set("license_key", d.c.AnonymKey)
params.Set("suffix", "tar.gz")
enc := params.Encode()
if req, err = http.NewRequest(http.MethodGet, d.anonym+"?"+enc, nil); err != nil {
log.Error("http.NewRequest(%v) error(%v)", d.anonym+"?"+enc, err)
return
}
if resp, err = d.client.Do(req); err != nil {
log.Error("d.client.Do error(%v)", d.anonym+"?"+enc, err)
return
}
if resp.StatusCode >= http.StatusBadRequest {
err = errors.New(fmt.Sprintf("incorrect http status:%d host:%s, url:%s", resp.StatusCode, d.anonym, enc))
log.Error("%v", err)
return
}
defer resp.Body.Close()
// get md5
buf := new(bytes.Buffer)
if _, err = io.Copy(buf, resp.Body); err != nil {
log.Error("io.Copy error(%v)", err)
return
}
var md5Str string
md5Bs := md5.Sum(buf.Bytes())
if md5Str, err = d.downloadAnonymMd5(); err != nil {
log.Error("downloadAnonymMd5 error(%v)", err)
return
}
if md5Str != hex.EncodeToString(md5Bs[:]) {
err = errors.New("md5 not matched")
return
}
var gr *gzip.Reader
if gr, err = gzip.NewReader(buf); err != nil {
log.Error("gzip.NewReader error(%v)", err)
return
}
defer gr.Close()
tr := tar.NewReader(gr)
var hdr *tar.Header
for {
if hdr, err = tr.Next(); err != nil {
if err == io.EOF {
err = nil
break
} else {
log.Error("DownloadAnonym error(%v)", err)
return
}
}
if strings.Index(hdr.Name, d.c.AnonymFileName) > -1 {
var f *os.File
downfile := path.Join(d.c.FilePath, d.c.AnonymFileName)
if f, err = os.OpenFile(downfile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
log.Error(" os.OpenFile(%v) error(%v)", downfile, err)
return
}
defer f.Close()
if _, err = io.Copy(f, tr); err != nil {
log.Error("io.Copy error(%v)", err)
return
}
break
}
}
return
}
// downloadAnonymMd5 get anonym file md5.
func (d *Dao) downloadAnonymMd5() (md5 string, err error) {
var (
req *http.Request
resp *http.Response
body []byte
)
params := url.Values{}
params.Set("edition_id", "GeoIP2-Anonymous-IP")
params.Set("date", "")
params.Set("license_key", d.c.AnonymKey)
params.Set("suffix", "tar.gz.md5")
enc := params.Encode()
if req, err = http.NewRequest(http.MethodGet, d.anonym+"?"+enc, nil); err != nil {
log.Error("DownloadAnonym http.NewRequest(%v) error(%v)", d.anonym+"?"+enc, err)
return
}
if resp, err = d.client.Do(req); err != nil {
log.Error("DownloadAnonym d.client.Do error(%v)", d.anonym+"?"+enc, err)
return
}
if resp.StatusCode >= http.StatusBadRequest {
err = errors.New(fmt.Sprintf("incorrect http status:%d host:%s, url:%s", resp.StatusCode, d.anonym, enc))
log.Error("%v", err)
return
}
defer resp.Body.Close()
if body, err = ioutil.ReadAll(resp.Body); err != nil {
log.Error("DownloadAnonymMd5 ioutil.ReadAll() error(%v)", err)
return
}
md5 = string(body)
return
}
func (d *Dao) CheckVersion(c context.Context) (version *model.Version, err error) {
var (
req *http.Request
ip = metadata.String(c, metadata.RemoteIP)
)
if req, err = d.client2.NewRequest("GET", d.checkip, ip, nil); err != nil {
log.Error("%v", err)
return
}
var res struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data *model.Version `json:"data"`
}
if err = d.client2.Do(c, req, &res); err != nil {
return
}
if res.Code != ecode.OK.Code() {
err = errors.New(fmt.Sprintf("checkVersion falid err_code(%v)", res.Code))
return
}
version = res.Data
return
}
func (d *Dao) DownIPLibrary(c context.Context, version, file string) (err error) {
var (
req *http.Request
resp *http.Response
)
if req, err = http.NewRequest(http.MethodGet, version, nil); err != nil {
log.Error("http.NewRequest(%v) error(%v)", version, err)
return
}
if resp, err = d.client.Do(req); err != nil {
log.Error("d.client.Do error(%v)", version, err)
return
}
if resp.StatusCode >= http.StatusBadRequest {
err = errors.New(fmt.Sprintf("incorrect http status:%d url:%s", resp.StatusCode, version))
log.Error("%v", err)
return
}
defer resp.Body.Close()
var f *os.File
if f, err = os.OpenFile(file, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666); err != nil {
log.Error(" os.OpenFile(%v) error(%v)", file, err)
return
}
defer f.Close()
if _, err = io.Copy(f, resp.Body); err != nil {
log.Error("io.Copy error(%v)", err)
}
return
}

View File

@@ -0,0 +1,52 @@
package dao
import (
"context"
"flag"
"os"
"testing"
"go-common/app/service/main/location/conf"
"go-common/library/cache/redis"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.app-svr.location-service")
flag.Set("conf_token", "bdc7976c3e1dbf8adeb1cdb7b1e823af")
flag.Set("tree_id", "3170")
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/location-example.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func CleanCache() {
pool := redis.NewPool(conf.Conf.Redis.Zlimit.Config)
pool.Get(context.TODO()).Do("FLUSHDB")
}
func WithDao(f func(d *Dao)) func() {
return func() {
convey.Reset(func() { CleanCache() })
f(d)
}
}

View File

@@ -0,0 +1,93 @@
package dao
import (
"context"
"strconv"
"go-common/library/cache/redis"
"github.com/pkg/errors"
)
const (
_prefixBlackList = "zl_"
)
func keyZlimit(aid int64) (key string) {
key = _prefixBlackList + strconv.FormatInt(aid, 10)
return
}
// ExistsAuth if existes ruls in redis.
func (d *Dao) ExistsAuth(c context.Context, aid int64) (ok bool, err error) {
conn := d.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXISTS", keyZlimit(aid))); err != nil {
err = errors.Wrapf(err, "EXISTS %s", keyZlimit(aid))
}
return
}
// Auth get zone rule from redis
func (d *Dao) Auth(c context.Context, aid int64, zoneids []int64) (res []int64, err error) {
var playauth int64
key := keyZlimit(aid)
conn := d.redis.Get(c)
defer conn.Close()
for _, v := range zoneids {
if err = conn.Send("HGET", key, v); err != nil {
err = errors.Wrapf(err, "HGET %s %d", key, v)
return
}
}
if err = conn.Flush(); err != nil {
err = errors.WithStack(err)
return
}
for range zoneids {
if playauth, err = redis.Int64(conn.Receive()); err != nil {
if err != redis.ErrNil {
err = errors.WithStack(err)
return
}
err = nil
}
res = append(res, playauth)
}
return
}
// AddAuth add zone rule from redis
func (d *Dao) AddAuth(c context.Context, zoneids map[int64]map[int64]int64) (err error) {
var key string
conn := d.redis.Get(c)
defer conn.Close()
count := 0
for aid, zids := range zoneids {
if key == "" {
key = keyZlimit(aid)
}
for zid, auth := range zids {
if err = conn.Send("HSET", key, zid, auth); err != nil {
err = errors.Wrapf(err, "HGET %s %d", key, zid)
return
}
count++
}
}
if err = conn.Send("EXPIRE", key, d.expire); err != nil {
err = errors.Wrapf(err, "EXPIRE %s %d", key, d.expire)
return
}
if err = conn.Flush(); err != nil {
err = errors.WithStack(err)
return
}
for i := 0; i <= count; i++ {
if _, err = conn.Receive(); err != nil {
err = errors.WithStack(err)
return
}
}
return
}

View File

@@ -0,0 +1,66 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaokeyZlimit(t *testing.T) {
var (
aid = int64(123456)
)
convey.Convey("keyZlimit", t, func(ctx convey.C) {
key := keyZlimit(aid)
ctx.Convey("key should not be equal to 123456", func(ctx convey.C) {
ctx.So(key, convey.ShouldEqual, "zl_123456")
})
})
}
func TestDaoExistsAuth(t *testing.T) {
var (
c = context.TODO()
aid = int64(123456)
zoneids = map[int64]map[int64]int64{int64(123456): {int64(234567): int64(345678)}}
)
convey.Convey("ExistsAuth", t, WithDao(func(d *Dao) {
d.AddAuth(c, zoneids)
ok, err := d.ExistsAuth(c, aid)
convey.Convey("Error should be nil, ok should be true", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldBeTrue)
})
}))
}
func TestDaoAuth(t *testing.T) {
var (
c = context.TODO()
aid = int64(0)
zoneid = []int64{int64(0)}
zoneids = map[int64]map[int64]int64{int64(123456): {int64(234567): int64(345678)}}
)
convey.Convey("Auth", t, WithDao(func(d *Dao) {
d.AddAuth(c, zoneids)
res, err := d.Auth(c, aid, zoneid)
convey.Convey("Error should be nil, res should not be empty", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
}))
}
func TestDaoAddAuth(t *testing.T) {
var (
c = context.TODO()
zoneids = map[int64]map[int64]int64{int64(123456): {int64(234567): int64(345678)}}
)
convey.Convey("AddAuth", t, WithDao(func(d *Dao) {
err := d.AddAuth(c, zoneids)
convey.Convey("Error should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
}))
}

View File

@@ -0,0 +1,151 @@
package dao
import (
"context"
"go-common/app/service/main/location/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_getPolicySQL = "SELECT id, play_auth, down_auth, zone_id FROM policy_item WHERE zone_id <> '' AND state=1"
_getRelationSQL = "SELECT policy_id FROM archive_relation WHERE aid=?"
_getGolbalPolicySQL = "SELECT group_id,group_concat(id) FROM policy_item WHERE zone_id <> '' AND state=1 GROUP BY group_id"
_getGroupZone = "SELECT a.group_id,a.play_auth,a.zone_id FROM policy_item AS a,policy_group AS b WHERE a.zone_id <> '' AND a.group_id=b.id AND b.type=2 AND a.state=1 AND b.state=1"
)
// Policies get policy data from db
func (d *Dao) Policies(c context.Context) (res map[int64]map[int64]int64, err error) {
var (
tmpres map[int64]int64
ok bool
)
rows, err := d.db.Query(c, _getPolicySQL)
if err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
res = make(map[int64]map[int64]int64)
for rows.Next() {
var (
pid, playAuth, downAuth int64
zoneID string
zoneIDs []int64
)
if err = rows.Scan(&pid, &playAuth, &downAuth, &zoneID); err != nil {
err = errors.WithStack(err)
return
}
if zoneIDs, err = xstr.SplitInts(zoneID); err != nil {
log.Error("xstr.SplitInts(%s) error(%v)", zoneID, err)
continue
}
for _, zoneid := range zoneIDs {
if tmpres, ok = res[pid]; !ok {
tmpres = make(map[int64]int64)
res[pid] = tmpres
}
resCode := playAuth<<8 | downAuth
tmpres[zoneid] = resCode
}
}
err = errors.WithStack(err)
return
}
// GroupPolicies get policy data from db group by group_id
func (d *Dao) GroupPolicies(c context.Context) (res map[int64][]int64, err error) {
rows, err := d.db.Query(c, _getGolbalPolicySQL)
if err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
res = make(map[int64][]int64)
for rows.Next() {
var (
groupID int64
pids string
zoneIDs []int64
)
if err = rows.Scan(&groupID, &pids); err != nil {
err = errors.WithStack(err)
return
}
if zoneIDs, err = xstr.SplitInts(pids); err != nil {
log.Error("xstr.SplitInts(%s) error(%v)", pids, err)
continue
}
res[groupID] = zoneIDs
}
err = errors.WithStack(err)
return
}
// Groupid get gid from db by aid
func (d *Dao) Groupid(c context.Context, aid int64) (gid int64, err error) {
row := d.db.QueryRow(c, _getRelationSQL, aid)
if err = row.Scan(&gid); err != nil {
if err == sql.ErrNoRows {
gid = 0
err = nil
} else {
err = errors.WithStack(err)
}
}
return
}
// GroupAuthZone zone_id by group_id.
func (d *Dao) GroupAuthZone(c context.Context) (res map[int64]map[int64]map[int64]int64, err error) {
var (
tmpAres map[int64]map[int64]int64
tmpZres map[int64]int64
ok bool
)
rows, err := d.db.Query(c, _getGroupZone)
if err != nil {
err = errors.WithStack(err)
return
}
defer rows.Close()
res = make(map[int64]map[int64]map[int64]int64)
for rows.Next() {
var (
gid, playAuth int64
zoneID string
zoneIDs []int64
)
if err = rows.Scan(&gid, &playAuth, &zoneID); err != nil {
err = errors.WithStack(err)
return
}
if playAuth != model.Forbidden && playAuth != model.Allow {
playAuth = model.Allow
}
if zoneIDs, err = xstr.SplitInts(zoneID); err != nil {
log.Error("xstr.SplitInts(%s) error(%v)", zoneID, err)
continue
}
for _, zoneid := range zoneIDs {
if tmpAres, ok = res[gid]; !ok {
tmpAres = make(map[int64]map[int64]int64)
res[gid] = tmpAres
}
if tmpZres, ok = tmpAres[playAuth]; !ok {
tmpZres = make(map[int64]int64)
tmpAres[playAuth] = tmpZres
}
if _, ok = tmpZres[zoneid]; !ok {
tmpZres[zoneid] = zoneid
}
}
}
err = errors.WithStack(err)
return
}

View File

@@ -0,0 +1,47 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoPolicies(t *testing.T) {
convey.Convey("Policies", t, func(ctx convey.C) {
res, err := d.Policies(context.Background())
ctx.Convey("Error should be nil, res should not be empty", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
})
}
func TestDaoGroupPolicies(t *testing.T) {
convey.Convey("GroupPolicies", t, func(ctx convey.C) {
res, err := d.GroupPolicies(context.Background())
ctx.Convey("Error should be nil, res should not be empty", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
})
}
func TestDaoGroupid(t *testing.T) {
convey.Convey("should get group_id", t, func(ctx convey.C) {
_, err := d.Groupid(context.Background(), 11424224)
ctx.Convey("Error should be nil", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoGroupAuthZone(t *testing.T) {
convey.Convey("GroupAuthZone", t, func(ctx convey.C) {
res, err := d.GroupAuthZone(context.Background())
ctx.Convey("Error should be nil, res should not be empty", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
})
}

View File

@@ -0,0 +1,32 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"anonymous.go",
"ip.go",
"rpc.go",
"zlimit.go",
],
importpath = "go-common/app/service/main/location/model",
tags = ["automanaged"],
)
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,10 @@
package model
// AnonymousIP IP database.
type AnonymousIP struct {
IsAnonymous bool `json:"is_anonymous" maxminddb:"is_anonymous"`
IsAnonymousVPN bool `json:"is_anonymous_vpn" maxminddb:"is_anonymous_vpn"`
IsHostingProvider bool `json:"is_hosting_provider" maxminddb:"is_hosting_provider"`
IsPublicProxy bool `json:"is_public_proxy" maxminddb:"is_public_proxy"`
IsTorExitNode bool `json:"is_tor_exit_node" maxminddb:"is_tor_exit_node"`
}

View File

@@ -0,0 +1,56 @@
package model
// TmpInfo old api will del soon
type TmpInfo struct {
Addr string `json:"addr"`
ZoneID int64 `json:"zoneId"`
Country string `json:"country"`
Province string `json:"province"`
City string `json:"city"`
}
// Info ipinfo with the smallest zone_id.
type Info struct {
Addr string `json:"addr"`
Country string `json:"country"`
Province string `json:"province"`
City string `json:"city"`
ISP string `json:"isp"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
ZoneID int64 `json:"zoneId"`
CountryCode int `json:"country_code"`
}
// InfoComplete ipinfo with all zone_id.
type InfoComplete struct {
Addr string `json:"addr"`
Country string `json:"country"`
Province string `json:"province"`
City string `json:"city"`
ISP string `json:"isp"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
ZoneID []int64 `json:"zone_id"`
CountryCode int `json:"country_code"`
}
// IP dont' use this, will del soon. use InfoComplete.
type IP struct {
Addr string `json:"addr"`
Country string `json:"country"`
Province string `json:"province"`
City string `json:"city"`
ISP string `json:"isp"`
ZoneID []int64 `json:"zone_id"`
}
// Version for check ip library.
type Version struct {
UpdateTimeV4 string `json:"ipv4_flagship_ipdb_update_time"`
NewestV4 string `json:""ipv4_flagship_ipdb_newest_url`
StableV4 string `json:"ipv4_flagship_ipdb_stable_url"`
UpdateTimeV6 string `json:"ipv6_flagship_ipdb_update_time"`
NewestV6 string `json:""ipv6_flagship_ipdb_newest_url`
StableV6 string `json:"ipv6_flagship_ipdb_stable_url"`
}

View File

@@ -0,0 +1,27 @@
package model
// ArgIP for Zone、Info、InfoComplete、Info2
type ArgIP struct {
IP string
}
// Archive for Archive
type Archive struct {
Aid int64
Mid int64
IP string
CIP string
}
// Group for group
type Group struct {
Gid int64
Mid int64
IP string
CIP string
}
// ArgPids for PIDs
type ArgPids struct {
Pids, IP, CIP string
}

View File

@@ -0,0 +1,35 @@
package model
// auth const
const (
Forbidden = int64(1)
Allow = int64(2)
Formal = int64(3)
Pay = int64(4)
AllowDown = int64(1)
ForbiddenDown = int64(0)
AuthOK = 1
AuthNotOK = 0
)
// for prom
var (
PlayAuth = map[int64]string{
Forbidden: "play_forbidden",
Allow: "play_allown",
Formal: "play_formal_member",
Pay: "play_pay_member",
}
DownAuth = map[int64]string{
ForbiddenDown: "down_forbidden",
AllowDown: "down_allown",
}
)
// Auth for auth result
type Auth struct {
Play int64 `json:"play"`
Down int64 `json:"down"`
}

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["client_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//app/service/main/location/model:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
importpath = "go-common/app/service/main/location/rpc/client",
tags = ["automanaged"],
deps = [
"//app/service/main/location/model:go_default_library",
"//library/net/rpc: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,87 @@
package client
import (
"context"
"go-common/app/service/main/location/model"
"go-common/library/net/rpc"
)
const (
_archive = "RPC.Archive"
_archive2 = "RPC.Archive2"
_group = "RPC.Group"
_authPIDs = "RPC.AuthPIDs"
// new
_info = "RPC.Info"
_infos = "RPC.Infos"
_infoComplete = "RPC.InfoComplete"
_infosComplete = "RPC.InfosComplete"
// app id
_appid = "location.service"
)
// Service is resource rpc client.
type Service struct {
client *rpc.Client2
}
// New new a resource rpc client.
func New(c *rpc.ClientConfig) (s *Service) {
s = &Service{}
s.client = rpc.NewDiscoveryCli(_appid, c)
return
}
// Archive get the aid auth.
func (s *Service) Archive(c context.Context, arg *model.Archive) (res *int64, err error) {
res = new(int64)
err = s.client.Call(c, _archive, arg, res)
return
}
// Archive2 get the aid auth.
func (s *Service) Archive2(c context.Context, arg *model.Archive) (res *model.Auth, err error) {
res = new(model.Auth)
err = s.client.Call(c, _archive2, arg, res)
return
}
// Group get the gip auth.
func (s *Service) Group(c context.Context, arg *model.Group) (res *model.Auth, err error) {
res = new(model.Auth)
err = s.client.Call(c, _group, arg, res)
return
}
// AuthPIDs check if ip in pids.
func (s *Service) AuthPIDs(c context.Context, arg *model.ArgPids) (res map[int64]*model.Auth, err error) {
err = s.client.Call(c, _authPIDs, arg, &res)
return
}
// Info get the ip info.
func (s *Service) Info(c context.Context, arg *model.ArgIP) (res *model.Info, err error) {
res = new(model.Info)
err = s.client.Call(c, _info, arg, res)
return
}
// Infos get the ips info.
func (s *Service) Infos(c context.Context, arg []string) (res map[string]*model.Info, err error) {
err = s.client.Call(c, _infos, arg, &res)
return
}
// InfoComplete get the whold ip info.
func (s *Service) InfoComplete(c context.Context, arg *model.ArgIP) (res *model.InfoComplete, err error) {
res = new(model.InfoComplete)
err = s.client.Call(c, _infoComplete, arg, res)
return
}
// InfosComplete get the whold ips infos.
func (s *Service) InfosComplete(c context.Context, arg []string) (res map[string]*model.InfoComplete, err error) {
err = s.client.Call(c, _infosComplete, arg, &res)
return
}

View File

@@ -0,0 +1,94 @@
package client
import (
"context"
"testing"
"time"
"go-common/app/service/main/location/model"
)
const (
_aid = 16428
_gid = 317
_mid = 0
_ip = "139.214.144.59"
_cip = "127.0.0.1"
)
func TestLocation(t *testing.T) {
s := New(nil)
time.Sleep(1 * time.Second)
testArchive(t, s)
testArchive2(t, s)
testGroup(t, s)
testAuthPIDs(t, s)
testInfo(t, s)
testInfos(t, s)
testInfoComplete(t, s)
testInfosComplete(t, s)
}
func testArchive(t *testing.T, s *Service) {
if res, err := s.Archive(context.TODO(), &model.Archive{Aid: _aid, Mid: _mid, IP: _ip, CIP: _cip}); err != nil {
t.Errorf("Service: archive err: %v", err)
} else {
t.Logf("Service: archive res: %v", res)
}
}
func testArchive2(t *testing.T, s *Service) {
if res, err := s.Archive2(context.TODO(), &model.Archive{Aid: _aid, Mid: _mid, IP: _ip, CIP: _cip}); err != nil {
t.Errorf("Service: archive2 err: %v", err)
} else {
t.Logf("Service: archive2 res: %v", res)
}
}
func testGroup(t *testing.T, s *Service) {
if res, err := s.Group(context.TODO(), &model.Group{Gid: _gid, Mid: _mid, IP: _ip, CIP: _cip}); err != nil {
t.Errorf("Service: group err: %v", err)
} else {
t.Logf("Service: group res: %v", res)
}
}
func testAuthPIDs(t *testing.T, s *Service) {
if res, err := s.AuthPIDs(context.TODO(), &model.ArgPids{IP: _ip, Pids: "2,1163,86,87", CIP: _cip}); err != nil {
t.Errorf("Service: AuthPIDs err: %v", err)
} else {
t.Logf("Service: AuthPIDs res: %v", res)
}
}
func testInfo(t *testing.T, s *Service) {
if res, err := s.Info(context.TODO(), &model.ArgIP{IP: _ip}); err != nil {
t.Errorf("Service: info err: %v", err)
} else {
t.Logf("Service: info res: %v", res)
}
}
func testInfos(t *testing.T, s *Service) {
if res, err := s.Infos(context.TODO(), []string{"61.216.166.156", "211.139.80.6"}); err != nil {
t.Errorf("Service: infos err: %v", err)
} else {
t.Logf("Service: infos res: %v", res)
}
}
func testInfoComplete(t *testing.T, s *Service) {
if res, err := s.InfoComplete(context.TODO(), &model.ArgIP{IP: _ip}); err != nil {
t.Errorf("Service: infoComplete err: %v", err)
} else {
t.Logf("Service: infoComplete res: %v", res)
}
}
func testInfosComplete(t *testing.T, s *Service) {
if res, err := s.InfosComplete(context.TODO(), []string{"61.216.166.156", "211.139.80.6"}); err != nil {
t.Errorf("Service: infosComplete err: %v", err)
} else {
t.Logf("Service: infosComplete res: %v", res)
}
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["server_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/location/conf:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/location/service:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/main/location/rpc/server",
tags = ["automanaged"],
deps = [
"//app/service/main/location/conf:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/location/service:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/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,92 @@
package server
import (
"go-common/app/service/main/location/conf"
"go-common/app/service/main/location/model"
"go-common/app/service/main/location/service"
"go-common/library/net/rpc"
"go-common/library/net/rpc/context"
)
// RPC struct
type RPC struct {
s *service.Service
}
// New init rpc server.
func New(c *conf.Config, s *service.Service) (svr *rpc.Server) {
r := &RPC{s: s}
svr = rpc.NewServer(c.RPCServer)
if err := svr.Register(r); err != nil {
panic(err)
}
return
}
// Ping check connection success.
func (r *RPC) Ping(c context.Context, arg *struct{}, res *struct{}) (err error) {
return
}
// Archive get aid auth.
func (r *RPC) Archive(c context.Context, a *model.Archive, res *int64) (err error) {
var play int64
if play, err = r.s.Auth(c, a.Aid, a.Mid, a.IP, a.CIP); err == nil {
*res = play
}
return
}
// Archive2 get aid auth.
func (r *RPC) Archive2(c context.Context, a *model.Archive, res *model.Auth) (err error) {
var auth *model.Auth
if auth, err = r.s.Archive2(c, a.Aid, a.Mid, a.IP, a.CIP); err == nil {
*res = *auth
}
return
}
// Group get gid auth.
func (r *RPC) Group(c context.Context, a *model.Group, res *model.Auth) (err error) {
auth := r.s.AuthGID(c, a.Gid, a.Mid, a.IP, a.CIP)
if auth != nil {
*res = *auth
}
return
}
// AuthPIDs check if ip in pids.
func (r *RPC) AuthPIDs(c context.Context, a *model.ArgPids, res *map[int64]*model.Auth) (err error) {
*res, err = r.s.AuthPIDs(c, a.Pids, a.IP, a.CIP)
return
}
// Info get IP info
func (r *RPC) Info(c context.Context, a *model.ArgIP, res *model.Info) (err error) {
var ti *model.Info
if ti, err = r.s.Info(c, a.IP); err == nil {
*res = *ti
}
return
}
// Infos get IPs infos.
func (r *RPC) Infos(c context.Context, a []string, res *map[string]*model.Info) (err error) {
*res, err = r.s.Infos(c, a)
return
}
// InfoComplete get IP whole info.
func (r *RPC) InfoComplete(c context.Context, a *model.ArgIP, res *model.InfoComplete) (err error) {
var info *model.InfoComplete
if info, err = r.s.InfoComplete(c, a.IP); err == nil {
*res = *info
}
return
}
// InfosComplete get ips whole infos.
func (r *RPC) InfosComplete(c context.Context, a []string, res *map[string]*model.InfoComplete) (err error) {
*res, err = r.s.InfosComplete(c, a)
return
}

View File

@@ -0,0 +1,173 @@
package server
import (
"fmt"
"net/rpc"
"testing"
"time"
"go-common/app/service/main/location/conf"
"go-common/app/service/main/location/model"
"go-common/app/service/main/location/service"
)
// rpc server const
const (
addr = "127.0.0.1:6293"
_archive = "RPC.Archive"
_archive2 = "RPC.Archive2"
_group = "RPC.Group"
_authPIDs = "RPC.AuthPIDs"
_info = "RPC.Info"
_infos = "RPC.Infos"
_infoComplete = "RPC.InfoComplete"
_infosComplete = "RPC.InfosComplete"
)
// TestLocation test rpc server
func TestLocation(t *testing.T) {
if err := conf.Init(); err != nil {
t.Errorf("conf.Init() error(%v)", err)
t.FailNow()
}
svr := service.New(conf.Conf)
New(conf.Conf, svr)
time.Sleep(time.Second * 3)
client, err := rpc.Dial("tcp", addr)
defer client.Close()
if err != nil {
t.Errorf("rpc.Dial(tcp, \"%s\") error(%v)", addr, err)
t.FailNow()
}
archiveRPC(client, t)
archive2RPC(client, t)
groupRPC(client, t)
authPIDsRPC(client, t)
infoRPC(client, t)
infosRPC(client, t)
infoCompleteRPC(client, t)
infosCompleteRPC(client, t)
}
func archiveRPC(client *rpc.Client, t *testing.T) {
var res int64
arg := &model.Archive{
Aid: 740955,
Mid: 0,
IP: "2.20.32.123",
CIP: "127.0.0.1",
}
err := client.Call(_archive, arg, &res)
if err != nil {
t.Errorf("err:%v.", err)
} else {
result("archive", t, res)
}
t.Logf("%+v", res)
}
func archive2RPC(client *rpc.Client, t *testing.T) {
res := &model.Auth{}
arg := &model.Archive{
Aid: 740955,
Mid: 0,
IP: "2.20.32.123",
CIP: "127.0.0.1",
}
err := client.Call(_archive2, arg, &res)
if err != nil {
t.Errorf("err:%v.", err)
} else {
result("archive2", t, res)
}
t.Logf("%+v", res)
}
func groupRPC(client *rpc.Client, t *testing.T) {
res := &model.Auth{}
arg := &model.Group{
Gid: 317,
Mid: 0,
IP: "2.20.32.123",
CIP: "127.0.0.1",
}
err := client.Call(_group, arg, &res)
if err != nil {
t.Errorf("err:%v.", err)
} else {
result("group", t, res)
}
t.Logf("%+v", res)
}
func authPIDsRPC(client *rpc.Client, t *testing.T) {
arg := &model.ArgPids{IP: "61.216.166.156", Pids: "150,92"}
res := map[int64]*model.Auth{}
err := client.Call(_authPIDs, arg, &res)
if err != nil {
t.Errorf("err:%v.", err)
} else {
result("authPIDs", t, res)
}
t.Logf("%+v,err:%v.", res, err)
}
func infoRPC(client *rpc.Client, t *testing.T) {
var res = new(model.Info)
arg := &model.ArgIP{
IP: "139.214.144.59",
}
err := client.Call(_info, arg, res)
if err != nil {
t.Errorf("err:%v.", err)
} else {
result("info", t, res)
}
t.Logf("%+v,err:%v.", res, err)
}
func infosRPC(client *rpc.Client, t *testing.T) {
arg := []string{"61.216.166.156", "211.139.80.6"}
res := map[string]*model.Info{}
err := client.Call(_infos, arg, &res)
if err != nil {
t.Errorf("err:%v.", err)
} else {
result("infos", t, res)
}
t.Logf("%+v,err:%v.", res, err)
}
func infoCompleteRPC(client *rpc.Client, t *testing.T) {
var res = new(model.InfoComplete)
arg := &model.ArgIP{
IP: "139.214.144.59",
}
err := client.Call(_infoComplete, arg, res)
if err != nil {
t.Errorf("err:%v.", err)
} else {
result("infoComplete", t, res)
}
t.Logf("%+v,err:%v.", res, err)
}
func infosCompleteRPC(client *rpc.Client, t *testing.T) {
arg := []string{"61.216.166.156", "211.139.80.6"}
res := map[string]*model.InfoComplete{}
err := client.Call(_infosComplete, arg, &res)
if err != nil {
t.Errorf("err:%v.", err)
} else {
result("infosComplete", t, res)
}
t.Logf("%+v,err:%v.", res, err)
}
func result(name string, t *testing.T, res interface{}) {
fmt.Printf("res : %+v \n", res)
t.Log("[==========" + name + "单元测试结果==========]")
t.Log(res)
t.Log("[↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑]\r\n")
}

View File

@@ -0,0 +1,50 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["server_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/location/api:go_default_library",
"//app/service/main/location/conf:go_default_library",
"//app/service/main/location/service:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/time:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/main/location/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/location/api:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/location/service:go_default_library",
"//library/net/rpc/warden:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,47 @@
// Package server generate by warden_gen
package grpc
import (
"context"
"fmt"
pb "go-common/app/service/main/location/api"
"go-common/app/service/main/location/model"
"go-common/app/service/main/location/service"
"go-common/library/net/rpc/warden"
)
// New Location warden rpc server
func New(c *warden.ServerConfig, svr *service.Service) *warden.Server {
ws := warden.NewServer(c)
pb.RegisterLocationServer(ws.Server(), &server{svr})
ws, err := ws.Start()
if err != nil {
panic(fmt.Sprintf("start warden server fail! %s", err))
}
return ws
}
type server struct {
svr *service.Service
}
var _ pb.LocationServer = &server{}
// Info get ip info.
func (s *server) Info(c context.Context, arg *pb.InfoReq) (res *pb.InfoReply, err error) {
var ipinfo *model.Info
if ipinfo, err = s.svr.Info(c, arg.Addr); err != nil {
return
}
res = &pb.InfoReply{
Addr: ipinfo.Addr,
Country: ipinfo.Country,
Province: ipinfo.Province,
City: ipinfo.City,
Isp: ipinfo.ISP,
Latitude: ipinfo.Latitude,
Longitude: ipinfo.Longitude,
ZoneId: ipinfo.ZoneID}
return
}

View File

@@ -0,0 +1,60 @@
package grpc
import (
"context"
"fmt"
"testing"
"time"
pb "go-common/app/service/main/location/api"
"go-common/app/service/main/location/conf"
"go-common/app/service/main/location/service"
"go-common/library/net/rpc/warden"
xtime "go-common/library/time"
)
// rpc server const
const (
addr = "127.0.0.1:9000"
)
// TestLocation test rpc server
func TestLocation(t *testing.T) {
if err := conf.Init(); err != nil {
t.Errorf("conf.Init() error(%v)", err)
t.FailNow()
}
svr := service.New(conf.Conf)
New(conf.Conf.WardenServer, svr)
time.Sleep(time.Second * 3)
cfg := &warden.ClientConfig{
Dial: xtime.Duration(time.Second * 3),
Timeout: xtime.Duration(time.Second * 3),
}
cc, err := warden.NewClient(cfg).Dial(context.Background(), addr)
if err != nil {
t.Errorf("rpc.Dial(tcp, \"%s\") error(%v)", addr, err)
t.FailNow()
}
client := pb.NewLocationClient(cc)
infoGRPC(client, t)
}
func infoGRPC(client pb.LocationClient, t *testing.T) {
arg := &pb.InfoReq{
Addr: "211.139.80.6",
}
res, err := client.Info(context.TODO(), arg)
if err != nil {
t.Error(err)
} else {
result("info", t, res)
}
}
func result(name string, t *testing.T, res interface{}) {
fmt.Printf("res : %+v \n", res)
t.Log("[==========" + name + "单元测试结果==========]")
t.Log(res)
t.Log("[↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑]\r\n")
}

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 = [
"http.go",
"ip.go",
"ip_old.go",
"local.go",
"manager.go",
"zlimit.go",
],
importpath = "go-common/app/service/main/location/server/http",
tags = ["automanaged"],
deps = [
"//app/service/main/location/conf:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/location/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/xstr: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,56 @@
package http
import (
"io"
"go-common/app/service/main/location/conf"
"go-common/app/service/main/location/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
svr *service.Service
vfySvc *verify.Verify
)
// Init init http.
func Init(c *conf.Config, s *service.Service, rpcCloser io.Closer) {
svr = s
vfySvc = verify.New(c.Verify)
// init external router
engineInner := bm.DefaultServer(c.BM.Inner)
innerRouter(engineInner)
// init internal server
if err := engineInner.Start(); err != nil {
log.Error("engineInner.Start() error(%v) | config(%v)", err, c)
panic(err)
}
}
// innerRouter init inner router.
func innerRouter(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
loc := e.Group("/x/location")
// old api will delete soon
loc.GET("/check", vfySvc.Verify, tmpInfo)
loc.GET("/zone", vfySvc.Verify, tmpInfos)
// ip info
loc.GET("/info", vfySvc.Verify, info)
loc.GET("/infos", vfySvc.Verify, infos)
loc.GET("/info/complete", vfySvc.Verify, infoComplete)
loc.GET("/infos/complete", vfySvc.Verify, infosComplete)
loc.GET("/anonym", vfySvc.Verify, anonym)
// area limit api
zl := loc.Group("/zlimit")
zl.GET("/pgc/in", vfySvc.Verify, pgcZone)
zl.GET("/archive", vfySvc.Verify, auth)
zl.GET("/archive2", vfySvc.Verify, archive2)
zl.GET("/group", vfySvc.Verify, authGID)
zl.GET("/groups", vfySvc.Verify, authGIDs)
mng := loc.Group("/manager")
mng.GET("/flushCache", vfySvc.Verify, flushCache)
}

View File

@@ -0,0 +1,73 @@
package http
import (
"strings"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
// info ip info.
func info(c *bm.Context) {
var (
ip string
query = c.Request.Form
)
if ip = query.Get("ip"); ip == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.Info(c, ip))
}
// infos ip info.
func infos(c *bm.Context) {
var (
ips string
query = c.Request.Form
)
if ips = query.Get("ips"); ips == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.Infos(c, strings.Split(ips, ",")))
}
// infoComplete get whole ip info.
func infoComplete(c *bm.Context) {
var (
ip string
query = c.Request.Form
)
if ip = query.Get("ip"); ip == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.InfoComplete(c, ip))
}
// infosComplete get whole ip infos.
func infosComplete(c *bm.Context) {
var (
ips string
query = c.Request.Form
)
if ips = query.Get("ips"); ips == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.InfosComplete(c, strings.Split(ips, ",")))
}
// anonym ip info.
func anonym(c *bm.Context) {
var (
ip string
query = c.Request.Form
)
if ip = query.Get("ip"); ip == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.Anonym(ip))
}

View File

@@ -0,0 +1,37 @@
package http
import (
"strings"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
// tmpInfo ip info.
func tmpInfo(c *bm.Context) {
var ip string
if ip = c.Request.FormValue("ip"); ip == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.TmpInfo(ip))
}
// tmpInfos ip info.
func tmpInfos(c *bm.Context) {
var ips string
if ips = c.Request.FormValue("ip"); ips == "" {
c.JSON(nil, ecode.RequestErr)
return
}
zones, err := svr.TmpInfos(c, strings.Split(ips, ",")...)
if err != nil {
c.JSON(nil, err)
return
}
if len(zones) == 1 {
c.JSON(zones[0], nil)
} else {
c.JSON(zones, nil)
}
}

View File

@@ -0,0 +1,20 @@
package http
import (
"net/http"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// ping check server ok.
func ping(c *bm.Context) {
if err := svr.Ping(c); err != nil {
log.Error("location service ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(nil, nil)
}

View File

@@ -0,0 +1,11 @@
package http
import (
bm "go-common/library/net/http/blademaster"
)
func flushCache(c *bm.Context) {
if err := svr.LoadPolicy(); err != nil {
c.JSON(nil, err)
}
}

View File

@@ -0,0 +1,151 @@
package http
import (
"strconv"
"go-common/app/service/main/location/model"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
// pgcZone get ip infos by gids.
func pgcZone(c *bm.Context) {
var (
params = c.Request.Form
err error
zoneID int64
zoneIDs = []int64{}
ip *model.InfoComplete
)
zoneStr := params.Get("zone_id")
ipStr := params.Get("ip")
if zoneStr == "" && ipStr == "" {
c.JSON(nil, ecode.RequestErr)
return
}
if zoneID, err = strconv.ParseInt(zoneStr, 10, 64); err != nil || zoneID == 0 {
if ip, err = svr.InfoComplete(c, ipStr); err != nil {
c.JSON(nil, ecode.RequestErr)
return
} else {
zoneIDs = ip.ZoneID
}
}
if len(zoneIDs) == 0 {
if zoneID != 0 {
zoneIDs = append(zoneIDs, 0)
}
zoneIDs = append(zoneIDs, zoneID)
}
c.JSON(svr.PgcZone(c, zoneIDs))
}
// auth get auth by aid & ip & cip & mid.
func auth(c *bm.Context) {
var (
params = c.Request.Form
err error
ipaddr, cdnip string
mid, aid int64
)
aidStr := params.Get("aid")
if aid, err = strconv.ParseInt(aidStr, 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if vmid, ok := c.Get("mid"); !ok {
mid = 0
} else {
mid = vmid.(int64)
}
ipaddr = params.Get("ip")
cdnip = params.Get("cdnip")
if ipaddr == "" && cdnip == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.Auth(c, aid, mid, ipaddr, cdnip))
}
// archive2 get auth by aid & ip & cip & mid.
func archive2(c *bm.Context) {
var (
params = c.Request.Form
err error
ipaddr, cdnip string
mid, aid int64
)
aidStr := params.Get("aid")
if aid, err = strconv.ParseInt(aidStr, 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if vmid, ok := c.Get("mid"); !ok {
mid = 0
} else {
mid = vmid.(int64)
}
ipaddr = params.Get("ip")
cdnip = params.Get("cdnip")
if ipaddr == "" && cdnip == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.Archive2(c, aid, mid, ipaddr, cdnip))
}
// authGID get auth by gids & ip & cid & mid.
func authGID(c *bm.Context) {
var (
mid, gid int64
ipaddr, cdnip string
params = c.Request.Form
err error
)
gidStr := params.Get("gid")
if gid, err = strconv.ParseInt(gidStr, 10, 64); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if vmid, ok := c.Get("mid"); !ok {
mid = 0
} else {
mid = vmid.(int64)
}
ipaddr = params.Get("ip")
cdnip = params.Get("cdnip")
if ipaddr == "" && cdnip == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.AuthGID(c, gid, mid, ipaddr, cdnip), nil)
}
// authGIDs get auth by gids & ip & cid & mid.
func authGIDs(c *bm.Context) {
var (
gids []int64
mid int64
ipaddr, cdnip string
params = c.Request.Form
err error
)
gidsStr := params.Get("gids")
if gids, err = xstr.SplitInts(gidsStr); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if vmid, ok := c.Get("mid"); !ok {
mid = 0
} else {
mid = vmid.(int64)
}
ipaddr = params.Get("ip")
cdnip = params.Get("cdnip")
if ipaddr == "" && cdnip == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(svr.AuthGIDs(c, gids, mid, ipaddr, cdnip), nil)
}

View File

@@ -0,0 +1,67 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"ip_old_test.go",
"ip_test.go",
"service_test.go",
"zlimit_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/location/conf:go_default_library",
"//library/cache/redis:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"anonymous.go",
"binary.go",
"ip.go",
"ip_old.go",
"service.go",
"zlimit.go",
],
importpath = "go-common/app/service/main/location/service",
tags = ["automanaged"],
deps = [
"//app/service/main/account/api:go_default_library",
"//app/service/main/location/conf:go_default_library",
"//app/service/main/location/dao:go_default_library",
"//app/service/main/location/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/ip:go_default_library",
"//library/stat/prom:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/ipipdotnet/ipdb-go:go_default_library",
"//vendor/github.com/oschwald/maxminddb-golang:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,32 @@
package service
import (
"net"
"go-common/app/service/main/location/model"
"go-common/library/log"
maxminddb "github.com/oschwald/maxminddb-golang"
)
// NewAnonym load bin file.
func (s *Service) NewAnonym(path string) (reader *maxminddb.Reader, err error) {
if reader, err = maxminddb.Open(path); err != nil {
log.Error("NewAnonym bin file error(%v)", err)
}
return
}
// Anonym .
func (s *Service) Anonym(ipStr string) (res *model.AnonymousIP, err error) {
nip := net.ParseIP(ipStr)
res = &model.AnonymousIP{}
if nip == nil || nip.To4() == nil {
log.Error("invalid ip(%s) format", ipStr)
return
}
if err = s.anonym.Lookup(nip, res); err != nil {
log.Error("Anonym bin file ip(%v) error(%v)", ipStr, err)
}
return
}

View File

@@ -0,0 +1,312 @@
package service
import (
"fmt"
"io/ioutil"
"strconv"
"go-common/library/net/ip"
"github.com/pkg/errors"
)
const (
_HeaderInfoSize = 24
)
// HeadIndex index pos.
type HeadIndex struct {
Index int
Country int
Province int
City int
ISP int
District int
}
// ZoneInfo all kinds of zone info.
type ZoneInfo struct {
code int
name string
}
func formByte(data []byte, pos int) (res uint32) {
res = (uint32(data[pos]&0xff) << 8) + uint32(data[pos+1]&0xff)
return
}
func formByte2(data []byte, pos int) (res int32) {
res = (int32(data[pos]&0xff) << 24) + (int32(data[pos+1]&0xff) << 16) + (int32(data[pos+2]&0xff) << 8) + int32(data[pos+3]&0xff)
return
}
// newBin new binary ip.
func (s *Service) newBin(path string) (list *ip.List, err error) {
var (
contents []byte
countrys map[int]*ZoneInfo
provinces map[int]*ZoneInfo
citys map[int]*ZoneInfo
isps map[int]*ZoneInfo
districts map[int]*ZoneInfo
)
if contents, err = ioutil.ReadFile(path); err != nil {
err = errors.WithStack(err)
return
}
if len(contents) < _HeaderInfoSize {
err = errors.New("文件异常")
return
}
index := s.loadHeader(contents)
if list, err = s.loadIP(contents, index); err != nil {
err = errors.WithStack(err)
return
}
if countrys, err = s.loadCounty(contents, index); err != nil {
err = errors.WithStack(err)
return
}
if provinces, err = s.loadProvince(contents, index); err != nil {
err = errors.WithStack(err)
return
}
if citys, err = s.loadCity(contents, index); err != nil {
err = errors.WithStack(err)
return
}
if isps, err = s.loadISP(contents, index); err != nil {
err = errors.WithStack(err)
return
}
if districts, err = s.loadDistrict(contents, index); err != nil {
err = errors.WithStack(err)
return
}
var (
zone *ZoneInfo
ok bool
)
for _, info := range list.IPs {
if zone, ok = countrys[info.CountryCode]; ok {
info.Country = zone.name
}
if zone, ok = provinces[info.ProvinceCode]; ok {
info.Province = zone.name
}
if zone, ok = citys[info.CityCode]; ok {
info.City = zone.name
}
if info.Province == "香港" || info.Province == "澳门" || info.Province == "台湾" {
info.Country = info.Province
info.Province = info.City
info.City = ""
}
if info.Country == info.Province {
info.Province = ""
info.City = ""
}
if info.Province == info.City {
info.City = ""
}
if zone, ok = isps[info.ISPCode]; ok {
info.ISP = zone.name
}
if zone, ok = districts[info.DistrictCode]; ok {
info.District = zone.name
}
}
return
}
func (s *Service) loadHeader(data []byte) (index *HeadIndex) {
var pos = 0
index = &HeadIndex{}
index.Index = int(formByte2(data, pos))
pos += 4
index.Country = int(formByte2(data, pos))
pos += 4
index.Province = int(formByte2(data, pos))
pos += 4
index.City = int(formByte2(data, pos))
pos += 4
index.ISP = int(formByte2(data, pos))
pos += 4
index.District = int(formByte2(data, pos))
return
}
func (s *Service) loadIP(data []byte, index *HeadIndex) (list *ip.List, err error) {
var (
pos = index.Index
count = int(formByte2(data, pos))
)
pos += 4
list = new(ip.List)
for i := 0; i < count; i++ {
if pos > len(data) {
break
}
item := &ip.IP{}
item.Begin = uint32(formByte2(data, pos))
pos += 4
item.End = uint32(formByte2(data, pos))
pos += 4
item.CountryCode = int(formByte(data, pos))
pos += 2
item.ProvinceCode = int(formByte(data, pos))
pos += 2
item.CityCode = int(formByte(data, pos))
pos += 2
item.ISPCode = int(formByte(data, pos))
pos += 2
item.DistrictCode = int(formByte(data, pos))
pos += 2
latitude, _ := strconv.ParseFloat(fmt.Sprintf("%.4f", float64(formByte2(data, pos))/float64(10000)), 64)
item.Latitude = latitude
pos += 4
longitude, _ := strconv.ParseFloat(fmt.Sprintf("%.4f", float64(formByte2(data, pos))/float64(10000)), 64)
item.Longitude = longitude
pos += 4
list.IPs = append(list.IPs, item)
}
if len(list.IPs) != count {
err = errors.New("loadIP error")
}
return
}
func (s *Service) loadCounty(data []byte, index *HeadIndex) (countrys map[int]*ZoneInfo, err error) {
var (
pos = index.Country
count = int(formByte(data, pos))
)
pos += 2
countrys = make(map[int]*ZoneInfo)
for i := 0; i < count; i++ {
if pos > len(data) {
break
}
item := new(ZoneInfo)
item.code = int(formByte(data, pos))
pos += 2
lenght := int(int32(data[pos]))
pos++
item.name = string(data[pos : pos+lenght])
pos += lenght
countrys[item.code] = item
}
if len(countrys) != count {
err = errors.New("loadCounty error")
return
}
return
}
func (s *Service) loadProvince(data []byte, index *HeadIndex) (provinces map[int]*ZoneInfo, err error) {
var (
pos = index.Province
count = int(formByte(data, pos))
)
pos += 2
provinces = make(map[int]*ZoneInfo)
for i := 0; i < count; i++ {
if pos > len(data) {
break
}
item := new(ZoneInfo)
item.code = int(formByte(data, pos))
pos += 2
lenght := int(int32(data[pos]))
pos++
item.name = string(data[pos : pos+lenght])
pos += lenght
provinces[item.code] = item
}
if len(provinces) != count {
err = errors.New("loadProvince error")
return
}
return
}
func (s *Service) loadCity(data []byte, index *HeadIndex) (citys map[int]*ZoneInfo, err error) {
var (
pos = index.City
count = int(formByte(data, pos))
)
pos += 2
citys = make(map[int]*ZoneInfo)
for i := 0; i < count; i++ {
if pos > len(data) {
break
}
item := new(ZoneInfo)
item.code = int(formByte(data, pos))
pos += 2
lenght := int(int32(data[pos]))
pos++
item.name = string(data[pos : pos+lenght])
pos += lenght
citys[item.code] = item
}
if len(citys) != count {
err = errors.New("loadCity error")
return
}
return
}
func (s *Service) loadISP(data []byte, index *HeadIndex) (isps map[int]*ZoneInfo, err error) {
var (
pos = index.ISP
count = int(formByte(data, pos))
)
pos += 2
isps = make(map[int]*ZoneInfo)
for i := 0; i < count; i++ {
if pos > len(data) {
break
}
item := new(ZoneInfo)
item.code = int(formByte(data, pos))
pos += 2
lenght := int(int32(data[pos]))
pos++
item.name = string(data[pos : pos+lenght])
pos += lenght
isps[item.code] = item
}
if len(isps) != count {
err = errors.New("loadISP error")
return
}
return
}
func (s *Service) loadDistrict(data []byte, index *HeadIndex) (districts map[int]*ZoneInfo, err error) {
var (
pos = index.District
count = int(formByte(data, pos))
)
pos += 2
districts = make(map[int]*ZoneInfo)
for i := 0; i < count; i++ {
if pos > len(data) {
break
}
item := new(ZoneInfo)
item.code = int(formByte(data, pos))
pos += 2
lenght := int(int32(data[pos]))
pos++
item.name = string(data[pos : pos+lenght])
pos += lenght
districts[item.code] = item
}
if len(districts) != count {
err = errors.New("loadDistrict error")
return
}
return
}

View File

@@ -0,0 +1,137 @@
package service
import (
"context"
"errors"
"net"
"strconv"
"go-common/app/service/main/location/model"
"go-common/library/ecode"
"go-common/library/log"
xip "go-common/library/net/ip"
)
// Info get ip info.
func (s *Service) Info(c context.Context, addr string) (res *model.Info, err error) {
var cityInfo map[string]string
if cityInfo, err = s.find(addr); err != nil {
log.Error("%v", err)
return
}
ic, _ := strconv.Atoi(cityInfo["idd_code"])
la, _ := strconv.ParseFloat(cityInfo["latitude"], 64)
lo, _ := strconv.ParseFloat(cityInfo["longitude"], 64)
res = &model.Info{
Addr: addr,
ZoneID: xip.ZoneID(cityInfo["country_name"], cityInfo["region_name"], cityInfo["city_name"]),
Country: cityInfo["country_name"],
ISP: cityInfo["isp_domain"],
Province: cityInfo["region_name"],
City: cityInfo["city_name"],
Latitude: la,
Longitude: lo,
CountryCode: ic,
}
return
}
// Infos get ip infos.
func (s *Service) Infos(c context.Context, addrs []string) (res map[string]*model.Info, err error) {
res = make(map[string]*model.Info, len(addrs))
for _, addr := range addrs {
var ri *model.Info
if ri, err = s.Info(c, addr); err != nil {
log.Error("%v", err)
res = make(map[string]*model.Info, len(addrs))
break
}
res[addr] = ri
}
return
}
// InfoComplete find get whole ip info.
func (s *Service) InfoComplete(c context.Context, addr string) (res *model.InfoComplete, err error) {
var cityInfo map[string]string
if cityInfo, err = s.find(addr); err != nil {
log.Error("%v", err)
return
}
ic, _ := strconv.Atoi(cityInfo["idd_code"])
la, _ := strconv.ParseFloat(cityInfo["latitude"], 64)
lo, _ := strconv.ParseFloat(cityInfo["longitude"], 64)
res = &model.InfoComplete{
Addr: addr,
Country: cityInfo["country_name"],
Province: cityInfo["region_name"],
City: cityInfo["city_name"],
ISP: cityInfo["isp_domain"],
Latitude: la,
Longitude: lo,
CountryCode: ic,
}
res.ZoneID = s.zoneIDs(cityInfo["country_name"], cityInfo["region_name"], cityInfo["city_name"])
return
}
// InfosComplete finds get whole ips infos.
func (s *Service) InfosComplete(c context.Context, ipsStr []string) (res map[string]*model.InfoComplete, err error) {
res = make(map[string]*model.InfoComplete, len(ipsStr))
for _, ipStr := range ipsStr {
var ti *model.InfoComplete
if ti, err = s.InfoComplete(c, ipStr); err != nil {
log.Error("%v", err)
res = make(map[string]*model.InfoComplete, len(ipsStr))
break
}
res[ipStr] = ti
}
return
}
// zoneIDs make zoneids
func (s *Service) zoneIDs(country, region, city string) []int64 {
cZid := xip.ZoneID(country, "", "")
cpZid := xip.ZoneID(country, region, "")
cpcZid := xip.ZoneID(country, region, city)
zoneids := []int64{0, cZid, cpZid, cpcZid}
return zoneids
}
func (s *Service) find(addr string) (cityInfo map[string]string, err error) {
ipv := net.ParseIP(addr)
if ip := ipv.To4(); ip != nil {
if cityInfo, err = s.v4.FindMap(addr, "CN"); err != nil {
log.Error("%v", err)
return
}
} else if ip := ipv.To16(); ip != nil {
if cityInfo, err = s.v6.FindMap(addr, "CN"); err != nil {
log.Error("%v", err)
return
}
} else {
err = errors.New("query ip format error")
return
}
if cityInfo == nil {
err = ecode.NothingFound
return
}
// ex.: from 中国 台湾 花莲市 to 台湾 花莲市 ”“
if cityInfo["region_name"] == "香港" || cityInfo["region_name"] == "澳门" || cityInfo["region_name"] == "台湾" {
cityInfo["country_name"] = cityInfo["region_name"]
cityInfo["region_name"] = cityInfo["city_name"]
cityInfo["city_name"] = ""
}
// ex.: from 中国 中国 ”“ to 中国 ”“ ”“
if cityInfo["country_name"] == cityInfo["region_name"] {
cityInfo["region_name"] = ""
cityInfo["city_name"] = ""
} else if cityInfo["region_name"] == cityInfo["city_name"] {
// ex.: from 中国 北京 北京 to 中国 北京 ”“
cityInfo["city_name"] = ""
}
return
}

View File

@@ -0,0 +1,80 @@
package service
import (
"context"
"sort"
"strconv"
"go-common/app/service/main/location/model"
"go-common/library/log"
xip "go-common/library/net/ip"
)
// TmpInfo get ip info.
func (s *Service) TmpInfo(addr string) (ti *model.TmpInfo, err error) {
var cityInfo map[string]string
if cityInfo, err = s.find(addr); err != nil {
log.Error("%v", err)
return
}
ti = &model.TmpInfo{
Addr: addr,
ZoneID: xip.ZoneID(cityInfo["country_name"], cityInfo["region_name"], cityInfo["city_name"]),
Country: cityInfo["country_name"],
Province: cityInfo["region_name"],
City: cityInfo["city_name"],
}
return
}
// TmpInfos get ip infos.
func (s *Service) TmpInfos(c context.Context, addrs ...string) (zone []*xip.Zone, err error) {
addrs = RemoveDuplicatesAndEmpty(addrs)
zone = make([]*xip.Zone, len(addrs))
for ide, addr := range addrs {
var tmp *xip.Zone
if tmp, err = s.TmpInfo2(c, addr); err != nil {
log.Error("%v", err)
zone = make([]*xip.Zone, len(addrs))
break
}
zone[ide] = tmp
}
return
}
// TmpInfo2 get ip zone from ip
func (s *Service) TmpInfo2(c context.Context, addr string) (zone *xip.Zone, err error) {
var cityInfo map[string]string
if cityInfo, err = s.find(addr); err != nil {
log.Error("%v", err)
return
}
ic, _ := strconv.Atoi(cityInfo["idd_code"])
la, _ := strconv.ParseFloat(cityInfo["latitude"], 64)
lo, _ := strconv.ParseFloat(cityInfo["longitude"], 64)
zone = &xip.Zone{
ID: xip.ZoneID(cityInfo["country_name"], cityInfo["region_name"], cityInfo["city_name"]),
Addr: addr,
ISP: cityInfo["isp_domain"],
Country: cityInfo["country_name"],
Province: cityInfo["region_name"],
City: cityInfo["city_name"],
Latitude: la,
Longitude: lo,
CountryCode: ic,
}
return
}
// RemoveDuplicatesAndEmpty string去重 去空
func RemoveDuplicatesAndEmpty(a []string) (ret []string) {
sort.Strings(a)
for i := 0; i < len(a); i++ {
if (i > 0 && a[i-1] == a[i]) || len(a[i]) == 0 {
continue
}
ret = append(ret, a[i])
}
return
}

View File

@@ -0,0 +1,32 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_TmpInfo(t *testing.T) {
Convey("ip tmp info", t, WithService(func(s *Service) {
res, err := s.TmpInfo("211.139.80.6")
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
}))
}
func Test_TmpInfos(t *testing.T) {
Convey("ips tmp info", t, WithService(func(s *Service) {
res, err := s.TmpInfos(context.Background(), []string{"211.139.80.6", "64.233.173.24"}...)
So(res, ShouldNotBeEmpty)
So(err, ShouldBeNil)
}))
}
func Test_TmpInfo2(t *testing.T) {
Convey("ip tmp info", t, WithService(func(s *Service) {
res, err := s.TmpInfo2(context.Background(), "211.139.80.6")
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,40 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Info(t *testing.T) {
Convey("ip info", t, WithService(func(s *Service) {
res, err := s.Info(context.Background(), "211.139.80.6")
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
}))
}
func Test_Infos(t *testing.T) {
Convey("ips info", t, WithService(func(s *Service) {
res, err := s.Infos(context.Background(), []string{"211.139.80.6", "64.233.173.24"})
So(res, ShouldNotBeEmpty)
So(err, ShouldBeNil)
}))
}
func Test_InfoComplete(t *testing.T) {
Convey("ip complete info", t, WithService(func(s *Service) {
res, err := s.InfoComplete(context.Background(), "211.139.80.6")
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
}))
}
func Test_InfosComplete(t *testing.T) {
Convey("ips complete info", t, WithService(func(s *Service) {
res, err := s.InfosComplete(context.Background(), []string{"211.139.80.6", "64.233.173.24"})
So(res, ShouldNotBeEmpty)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,235 @@
package service
import (
"context"
"path"
"time"
accoutCli "go-common/app/service/main/account/api"
"go-common/app/service/main/location/conf"
"go-common/app/service/main/location/dao"
"go-common/app/service/main/location/model"
"go-common/library/log"
"go-common/library/stat/prom"
ipdb "github.com/ipipdotnet/ipdb-go"
maxminddb "github.com/oschwald/maxminddb-golang"
"github.com/pkg/errors"
)
// Service define resource service
type Service struct {
c *conf.Config
zdb *dao.Dao
accountSvc accoutCli.AccountClient
anonym *maxminddb.Reader
anonymFileName string
// cache
policy map[int64]map[int64]int64
groupPolicy map[int64][]int64
// groupid by zone_id
groupAuthZone map[int64]map[int64]map[int64]int64
missch chan interface{}
// prom
missedPorm *prom.Prom
authCodePorm *prom.Prom
innerIPPorm *prom.Prom
// new ip library
v4 *ipdb.City
v6 *ipdb.City
version4 string
version6 string
}
// New new a Service and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
zdb: dao.New(c),
missch: make(chan interface{}, 1024),
policy: make(map[int64]map[int64]int64),
groupPolicy: make(map[int64][]int64),
groupAuthZone: make(map[int64]map[int64]map[int64]int64),
missedPorm: prom.New().WithCounter("auth_missed", []string{"method"}),
authCodePorm: prom.New().WithCounter("auth_code", []string{"method"}),
innerIPPorm: prom.New().WithCounter("inner_ipaddr", []string{"method"}),
anonymFileName: c.AnonymFileName,
}
accountSvc, err := accoutCli.NewClient(c.Account)
if err != nil {
panic(err)
}
s.accountSvc = accountSvc
if err := s.loadIPs(); err != nil {
panic(err)
}
if err := s.loadAnonymous(); err != nil {
panic(err)
}
if err := s.LoadPolicy(); err != nil {
panic(err)
}
go s.reloadproc()
go s.cacheproc()
go s.reloadanonymous()
return
}
// loadIPs load ip from ip.txt.
func (s *Service) loadIPs() (err error) {
var (
v4File = path.Join(s.c.FilePath, s.c.IPv4Name)
v6File = path.Join(s.c.FilePath, s.c.IPv6Name)
tmpV4 *ipdb.City
tmpV6 *ipdb.City
verison *model.Version
)
if verison, err = s.zdb.CheckVersion(context.Background()); err != nil || verison == nil {
log.Error("%v or version is nil", err)
return
}
if s.version4 != verison.StableV4 {
log.Info("star down IPv4 library verson(%v) filename(%v)", verison.StableV4, v4File)
if err = s.zdb.DownIPLibrary(context.Background(), verison.StableV4, v4File); err != nil {
log.Error("error(%v) verson(%v) filename(%v)", err, verison.StableV4, v4File)
return
}
log.Info("success down IPv4 library")
log.Info("start load IPv4 library filename(%s)!", v4File)
if tmpV4, err = ipdb.NewCity(v4File); err != nil {
log.Error("load new IPv4 library error(%v)", err)
err = errors.WithStack(err)
return
}
s.v4 = tmpV4
s.version4 = verison.StableV4
log.Info("success load IPv4 library")
}
if s.version6 != verison.StableV6 {
log.Info("star down IPv6 library verson(%v) filename(%v)", verison.StableV6, v6File)
if err = s.zdb.DownIPLibrary(context.Background(), verison.StableV6, v6File); err != nil {
log.Error("error(%v) verson(%v) filename(%v)", err, verison.StableV6, v6File)
return
}
log.Info("success down IPv6 library")
log.Info("start load IPv6 library filename(%s)!", v6File)
if tmpV6, err = ipdb.NewCity(v6File); err != nil {
err = errors.WithStack(err)
return
}
s.v6 = tmpV6
s.version6 = verison.StableV6
log.Info("success load IPv6 library")
}
return
}
// reloadanonymous reload anonymous data.
func (s *Service) reloadIPs() {
for {
time.Sleep(time.Second * 86400)
s.loadIPs()
}
}
// loadAnonymous load anonymous ip.
func (s *Service) loadAnonymous() (err error) {
log.Info("start down load Anonymous")
if err = s.zdb.DownloadAnonym(); err != nil {
log.Error("down load Anonymous faild error(%v)", err)
return
}
log.Info("success down load Anonymous")
var (
anonymFile = path.Join(s.c.FilePath, s.c.AnonymFileName)
tmpAnonym *maxminddb.Reader
)
log.Info("start load Anonymous IP library filename(%s)!", anonymFile)
if tmpAnonym, err = s.NewAnonym(anonymFile); err != nil {
err = errors.WithStack(err)
return
}
s.anonym = tmpAnonym
log.Info("success load Anonymous IP library")
return
}
// reloadanonymous reload anonymous data.
func (s *Service) reloadanonymous() {
for {
if time.Now().Weekday().String() == "Monday" && time.Now().Hour() == 0 {
s.loadAnonymous()
}
time.Sleep(time.Minute * 60)
}
}
// LoadPolicy locad policy from db
func (s *Service) LoadPolicy() (err error) {
log.Info("start load policy cache !")
var (
tmpPolicy map[int64]map[int64]int64
tmpGroupPolicy map[int64][]int64
tmpGroupAuthZone map[int64]map[int64]map[int64]int64
)
log.Info("start to load s.policy")
if tmpPolicy, err = s.zdb.Policies(context.TODO()); err != nil {
return
} else if len(tmpPolicy) > 0 {
s.policy = tmpPolicy
}
log.Info("start to load s.groupPolicy")
if tmpGroupPolicy, err = s.zdb.GroupPolicies(context.TODO()); err != nil {
log.Error("s.groupPolicies error(%+v)", err)
} else if len(tmpGroupPolicy) > 0 {
s.groupPolicy = tmpGroupPolicy
}
log.Info("start to load s.zoneGroup")
if tmpGroupAuthZone, err = s.zdb.GroupAuthZone(context.TODO()); err != nil {
log.Error("s.GroupAuthZone error(%+v)", err)
} else if len(tmpGroupAuthZone) > 0 {
s.groupAuthZone = tmpGroupAuthZone
}
return
}
// reloadproc reload data from db.
func (s *Service) reloadproc() {
for {
time.Sleep(time.Minute * 10)
s.LoadPolicy()
}
}
// Close dao.
func (s *Service) Close() {}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
return s.zdb.Ping(c)
}
func (s *Service) addCache(d interface{}) {
// asynchronous add rules to redis
select {
case s.missch <- d:
default:
log.Warn("cacheproc chan full")
}
}
// cacheproc is a routine for add rules into redis.
func (s *Service) cacheproc() {
for {
d := <-s.missch
switch d.(type) {
case map[int64]map[int64]int64:
v := d.(map[int64]map[int64]int64)
if err := s.zdb.AddAuth(context.TODO(), v); err != nil {
log.Error("s.zdb.AddAuth(%v) error(%+v)", v, err)
}
default:
log.Warn("cacheproc can't process the type")
}
}
}

View File

@@ -0,0 +1,38 @@
package service
import (
"context"
"flag"
"path/filepath"
"time"
"go-common/app/service/main/location/conf"
"go-common/library/cache/redis"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func CleanCache() {
c := context.TODO()
pool := redis.NewPool(conf.Conf.Redis.Zlimit.Config)
pool.Get(c).Do("FLUSHDB")
}
func init() {
dir, _ := filepath.Abs("../cmd/convey-test.toml")
flag.Set("conf", dir)
conf.Init()
s = New(conf.Conf)
time.Sleep(time.Second)
}
func WithService(f func(s *Service)) func() {
return func() {
Reset(func() { CleanCache() })
f(s)
}
}

View File

@@ -0,0 +1,316 @@
package service
import (
"context"
accoutCli "go-common/app/service/main/account/api"
"go-common/app/service/main/location/model"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
// PgcZone get group_id by zoneid .
func (s *Service) PgcZone(c context.Context, zoneIDs []int64) (res map[string][]int64, err error) {
var (
ok bool
fb, al map[int64]int64
gidNotIn = []int64{}
gidIn = []int64{}
)
res = make(map[string][]int64)
for gid, authZid := range s.groupAuthZone {
// forbidden priority.
for k, zoneID := range zoneIDs {
if fb, ok = authZid[model.Forbidden]; ok {
if _, ok = fb[zoneID]; ok {
gidNotIn = append(gidNotIn, gid)
break
} else {
// final value
if k == len(zoneIDs)-1 {
gidIn = append(gidIn, gid)
}
}
} else if al, ok = authZid[model.Allow]; ok {
if _, ok = al[zoneID]; ok {
gidIn = append(gidIn, gid)
break
} else {
// final value
if k == len(zoneIDs)-1 {
gidNotIn = append(gidNotIn, gid)
}
}
}
}
}
res["not_in"] = gidNotIn
res["in"] = gidIn
return
}
func (s *Service) checkLimit(c context.Context, mid, code int64, ip string) int64 {
switch code {
case model.Allow, model.Forbidden:
return code
case model.Formal:
if mid == 0 {
return model.Forbidden
}
if card, err := s.accCard(c, mid, ip); err != nil {
return model.Forbidden
} else if card != nil && card.Level < 1 && (card.Vip.Type == 0 || card.Vip.Status == 0 || card.Vip.Status == 2 || card.Vip.Status == 3) {
return model.Forbidden
} else {
return model.Allow
}
case model.Pay:
// TODO VIP member
}
return model.Forbidden
}
func (s *Service) accCard(c context.Context, mid int64, ip string) (ai *accoutCli.Card, err error) {
arg := &accoutCli.MidReq{
Mid: mid,
}
cr := &accoutCli.CardReply{}
if cr, err = s.accountSvc.Card3(c, arg); err != nil {
err = errors.Wrapf(err, "mid(%d)", mid)
return
}
return cr.Card, nil
}
// Auth get auth by aid and ipaddr & check mid.
func (s *Service) Auth(c context.Context, aid, mid int64, ipaddr, cdnip string) (ret int64, err error) {
var retdown int64
if ret, retdown, err = s.Auth2(c, aid, ipaddr, cdnip); err != nil {
err = errors.Wrapf(err, "s.Auth2(%d, %s, %s)", aid, ipaddr, cdnip)
return
}
s.authCodePorm.Incr(model.PlayAuth[ret])
s.authCodePorm.Incr(model.DownAuth[retdown])
ret = s.checkLimit(c, mid, ret, ipaddr)
return
}
// Archive2 get auth by aid and ipaddr & check mid.
func (s *Service) Archive2(c context.Context, aid, mid int64, ipaddr, cdnip string) (res *model.Auth, err error) {
var ret, retdown int64
if ret, retdown, err = s.Auth2(c, aid, ipaddr, cdnip); err != nil {
err = errors.Wrapf(err, "s.Auth2(%d, %s, %s)", aid, ipaddr, cdnip)
return
}
s.authCodePorm.Incr(model.PlayAuth[ret])
s.authCodePorm.Incr(model.DownAuth[retdown])
ret = s.checkLimit(c, mid, ret, ipaddr)
res = &model.Auth{Play: ret, Down: retdown}
return
}
// Auth2 get auth by aid and ipaddr.
func (s *Service) Auth2(c context.Context, aid int64, ipaddr, cdnip string) (ret, retdown int64, err error) {
var (
ok bool
auth, pid, zid, gid int64
rules, pids []int64
zids map[int64]int64
ipInfo *model.InfoComplete
)
ipInfo, _ = s.InfoComplete(c, ipaddr)
if (ipInfo == nil || (ipInfo != nil && s.filterInnerIP(ipInfo))) && cdnip != "" {
log.Info("ip(%v) aid(%v) cdnip(%v), ipaddr is nil or is filter zone", ipaddr, aid, cdnip)
s.innerIPPorm.Add("archive", 1)
ipInfo, _ = s.InfoComplete(c, cdnip)
}
if ipInfo == nil {
ret = model.Allow
retdown = model.AllowDown
return
}
uz := ipInfo.ZoneID // country, state, city
if ok, err = s.zdb.ExistsAuth(c, aid); err != nil {
log.Error("s.zdb.ExistsAuth error(%+v)", err)
err = nil
} else if ok {
if rules, err = s.zdb.Auth(c, aid, uz); err != nil {
log.Error("s.zdb.Auth(%d) error(%+v) ", aid, err)
err = nil
} else {
for _, auth = range rules {
retdown = 0xff & auth
ret = auth >> 8
if ret != 0 {
break
}
}
if ret == 0 {
ret = model.Allow
retdown = model.AllowDown
}
return
}
}
s.missedPorm.Incr("redis_missed")
if gid, err = s.zdb.Groupid(c, aid); err != nil {
return
} else if gid != 0 {
if pids, ok = s.groupPolicy[gid]; ok {
for _, pid = range pids {
if zids, ok = s.policy[pid]; !ok {
continue
}
if ret == 0 {
// ret already set skip check
for _, zid = range uz {
if auth, ok = zids[zid]; ok {
if ret == 0 {
retdown = 0xff & auth
ret = auth >> 8 // ret must not be zero
break
}
}
}
}
tmpZids := map[int64]map[int64]int64{
aid: zids,
}
s.addCache(tmpZids)
}
if ret == 0 {
s.missedPorm.Incr("local_policy_cache_missed")
ret = model.Allow
retdown = model.AllowDown
}
return
}
s.missedPorm.Incr("local_group_cache_missed")
}
s.missedPorm.Incr("db_missed")
ret = model.Allow
retdown = model.AllowDown
zids = make(map[int64]int64)
zids[0] = ret<<8 | retdown
tmpZids := map[int64]map[int64]int64{
aid: zids,
}
s.addCache(tmpZids)
return
}
// AuthGID auth by group_id and ipaddr(or cdnip) & check mid.
func (s *Service) AuthGID(c context.Context, gid, mid int64, ipaddr, cdnip string) (res *model.Auth) {
ret, retdown := s.AuthGID2(c, gid, ipaddr, cdnip)
s.authCodePorm.Incr(model.PlayAuth[ret])
s.authCodePorm.Incr(model.DownAuth[retdown])
ret = s.checkLimit(c, mid, ret, ipaddr)
res = &model.Auth{
Play: ret,
Down: retdown,
}
return
}
// AuthGIDs auth by group_id and ipaddr(or cdnip) & check mid.
func (s *Service) AuthGIDs(c context.Context, gids []int64, mid int64, ipaddr, cdnip string) (res map[int64]*model.Auth) {
res = make(map[int64]*model.Auth)
for _, gid := range gids {
ret, retdown := s.AuthGID2(c, gid, ipaddr, cdnip)
s.authCodePorm.Incr(model.PlayAuth[ret])
s.authCodePorm.Incr(model.DownAuth[retdown])
ret = s.checkLimit(c, mid, ret, ipaddr)
res[gid] = &model.Auth{
Play: ret,
Down: retdown,
}
}
return
}
// AuthGID2 auth by group_id and ipaddr(or cdnip).
func (s *Service) AuthGID2(c context.Context, gid int64, ipaddr, cdnip string) (ret, retdown int64) {
var (
ipInfo *model.InfoComplete
hitMark string
)
ret = model.Allow
retdown = model.AllowDown
ipInfo, _ = s.InfoComplete(c, ipaddr)
if (ipInfo == nil || (ipInfo != nil && s.filterInnerIP(ipInfo))) && cdnip != "" {
log.Info("ip(%v) gid(%v) cdnip(%v), ipaddr is nil or is filter zone", ipaddr, gid, cdnip)
s.innerIPPorm.Add("group", 1)
ipInfo, _ = s.InfoComplete(c, cdnip)
}
if ipInfo == nil {
return
}
if pids, ok := s.groupPolicy[gid]; ok {
for _, pid := range pids {
if _, ok := s.policy[pid]; !ok {
continue
}
for _, zoneid := range ipInfo.ZoneID {
if auth, ok := s.policy[pid][zoneid]; ok {
retdown = 0xff & auth
ret = auth >> 8
hitMark = "hit"
break
}
}
}
}
if len(hitMark) == 0 {
s.missedPorm.Incr("local_cache_missed")
}
return
}
// AuthPIDs check by policy_ids and ipaddr
func (s *Service) AuthPIDs(c context.Context, pidStr, ipaddr, cdnip string) (res map[int64]*model.Auth, err error) {
var (
pids []int64
ipInfo *model.InfoComplete
)
res = make(map[int64]*model.Auth, len(pids))
if pids, err = xstr.SplitInts(pidStr); err != nil || len(pids) == 0 {
log.Error("xstr.SplitInts(%v) error(%v) or pids is empty", pidStr, err)
return
}
ipInfo, _ = s.InfoComplete(c, ipaddr)
if (ipInfo == nil || (ipInfo != nil && s.filterInnerIP(ipInfo))) && cdnip != "" {
ipInfo, _ = s.InfoComplete(c, cdnip)
}
if ipInfo == nil {
return
}
for _, pid := range pids {
res[pid] = &model.Auth{
Play: model.Allow,
Down: model.AllowDown,
}
if _, ok := s.policy[pid]; !ok {
continue
}
for _, zoneid := range ipInfo.ZoneID {
if auth, ok := s.policy[pid][zoneid]; ok {
res[pid].Down = 0xff & auth
res[pid].Play = auth >> 8
break
}
}
}
return
}
func (s *Service) filterInnerIP(ip *model.InfoComplete) bool {
for _, zone := range s.c.FilterZone {
if ip.Country == zone || ip.Province == zone || ip.City == zone {
return true
}
}
return false
}

View File

@@ -0,0 +1,29 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_PgcZone(t *testing.T) {
Convey("pgc zone in", t, WithService(func(s *Service) {
_, err := s.PgcZone(context.Background(), []int64{2, 124425})
So(err, ShouldBeNil)
}))
}
func Test_Auth(t *testing.T) {
Convey("get archive auth", t, WithService(func(s *Service) {
_, err := s.Auth(context.Background(), 740955, 13414510, "211.139.80.6", "64.233.173.24")
So(err, ShouldBeNil)
}))
}
func Test_AuthGID(t *testing.T) {
Convey("get group auth", t, WithService(func(s *Service) {
res := s.AuthGID(context.Background(), 1195, 13414510, "211.139.80.6", "64.233.173.24")
So(res, ShouldNotBeNil)
}))
}

View File

@@ -0,0 +1,56 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["zlimit_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//library/cache/redis:go_default_library",
"//library/container/pool:go_default_library",
"//library/database/sql:go_default_library",
"//library/time:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"cache.go",
"db.go",
"zlimit.go",
],
importpath = "go-common/app/service/main/location/zlimit",
tags = ["automanaged"],
deps = [
"//app/service/main/location/model:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/ip:go_default_library",
"//library/time:go_default_library",
"//library/xstr: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,88 @@
package zlimit
import (
"context"
"strconv"
"go-common/library/cache/redis"
"go-common/library/log"
)
func keyZlimit(aid int64) (key string) {
key = _prefixBlackList + strconv.FormatInt(aid, 10)
return
}
// existsRule if existes ruls in redis
func (s *Service) existsRule(c context.Context, aid int64) (ok bool, err error) {
conn := s.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXISTS", keyZlimit(aid))); err != nil {
log.Error("conn.DO(HEXISTS) error(%v)", err)
}
return
}
// rule get zone rule from redis
func (s *Service) rule(c context.Context, aid int64, zoneids []int64) (res []int64, err error) {
var playauth int64
key := keyZlimit(aid)
conn := s.redis.Get(c)
defer conn.Close()
for _, v := range zoneids {
if err = conn.Send("HGET", key, v); err != nil {
log.Error("rule conn.Send(HGET, %s, %d) error(%v)", key, v, err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("rule conn.Flush error(%v)", err)
return
}
for i := 0; i < len(zoneids); i++ {
if playauth, err = redis.Int64(conn.Receive()); err != nil {
if err != redis.ErrNil {
log.Error("rule conn.Receive()%d error(%v)", i+1, err)
return
}
err = nil
}
res = append(res, playauth)
}
return
}
// addRule add zone rule from redis
func (s *Service) addRule(c context.Context, zoneids map[int64]map[int64]int64) (err error) {
var key string
conn := s.redis.Get(c)
defer conn.Close()
count := 0
for aid, zids := range zoneids {
if key == "" {
key = keyZlimit(aid)
}
for zid, auth := range zids {
if err = conn.Send("HSET", key, zid, auth); err != nil {
log.Error("add conn.Send error(%v)", err)
return
}
count++
}
}
if err = conn.Send("EXPIRE", key, s.expire); err != nil {
log.Error("add conn.Send error(%v)", err)
return
}
if err = conn.Flush(); err != nil {
log.Error("add conn.Flush error(%v)", err)
return
}
for i := 0; i <= count; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("add conn.Receive()%d error(%v)", i+1, err)
return
}
}
return
}

View File

@@ -0,0 +1,96 @@
package zlimit
import (
"context"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_getPolicySQL = "SELECT id, play_auth, down_auth, zone_id FROM policy_item WHERE zone_id <> '' AND state=1"
_getRelationSQL = "SELECT policy_id FROM archive_relation WHERE aid=?"
_getGolbalPolicySQL = "select group_id,group_concat(id) from policy_item WHERE zone_id <> '' AND state=1 GROUP BY group_id"
)
// policies get policy data from db
func (s *Service) policies(c context.Context) (res map[int64]map[int64]int64, err error) {
var (
tmpres map[int64]int64
ok bool
)
rows, err := s.db.Query(c, _getPolicySQL)
if err != nil {
log.Error("db.Query error(%v)", err)
return
}
defer rows.Close()
res = make(map[int64]map[int64]int64)
for rows.Next() {
var (
pid, playAuth, downAuth int64
zoneID string
zoneIDs []int64
)
if err = rows.Scan(&pid, &playAuth, &downAuth, &zoneID); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
if zoneIDs, err = xstr.SplitInts(zoneID); err != nil {
log.Error("xstr.SplitInts(%s) error(%v)", zoneID, err)
continue
}
for _, zoneid := range zoneIDs {
if tmpres, ok = res[pid]; !ok {
tmpres = make(map[int64]int64)
res[pid] = tmpres
}
resCode := playAuth<<8 | downAuth
tmpres[zoneid] = resCode
}
}
return
}
// groupPolicies get policy data from db group by group_id
func (s *Service) groupPolicies(c context.Context) (res map[int64][]int64, err error) {
rows, err := s.db.Query(c, _getGolbalPolicySQL)
if err != nil {
log.Error("db.Query error(%v)", err)
return
}
defer rows.Close()
res = make(map[int64][]int64)
for rows.Next() {
var (
groupID int64
pids string
zoneIDs []int64
)
if err = rows.Scan(&groupID, &pids); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
if zoneIDs, err = xstr.SplitInts(pids); err != nil {
log.Error("xstr.SplitInts(%s) error(%v)", pids, err)
continue
}
res[groupID] = zoneIDs
}
return
}
// policy get pids from db by aid
func (s *Service) groupid(c context.Context, aid int64) (gid int64, err error) {
row := s.getRelationStmt.QueryRow(c, aid)
if err = row.Scan(&gid); err != nil {
if err == sql.ErrNoRows {
gid = 0
err = nil
} else {
log.Error("rows.Scan error(%v)", err)
}
}
return
}

View File

@@ -0,0 +1,300 @@
package zlimit
import (
"context"
"time"
"go-common/app/service/main/location/model"
"go-common/library/cache/redis"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
xip "go-common/library/net/ip"
xtime "go-common/library/time"
"go-common/library/xstr"
)
const (
_prefixBlackList = "zl_"
)
// Config default struct
type Config struct {
DB *sql.Config
Redis *Redis
IPFile string
FlushTime xtime.Duration
}
// Redis redis struct
type Redis struct {
*redis.Config
Expire xtime.Duration
}
// Service zlimit service struct
type Service struct {
// mysql
db *sql.DB
getPolicyStmt *sql.Stmt
getRelationStmt *sql.Stmt
getGroupPolicyStmt *sql.Stmt
// redis
redis *redis.Pool
expire int32
flushTime time.Duration
// cache
policy map[int64]map[int64]int64
groupPolicy map[int64][]int64
missch chan interface{}
// xip
list *xip.List
}
// New new zlimit service
func New(c *Config) (s *Service) {
var err error
s = &Service{
db: sql.NewMySQL(c.DB),
redis: redis.NewPool(c.Redis.Config),
expire: int32(time.Duration(c.Redis.Expire) / time.Second),
missch: make(chan interface{}, 1024),
policy: make(map[int64]map[int64]int64),
groupPolicy: make(map[int64][]int64),
flushTime: time.Duration(c.FlushTime),
}
s.getPolicyStmt = s.db.Prepared(_getPolicySQL)
s.getRelationStmt = s.db.Prepared(_getRelationSQL)
s.getGroupPolicyStmt = s.db.Prepared(_getGolbalPolicySQL)
s.load()
s.list, err = xip.New(c.IPFile)
if err != nil {
log.Error("xip.New(%s) error(%v)", c.IPFile, err)
panic(err)
}
go s.reloadproc()
go s.cacheproc()
return
}
func (s *Service) load() {
var (
tmpPolicy map[int64]map[int64]int64
tmpGroupPolicy map[int64][]int64
err error
)
if tmpPolicy, err = s.policies(context.TODO()); err != nil {
log.Error("s.policies error(%v)", err)
} else if len(tmpPolicy) > 0 {
s.policy = tmpPolicy
}
if tmpGroupPolicy, err = s.groupPolicies(context.TODO()); err != nil {
log.Error("s.groupPolicies error(%v)", err)
} else if len(tmpGroupPolicy) > 0 {
s.groupPolicy = tmpGroupPolicy
}
}
// reloadproc reload data from db
func (s *Service) reloadproc() {
for {
s.load()
time.Sleep(s.flushTime)
}
}
// Find redio rule by aid and ipaddr
func (s *Service) Find(c context.Context, aid int64, ipaddr, cdnip string) (ret, retdown int64, err error) {
var (
ok bool
auth, pid, zid, gid int64
rules, pids []int64
zids map[int64]int64
ipInfo *xip.Zone
)
ipInfo = s.list.Zone(ipaddr)
if (ipInfo != nil) && (ipInfo.Province == "共享地址" || ipInfo.City == "共享地址") && cdnip != "" {
ipInfo = s.list.Zone(cdnip)
}
if ipInfo == nil {
ret = model.Allow
retdown = model.AllowDown
return
}
uz := s.zoneids(ipInfo) // country, state, city
if ok, err = s.existsRule(c, aid); err != nil {
log.Error("s.existsRule error(%v)", err)
err = nil
} else if ok {
if rules, err = s.rule(c, aid, uz); err != nil {
log.Error("s.rule(%d) error(%v) ", aid, err)
err = nil
} else {
for _, auth = range rules {
retdown = 0xff & auth
ret = auth >> 8
if ret != 0 {
break
}
}
if ret == 0 {
ret = model.Allow
retdown = model.AllowDown
}
return
}
}
if gid, err = s.groupid(c, aid); err != nil {
return
} else if gid != 0 {
if pids, ok = s.groupPolicy[gid]; ok {
for _, pid = range pids {
if zids, ok = s.policy[pid]; !ok {
continue
}
if ret == 0 {
// ret already set skip check
for _, zid = range uz {
if auth, ok = zids[zid]; ok {
if ret == 0 {
retdown = 0xff & auth
ret = auth >> 8 // ret must not be zero
break
}
}
}
}
tmpZids := map[int64]map[int64]int64{
aid: zids,
}
s.addCache(tmpZids)
}
if ret == 0 {
ret = model.Allow
retdown = model.AllowDown
}
return
}
}
ret = model.Allow
retdown = model.AllowDown
zids = make(map[int64]int64)
zids[0] = ret<<8 | retdown
tmpZids := map[int64]map[int64]int64{
aid: zids,
}
s.addCache(tmpZids)
return
}
// Forbid check ip is forbid or not.
func (s *Service) Forbid(c context.Context, pstr string, ipaddr string) (err error) {
if pstr == "" {
return
}
var (
ret int64
pids []int64
)
if pids, err = xstr.SplitInts(pstr); err != nil {
log.Error("xstr.SplitInts(%s) error(%v)", pstr, err)
return
}
if ret, _ = s.FindByPid(c, pids, ipaddr); ret == model.Forbidden {
err = ecode.ZlimitForbidden
}
return
}
// FindByPid redio rule by policy_id and ipaddr
func (s *Service) FindByPid(c context.Context, pids []int64, ipaddr string) (ret, retdown int64) {
var (
ok bool
auth int64
zoneids []int64
)
ret = model.Allow
retdown = model.AllowDown
ipInfo := s.list.Zone(ipaddr)
if ipInfo == nil {
return
}
zoneids = s.zoneids(ipInfo)
for _, pid := range pids {
if _, ok = s.policy[pid]; !ok {
continue
}
for _, zoneid := range zoneids {
if auth, ok = s.policy[pid][zoneid]; ok {
retdown = 0xff & auth
ret = auth >> 8
break
}
}
}
return
}
// FindByGid redio rule by group_id and ipaddr(or cdnip)
func (s *Service) FindByGid(c context.Context, gid int64, ipaddr, cdnip string) (ret, retdown int64) {
var ipInfo *xip.Zone
ret = model.Allow
retdown = model.AllowDown
ipInfo = s.list.Zone(ipaddr)
if (ipInfo != nil) && (ipInfo.Province == "共享地址" || ipInfo.City == "共享地址") && cdnip != "" {
ipInfo = s.list.Zone(cdnip)
}
if ipInfo == nil {
return
}
zoneids := s.zoneids(ipInfo)
if pids, ok := s.groupPolicy[gid]; ok {
for _, pid := range pids {
if _, ok := s.policy[pid]; !ok {
continue
}
for _, zoneid := range zoneids {
if auth, ok := s.policy[pid][zoneid]; ok {
retdown = 0xff & auth
ret = auth >> 8
break
}
}
}
}
return
}
// zoneids make zoneids
func (s *Service) zoneids(ipinfos *xip.Zone) []int64 {
cZid := xip.ZoneID(ipinfos.Country, "", "")
cpZid := xip.ZoneID(ipinfos.Country, ipinfos.Province, "")
cpcZid := xip.ZoneID(ipinfos.Country, ipinfos.Province, ipinfos.City)
zoneids := []int64{0, cZid, cpZid, cpcZid}
return zoneids
}
func (s *Service) addCache(d interface{}) {
// asynchronous add rules to redis
select {
case s.missch <- d:
default:
log.Warn("cacheproc chan full")
}
}
// cacheproc is a routine for add rules into redis.
func (s *Service) cacheproc() {
for {
d := <-s.missch
switch d.(type) {
case map[int64]map[int64]int64:
v := d.(map[int64]map[int64]int64)
if err := s.addRule(context.TODO(), v); err != nil {
log.Error("s.addRule error(%v) error(%v)", v, err)
}
default:
log.Warn("cacheproc can't process the type")
}
}
}

View File

@@ -0,0 +1,71 @@
package zlimit
import (
"context"
"testing"
"time"
"go-common/library/cache/redis"
"go-common/library/container/pool"
"go-common/library/database/sql"
xtime "go-common/library/time"
)
func TestZlimit(t *testing.T) {
c := &Config{
DB: &sql.Config{
Addr: "172.16.33.54:3306",
DSN: "test:test@tcp(172.16.33.54:3306)/bilibili_oversea?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4",
Active: 5,
Idle: 2,
},
Redis: &Redis{
Config: &redis.Config{
Config: &pool.Config{
Active: 20,
Idle: 10,
IdleTimeout: xtime.Duration(80 * time.Millisecond),
},
Name: "business/zlimit",
Proto: "tcp",
Addr: "172.16.33.54:6380",
DialTimeout: xtime.Duration(50 * time.Millisecond),
ReadTimeout: xtime.Duration(100 * time.Millisecond),
WriteTimeout: xtime.Duration(100 * time.Millisecond),
},
Expire: xtime.Duration(1 * time.Second),
},
IPFile: "/data/conf/iprepo/iprepo.txt",
FlushTime: xtime.Duration(1 * time.Second),
}
s := New(c)
testFind(t, s, 0, "", "")
testForbid(t, s, "", "")
testFindByPid(t, s, []int64{0}, "")
testFindByGid(t, s, 0, "", "")
}
func testFind(t *testing.T, s *Service, aid int64, ipaddr, cdnip string) {
ret, retdown, err := s.Find(context.TODO(), aid, ipaddr, cdnip)
if err != nil {
t.Errorf("Service: find err: %v", err)
} else {
t.Logf("Service: find %d,%d", ret, retdown)
}
}
func testForbid(t *testing.T, s *Service, pstr, ipaddr string) {
if err := s.Forbid(context.TODO(), pstr, ipaddr); err != nil {
t.Errorf("Service: forbid err: %v", err)
}
}
func testFindByPid(t *testing.T, s *Service, pids []int64, ipaddr string) {
ret, retdown := s.FindByPid(context.TODO(), pids, ipaddr)
t.Logf("Service: findByPid %d,%d", ret, retdown)
}
func testFindByGid(t *testing.T, s *Service, gid int64, ipaddr, cdnip string) {
ret, retdown := s.FindByGid(context.TODO(), gid, ipaddr, cdnip)
t.Logf("Service: findByGid %d,%d", ret, retdown)
}