Initial commit

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

View File

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

View File

@@ -0,0 +1,33 @@
## passport-service
#### Version 1.7.1
> 1. add dao ut
#### Version 1.8.0
> 1.add history pwd check
#### Version 1.7.0
> 1.升级HBase
#### Version 1.6.0
> 1.use bm
#### Version 1.5.0
> 1.add limit param to get login log API and RPC request struct
> 2.move project dir from business/service to business/service/main
#### Version 1.4.0
> 1.change face apply hbase table name from user_face_new to account:user_face
#### Version 1.3.0
> 1.remove panic in reverse id when mid string length > 10
> 2.use goconvey in service UTs
#### Version 1.2.0
> 1.add get login logs from hbase API
> 2.change for face apply hbase table's new row key
#### Version 1.0.1
> 1.remove ping hbase in dao
#### Version 1.0.0
> 1.添加读取用户头像hbase表接口

View File

@@ -0,0 +1,11 @@
# Owner
wanghuan01
# Author
wanghuan01
wucongyou
# Reviewer
linmiao
wanghuan01
wutao

View File

@@ -0,0 +1,16 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wanghuan01
- wucongyou
labels:
- main
- service
- service/main/passport
options:
no_parent_owners: true
reviewers:
- linmiao
- wanghuan01
- wucongyou
- wutao

View File

@@ -0,0 +1,13 @@
## passport-service
#### 项目简介
> 1.passport服务
#### 编译环境
> 请只用golang v1.8.x以上版本编译执行。
#### 依赖包
> 1.公共包go-common
#### 特别说明
> 1.model目录可能会被其他项目引用请谨慎更改并通知各方。

View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["passport-service.toml"],
importpath = "go-common/app/service/main/passport/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport/conf:go_default_library",
"//app/service/main/passport/http:go_default_library",
"//app/service/main/passport/rpc/server:go_default_library",
"//app/service/main/passport/service:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc: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,60 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/passport/conf"
"go-common/app/service/main/passport/http"
rpc "go-common/app/service/main/passport/rpc/server"
"go-common/app/service/main/passport/service"
"go-common/library/log"
xrpc "go-common/library/net/rpc"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
// init conf,log,trace,stat,perf.
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Xlog)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
// service init
svr := service.New(conf.Conf)
var rpcSvr *xrpc.Server
if conf.Conf.Switch.RPC {
rpcSvr = rpc.New(conf.Conf, svr)
}
http.Init(conf.Conf, svr)
// signal handler
log.Info("passport-service start")
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("passport-service get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("passport-service exit")
if conf.Conf.Switch.RPC {
rpcSvr.Close()
time.Sleep(time.Second * 2)
}
svr.Close()
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,112 @@
# This is a TOML document. Boom.
version = "1.0.0"
user = "nobody"
dir = "./"
perf = "0.0.0.0:7290"
family = "passport-service"
env = "qa"
[xlog]
dir = "/data/log/passport-service"
[tracer]
family = "passport-service"
proto = "unixgram"
addr = "/var/run/dapper-collect/dapper-collect.sock"
[switch]
# NOTE: if login log hbase on, default false
loginLogHBase = true
# NOTE: if offer RPC, default false
rpc = false
# NOTE: if switch.rpc = false, ignore rpcServer2 conf.
#[rpcServer2]
#[[rpcServer2.servers]]
# proto = "tcp"
# addr = "0.0.0.0:7299"
# weight = 10
#[rpcServer2.zookeeper]
# root = "/microservice/passport-service/"
# addrs = ["172.18.33.172:2181"]
# timeout = "30s"
[identify]
WhiteAccessKey = ""
WhiteMid = 0
[identify.app]
key = "e7482d29be4a95b8"
secret = "test"
[identify.memcache]
name = "go-business/identify"
proto = "tcp"
addr = "172.16.33.54:11211"
active = 5
idle = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[identify.host]
auth = "http://passport.bilibili.com"
secret = "http://open.bilibili.com"
[identify.httpClient]
key = "e7482d29be4a95b8"
secret = "test"
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"}
[hbase]
[hbase.faceApply]
master = ""
meta = ""
testRowKey = "passport-service-ping"
dialTimeout = "1s"
readTimeout = "10s"
readsTimeout = "10s"
writeTimeout = "10s"
writesTimeout = "10s"
[hbase.faceApply.zookeeper]
root = ""
addrs = ["172.18.33.131:2181","172.18.33.168:2181","172.18.33.169:2181"]
timeout = "30s"
[hbase.loginLog]
master = ""
meta = ""
testRowKey = "passport-service-ping"
dialTimeout = "1s"
readTimeout = "10s"
readsTimeout = "10s"
writeTimeout = "10s"
writesTimeout = "10s"
[hbase.loginLog.zookeeper]
root = ""
addrs = ["172.18.33.131:2181","172.18.33.168:2181","172.18.33.169:2181"]
timeout = "30s"
[hbase.pwdLog]
master = ""
meta = ""
testRowKey = "passport-service-ping"
dialTimeout = "1s"
readTimeout = "10s"
readsTimeout = "10s"
writeTimeout = "10s"
writesTimeout = "10s"
[hbase.pwdLog.zookeeper]
root = ""
addrs = ["172.18.33.131:2181","172.18.33.168:2181","172.18.33.169:2181"]
timeout = "30s"

View File

@@ -0,0 +1,39 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/service/main/passport/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/conf:go_default_library",
"//library/database/hbase.v2:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc: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,115 @@
package conf
import (
"errors"
"flag"
"go-common/library/conf"
"go-common/library/log"
"go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc"
"go-common/library/net/trace"
xtime "go-common/library/time"
"go-common/library/database/hbase.v2"
"github.com/BurntSushi/toml"
)
// Conf global variable.
var (
Conf = &Config{}
client *conf.Client
confPath string
)
// HBaseConfig ...
type HBaseConfig struct {
*hbase.Config
WriteTimeout xtime.Duration
ReadTimeout xtime.Duration
}
// Config struct of conf.
type Config struct {
// base
// log
Xlog *log.Config
// tracer
Tracer *trace.Config
// identify
Identify *verify.Config
// BM
BM *blademaster.ServerConfig
// Switch switch
Switch *Switch
// RPCServer rpc server2
RPCServer *rpc.ServerConfig
// HBase
HBase *HBase
}
// Switch switch.
type Switch struct {
LoginLogHBase bool
RPC bool
}
// HBase multi hbase.
type HBase struct {
FaceApply *HBaseConfig
LoginLog *HBaseConfig
PwdLog *HBaseConfig
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init int config
func Init() error {
if confPath != "" {
return local()
}
return remote()
}

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",
"hbase_face_test.go",
"hbase_login_log_test.go",
"row_key_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/passport/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/github.com/tsuna/gohbase/hrpc:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"hbase_face.go",
"hbase_login_log.go",
"hbase_pwd.go",
"row_key.go",
],
importpath = "go-common/app/service/main/passport/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport/conf:go_default_library",
"//app/service/main/passport/model:go_default_library",
"//library/database/hbase.v2:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/tsuna/gohbase/filter:go_default_library",
"//vendor/github.com/tsuna/gohbase/hrpc:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,50 @@
package dao
import (
"context"
"go-common/app/service/main/passport/conf"
"go-common/library/database/hbase.v2"
)
// Dao struct answer history of Dao
type Dao struct {
c *conf.Config
hbase *hbase.Client
loginLogHBase *hbase.Client
pwdLogHBase *hbase.Client
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
var loginLogHBase *hbase.Client
if c.Switch.LoginLogHBase {
loginLogHBase = hbase.NewClient(c.HBase.LoginLog.Config)
}
d = &Dao{
c: c,
hbase: hbase.NewClient(c.HBase.FaceApply.Config),
loginLogHBase: loginLogHBase,
pwdLogHBase: hbase.NewClient(c.HBase.PwdLog.Config),
}
return
}
// Close close connections.
func (d *Dao) Close() {
if d.hbase != nil {
d.hbase.Close()
}
if d.loginLogHBase != nil {
d.loginLogHBase.Close()
}
if d.pwdLogHBase != nil {
d.pwdLogHBase.Close()
}
}
// Ping ping health.
func (d *Dao) Ping(c context.Context) (err error) {
return
}

View File

@@ -0,0 +1,34 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/service/main/passport/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.passport-service")
flag.Set("conf_token", "c643a3cf59902ee7907946f12bdba10c")
flag.Set("tree_id", "7812")
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")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,166 @@
package dao
import (
"bytes"
"context"
"io"
"strconv"
"time"
"go-common/app/service/main/passport/model"
"go-common/library/log"
"github.com/tsuna/gohbase/filter"
"github.com/tsuna/gohbase/hrpc"
)
const (
_tFace = "account:user_face"
_fFaceApply = "c"
_cMid = "mid"
_cApplyTime = "at"
_cModifyTime = "mt"
_cNewFace = "nf"
_cOldFace = "of"
_cOperator = "op"
_cStatus = "s"
_maxIDLen = 10
)
var (
_tFaceB = []byte(_tFace)
_cMidB = []byte(_cMid)
_fFaceApplyB = []byte(_fFaceApply)
_cApplyTimeB = []byte(_cApplyTime)
_cModifyTimeB = []byte(_cModifyTime)
_cNewFaceB = []byte(_cNewFace)
_cOldFaceB = []byte(_cOldFace)
_cOperatorB = []byte(_cOperator)
_cStatusB = []byte(_cStatus)
)
// FaceApplies get face applies from hbase.
func (d *Dao) FaceApplies(c context.Context, mid, from, to int64, status, operator string) (res []*model.FaceApply, err error) {
midStr := strconv.FormatInt(mid, 10)
if !checkIDLen(midStr) {
log.Error("midInt64: %d, midStr: %s, len(midStr): %d, exceed max length %d", mid, midStr, len(midStr), _maxIDLen)
return
}
ctx, cancel := context.WithTimeout(c, time.Duration(d.c.HBase.FaceApply.ReadTimeout))
defer cancel()
st := rowKeyFaceApplyMts(midStr, to, _uint32Max)
if len(st) == 0 {
return
}
ed := rowKeyFaceApplyMts(midStr, from, 0)
if len(st) == 0 {
return
}
fts := filter.NewList(filter.MustPassAll)
if status != "" {
statusFt := filter.NewSingleColumnValueFilter(_fFaceApplyB, _cStatusB, filter.Equal, filter.NewBinaryComparator(filter.NewByteArrayComparable([]byte(status))), true, true)
fts.AddFilters(statusFt)
}
if operator != "" {
operatorFt := filter.NewSingleColumnValueFilter(_fFaceApplyB, _cOperatorB, filter.Equal, filter.NewBinaryComparator(filter.NewByteArrayComparable([]byte(operator))), true, true)
fts.AddFilters(operatorFt)
}
var options []func(hrpc.Call) error
if len(fts.Filters) > 0 {
options = append(options, hrpc.Filters(fts))
}
var scaner hrpc.Scanner
scaner, err = d.hbase.ScanRange(ctx, _tFaceB, st, ed, options...)
if err != nil {
log.Error("hbase.ScanRange(%s, %s, %s) error(%v)", _tFaceB, st, ed, err)
return
}
var rs []*hrpc.Result
for {
var r *hrpc.Result
r, err = scaner.Next()
if err != nil {
if err == io.EOF {
// set err nil
err = nil
break
}
return
}
rs = append(rs, r)
}
if len(rs) == 0 {
return
}
res = make([]*model.FaceApply, 0, len(rs))
for _, r := range rs {
var u *model.FaceApply
if u, err = scanFaceRecord(r.Cells); err != nil {
return
}
if u != nil {
res = append(res, u)
}
}
return
}
// rowKeyFaceApplyMts get row key for face apply using this schema:
// mid string reverse with right fill 0 +
// (int64_max - mts) string cut last 10 digit +
// (unsigned_int32_max - id) string with left fill 0.
func rowKeyFaceApplyMts(midStr string, mts, id int64) []byte {
rMid := reverseID(midStr, 10)
if len(rMid) == 0 {
return nil
}
b := bytes.Buffer{}
b.WriteString(rMid)
rMTS := diffTs(mts)
b.WriteString(rMTS)
rID := diffID(id)
b.WriteString(rID)
return b.Bytes()
}
func scanFaceRecord(cells []*hrpc.Cell) (res *model.FaceApply, err error) {
if len(cells) == 0 {
return
}
res = new(model.FaceApply)
for _, cell := range cells {
if bytes.Equal(cell.Family, _fFaceApplyB) {
switch {
case bytes.Equal(cell.Qualifier, _cMidB):
if res.Mid, err = strconv.ParseInt(string(cell.Value), 10, 64); err != nil {
log.Error("failed to parse mid from cell, strconv.ParseInt(%s, 10, 64) error(%v)", cell.Value, err)
return
}
case bytes.Equal(cell.Qualifier, _cOldFaceB):
res.OldFace = string(cell.Value)
case bytes.Equal(cell.Qualifier, _cNewFaceB):
res.NewFace = string(cell.Value)
case bytes.Equal(cell.Qualifier, _cApplyTimeB):
if res.ApplyTime, err = strconv.ParseInt(string(cell.Value), 10, 64); err != nil {
log.Error("failed to parse apply_time from cell, strconv.ParseInt(%s, 10, 64) error(%v)", cell.Value, err)
return
}
case bytes.Equal(cell.Qualifier, _cStatusB):
res.Status = string(cell.Value)
case bytes.Equal(cell.Qualifier, _cOperatorB):
res.Operator = string(cell.Value)
case bytes.Equal(cell.Qualifier, _cModifyTimeB):
res.ModifyTime = string(cell.Value)
}
}
}
return
}

View File

@@ -0,0 +1,88 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
"github.com/tsuna/gohbase/hrpc"
)
func TestDaoFaceApplies(t *testing.T) {
var (
c = context.TODO()
mid = int64(100)
from, to = int64(0), int64(_uint32Max)
status = ""
operator = ""
)
convey.Convey("FaceApplies", t, func(ctx convey.C) {
_, err := d.FaceApplies(c, mid, from, to, status, operator)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
//ctx.So(res, convey.ShouldNotBeNil)
//
//lastTs := int64(0)
//lastID := int64(0)
//for _, v := range res {
// ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
// mt, err := time.ParseInLocation(_inputFormat, v.ModifyTime, _loc)
// ctx.So(err, convey.ShouldBeNil)
//
// id, err := strconv.ParseInt(v.Operator, 10, 64)
// ctx.So(err, convey.ShouldBeNil)
//
// // check ts seq
// ts := mt.Unix()
// if lastTs > 0 {
// ctx.So(lastTs, convey.ShouldBeGreaterThanOrEqualTo, ts)
// }
//
// // check id seq when ts equal
// if lastTs == ts && lastID > 0 {
// ctx.So(lastID, convey.ShouldBeGreaterThan, id)
// }
//
// lastTs = ts
// lastID = id
// })
//}
})
})
}
func TestDaorowKeyFaceApplyMts(t *testing.T) {
var (
midStr = "123"
mts = int64(0)
id = int64(0)
)
convey.Convey("rowKeyFaceApplyMts", t, func(ctx convey.C) {
p1 := rowKeyFaceApplyMts(midStr, mts, id)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoscanFaceRecord(t *testing.T) {
var (
cells = []*hrpc.Cell{
{Family: []byte("c"), Qualifier: []byte("mid"), Value: []byte("123")},
{Family: []byte("c"), Qualifier: []byte("at"), Value: []byte("1530846373")},
{Family: []byte("c"), Qualifier: []byte("mt"), Value: []byte("1530846373")},
{Family: []byte("c"), Qualifier: []byte("nf"), Value: []byte("nf")},
{Family: []byte("c"), Qualifier: []byte("of"), Value: []byte("of")},
{Family: []byte("c"), Qualifier: []byte("op"), Value: []byte("op")},
{Family: []byte("c"), Qualifier: []byte("s"), Value: []byte("0")},
}
)
convey.Convey("scanFaceRecord", t, func(ctx convey.C) {
res, err := scanFaceRecord(cells)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,137 @@
package dao
import (
"bytes"
"context"
"encoding/binary"
"io"
"strconv"
"time"
"go-common/app/service/main/passport/model"
"go-common/library/log"
"github.com/tsuna/gohbase/hrpc"
)
const (
_tLoginLog = "ugc:AsoLoginLog"
_fLoginLogInfo = "f"
_cLoginLogMid = "mid"
_cLoginLogTs = "ts"
_cLoginLogLoginIP = "ip"
_cLoginLogType = "t"
_cLoginLogServer = "s"
)
var (
_tLoginLogB = []byte(_tLoginLog)
_fLoginLogInfoB = []byte(_fLoginLogInfo)
_cLoginLogMidB = []byte(_cLoginLogMid)
_cLoginLogTsB = []byte(_cLoginLogTs)
_cLoginLogLoginIPB = []byte(_cLoginLogLoginIP)
_cLoginLogTypeB = []byte(_cLoginLogType)
_cLoginLogServerB = []byte(_cLoginLogServer)
)
// LoginLogs get last limit login logs.
func (d *Dao) LoginLogs(c context.Context, mid int64, limit int) (res []*model.LoginLog, err error) {
ctx, cancel := context.WithTimeout(c, time.Duration(d.c.HBase.LoginLog.ReadTimeout))
defer cancel()
st := rowKeyLoginLog(mid, _int64Max)
ed := rowKeyLoginLog(mid, 0)
var scaner hrpc.Scanner
scaner, err = d.loginLogHBase.ScanRange(ctx, _tLoginLogB, st, ed)
if err != nil {
log.Error("hbase.ScanRange(%s, %s, %s) error(%v)", _tLoginLogB, st, ed, err)
return
}
res = make([]*model.LoginLog, 0)
for ; limit > 0; limit-- {
var u *model.LoginLog
var r *hrpc.Result
r, err = scaner.Next()
if err != nil {
if err == io.EOF {
err = nil
break
}
return
}
if u, err = scanLoginLog(r.Cells); err != nil {
scaner.Close()
return
}
if u != nil {
res = append(res, u)
}
}
if err := scaner.Close(); err != nil {
log.Error("hbase.Scanner.Close error(%v)", err)
}
return
}
// rowKeyLoginLog generate row key of login log.
func rowKeyLoginLog(mid, ts int64) (res []byte) {
buf := bytes.Buffer{}
b := make([]byte, 8)
// reverse mid bytes
binary.BigEndian.PutUint64(b, uint64(mid))
reverse(b)
buf.Write(b)
// (int64_max - ts) bytes
binary.BigEndian.PutUint64(b, uint64(_int64Max-ts))
buf.Write(b)
res = buf.Bytes()
return
}
func reverse(b []byte) {
l := len(b)
for i := 0; i < l/2; i++ {
t := b[i]
b[i] = b[l-1-i]
b[l-1-i] = t
}
}
func scanLoginLog(cells []*hrpc.Cell) (res *model.LoginLog, err error) {
if len(cells) == 0 {
return
}
res = new(model.LoginLog)
for _, cell := range cells {
if bytes.Equal(cell.Family, _fLoginLogInfoB) {
switch {
case bytes.Equal(cell.Qualifier, _cLoginLogMidB):
if res.Mid, err = strconv.ParseInt(string(cell.Value), 10, 64); err != nil {
log.Error("failed to parse mid from cell, strconv.ParseInt(%s, 10, 64) error(%v)", cell.Value, err)
return
}
case bytes.Equal(cell.Qualifier, _cLoginLogTsB):
if res.Timestamp, err = strconv.ParseInt(string(cell.Value), 10, 64); err != nil {
log.Error("failed to parse timestamp from cell, strconv.ParseInt(%s, 10, 64) error(%v)", cell.Value, err)
return
}
case bytes.Equal(cell.Qualifier, _cLoginLogLoginIPB):
if res.LoginIP, err = strconv.ParseInt(string(cell.Value), 10, 64); err != nil {
log.Error("failed to parse loginip from cell, strconv.ParseInt(%s, 10, 64) error(%v)", cell.Value, err)
return
}
case bytes.Equal(cell.Qualifier, _cLoginLogTypeB):
if res.Type, err = strconv.ParseInt(string(cell.Value), 10, 64); err != nil {
log.Error("failed to parse type from cell, strconv.ParseInt(%s, 10, 64) error(%v)", cell.Value, err)
return
}
case bytes.Equal(cell.Qualifier, _cLoginLogServerB):
res.Server = string(cell.Value)
}
}
}
return
}

View File

@@ -0,0 +1,67 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
"github.com/tsuna/gohbase/hrpc"
)
func TestDaoLoginLogs(t *testing.T) {
var (
c = context.TODO()
mid = int64(123)
limit = int(1)
)
convey.Convey("LoginLogs", t, func(ctx convey.C) {
res, err := d.LoginLogs(c, mid, limit)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaorowKeyLoginLog(t *testing.T) {
var (
mid = int64(123)
ts = int64(1530846373)
)
convey.Convey("rowKeyLoginLog", t, func(ctx convey.C) {
res := rowKeyLoginLog(mid, ts)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaoreverse(t *testing.T) {
var (
b = []byte("123")
)
convey.Convey("reverse", t, func(ctx convey.C) {
reverse(b)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestDaoscanLoginLog(t *testing.T) {
var (
cells = []*hrpc.Cell{
{Family: []byte("f"), Qualifier: []byte("mid"), Value: []byte("123")},
{Family: []byte("f"), Qualifier: []byte("ts"), Value: []byte("1530846373")},
{Family: []byte("f"), Qualifier: []byte("ip"), Value: []byte("2886731194")},
{Family: []byte("f"), Qualifier: []byte("t"), Value: []byte("0")},
{Family: []byte("f"), Qualifier: []byte("s"), Value: []byte("s")},
}
)
convey.Convey("scanLoginLog", t, func(ctx convey.C) {
res, err := scanLoginLog(cells)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,103 @@
package dao
import (
"bytes"
"context"
"encoding/binary"
"io"
"time"
"go-common/app/service/main/passport/model"
"go-common/library/log"
"github.com/tsuna/gohbase/hrpc"
)
const (
_tPwdLog = "ugc:PwdLog"
_fPwdLog = "pwdlog"
_cPwdLogOldPwd = "old_pwd"
_cPwdLogOldSalt = "old_salt"
)
var (
_tPwdLogB = []byte(_tPwdLog)
_fPwdLogB = []byte(_fPwdLog)
_cPwdLogOldPwdB = []byte(_cPwdLogOldPwd)
_cPwdLogOldSaltB = []byte(_cPwdLogOldSalt)
)
// HistoryPwds get history pwd
func (d *Dao) HistoryPwds(c context.Context, mid int64) (res []*model.HistoryPwd, err error) {
ctx, cancel := context.WithTimeout(c, time.Duration(d.c.HBase.LoginLog.ReadTimeout))
defer cancel()
st := RowKeyPwdLog(mid, _int64Max)
ed := RowKeyPwdLog(mid, 0)
var scaner hrpc.Scanner
scaner, err = d.pwdLogHBase.ScanRange(ctx, _tPwdLogB, st, ed)
if err != nil {
log.Error("hbase.ScanRange(%s, %s, %s) error(%v)", _tPwdLogB, st, ed, err)
return
}
res = make([]*model.HistoryPwd, 0)
for {
var pwd *model.HistoryPwd
var r *hrpc.Result
r, err = scaner.Next()
if err != nil {
if err == io.EOF {
err = nil
break
}
return
}
if pwd, err = scanPwdLog(r.Cells); err != nil {
scaner.Close()
return
}
if pwd != nil {
res = append(res, pwd)
}
}
if err := scaner.Close(); err != nil {
log.Error("hbase.Scanner.Close error(%v)", err)
}
return
}
// RowKeyPwdLog generate row key of pwd log.
func RowKeyPwdLog(mid, ts int64) (res []byte) {
buf := bytes.Buffer{}
b := make([]byte, 8)
// reverse mid bytes
binary.BigEndian.PutUint64(b, uint64(mid))
reverse(b)
buf.Write(b)
// (int64_max - ts) bytes
binary.BigEndian.PutUint64(b, uint64(_int64Max-ts))
buf.Write(b)
res = buf.Bytes()
return
}
func scanPwdLog(cells []*hrpc.Cell) (res *model.HistoryPwd, err error) {
if len(cells) == 0 {
return
}
res = new(model.HistoryPwd)
for _, cell := range cells {
if bytes.Equal(cell.Family, _fPwdLogB) {
switch {
case bytes.Equal(cell.Qualifier, _cPwdLogOldPwdB):
res.OldPwd = string(cell.Value)
case bytes.Equal(cell.Qualifier, _cPwdLogOldSaltB):
res.OldSalt = string(cell.Value)
}
}
}
return
}

View File

@@ -0,0 +1,60 @@
package dao
import (
"strconv"
"strings"
"go-common/library/log"
)
const (
_int64Max = 0x7fffffffffffffff
_uint32Max = 0xffffffff
)
// reverseID reverse a digital number represented in string,
// if len(id) < len, fill 0 on the right of reverse id to make reverse id len 10,
// if len(id) > len, will return empty string.
func reverseID(id string, l int) string {
if len(id) > l {
log.Error("len(%s) is %d, greater than the given l %d", id, len(id), l)
return ""
}
// reverse id string
runes := []rune(id)
for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
runes[from], runes[to] = runes[to], runes[from]
}
rid := string(runes)
if len(id) == l {
return rid
}
// fill with 0 on rid's right
rid += strings.Repeat("0", l-len(id))
return rid
}
func checkIDLen(id string) bool {
return len(id) <= _maxIDLen
}
// diffTs return the last 10 digit of (int64_max - ts).
func diffTs(ts int64) string {
i := _int64Max - ts
s := strconv.FormatInt(i, 10)
// during ts 0 - (int64 - now), cut the [9,19) part of s as result
return s[9:19]
}
// diffID return the (unsigned_int32_max - id) convert to string in base 10.
// if len of the string < 10, fill 0 on the left to make len(res) equal to 10.
func diffID(id int64) string {
i := _uint32Max - id
s := strconv.FormatInt(i, 10)
if len(s) == 10 {
return s
}
return strings.Repeat("0", 10-len(s)) + s
}

View File

@@ -0,0 +1,56 @@
package dao
import (
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoreverseID(t *testing.T) {
var (
id = "123"
l = int(3)
)
convey.Convey("reverseID", t, func(ctx convey.C) {
p1 := reverseID(id, l)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaocheckIDLen(t *testing.T) {
var (
id = "123"
)
convey.Convey("checkIDLen", t, func(ctx convey.C) {
p1 := checkIDLen(id)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaodiffTs(t *testing.T) {
var (
ts = int64(0)
)
convey.Convey("diffTs", t, func(ctx convey.C) {
p1 := diffTs(ts)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaodiffID(t *testing.T) {
var (
id = int64(0)
)
convey.Convey("diffID", t, func(ctx convey.C) {
p1 := diffID(id)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"face.go",
"http.go",
"login_log.go",
"pwd.go",
],
importpath = "go-common/app/service/main/passport/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport/conf:go_default_library",
"//app/service/main/passport/model:go_default_library",
"//app/service/main/passport/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",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,42 @@
package http
import (
"strconv"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func face(c *bm.Context) {
params := c.Request.Form
midStr := params.Get("mid")
if midStr == "" {
c.JSON(nil, ecode.RequestErr)
return
}
fromStr, toStr := params.Get("from"), params.Get("to")
if fromStr == "" || toStr == "" {
c.JSON(nil, ecode.RequestErr)
return
}
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if mid < 0 {
c.JSON(nil, ecode.RequestErr)
return
}
from, err := strconv.ParseInt(fromStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
to, err := strconv.ParseInt(toStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(passportSvc.FaceApplies(c, mid, from, to, params.Get("status"), params.Get("operator")))
}

View File

@@ -0,0 +1,56 @@
package http
import (
"net/http"
"go-common/app/service/main/passport/conf"
"go-common/app/service/main/passport/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
passportSvc *service.Service
vfy *verify.Verify
)
// Init fot init open service
func Init(c *conf.Config, s *service.Service) {
passportSvc = s
vfy = verify.New(c.Identify)
// engine
engIn := bm.DefaultServer(c.BM)
innerRouter(c, engIn)
// init inner server
if err := engIn.Start(); err != nil {
log.Error("bm.Start error(%v)", err)
panic(err)
}
}
func innerRouter(c *conf.Config, e *bm.Engine) {
e.Ping(ping)
e.Register(register)
group := e.Group("/x/internal/passport", vfy.Verify)
{
group.GET("/records/face", face)
if c.Switch.LoginLogHBase {
group.GET("records/loginlog", loginLog)
}
group.POST("/history/pwd/check", historyPwdCheck)
}
}
// ping check server ok.
func ping(c *bm.Context) {
if err := passportSvc.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
// register support discovery.
func register(c *bm.Context) {
c.JSON(map[string]struct{}{}, nil)
}

View File

@@ -0,0 +1,40 @@
package http
import (
"strconv"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
const (
_defaultLimit = 1
)
func loginLog(c *bm.Context) {
params := c.Request.Form
midStr := params.Get("mid")
if midStr == "" {
c.JSON(nil, ecode.RequestErr)
return
}
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
if mid < 0 {
c.JSON(nil, ecode.RequestErr)
return
}
limit := _defaultLimit
limitStr := params.Get("limit")
if limitStr != "" {
if limit, err = strconv.Atoi(limitStr); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
}
c.JSON(passportSvc.FormattedLoginLogs(c, mid, limit))
}

View File

@@ -0,0 +1,17 @@
package http
import (
"go-common/app/service/main/passport/model"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func historyPwdCheck(c *bm.Context) {
param := new(model.HistoryPwdCheckParam)
c.Bind(param)
if param.Mid <= 0 || param.Pwd == "" {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(passportSvc.HistoryPwdCheck(c, param))
}

View File

@@ -0,0 +1,33 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"face.go",
"login_log.go",
"pwd.go",
"rpc.go",
],
importpath = "go-common/app/service/main/passport/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,13 @@
package model
// FaceApply face record.
type FaceApply struct {
ID int64 `json:"-"`
Mid int64 `json:"mid"`
OldFace string `json:"old_face"`
NewFace string `json:"new_face"`
ApplyTime int64 `json:"apply_time"`
Status string `json:"status"`
Operator string `json:"operator"`
ModifyTime string `json:"modify_time"`
}

View File

@@ -0,0 +1,43 @@
package model
import (
"fmt"
)
// LoginLog login log.
type LoginLog struct {
Mid int64 `json:"mid"`
Timestamp int64 `json:"timestamp"`
LoginIP int64 `json:"loginip"`
Type int64 `json:"type"`
Server string `json:"server"`
}
// LoginLogResp login log.
type LoginLogResp struct {
Mid int64 `json:"mid"`
Timestamp int64 `json:"timestamp"`
LoginIP string `json:"loginip"`
Type int64 `json:"type"`
Server string `json:"server"`
}
// Format format login log to login log resp.
func Format(l *LoginLog) *LoginLogResp {
if l == nil {
return nil
}
return &LoginLogResp{
Mid: l.Mid,
Timestamp: l.Timestamp,
LoginIP: InetNtoA(l.LoginIP),
Type: l.Type,
Server: l.Server,
}
}
// InetNtoA .
func InetNtoA(ip int64) string {
return fmt.Sprintf("%d.%d.%d.%d",
byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))
}

View File

@@ -0,0 +1,13 @@
package model
// HistoryPwdCheckParam history pwd check param
type HistoryPwdCheckParam struct {
Mid int64 `form:"mid"`
Pwd string `form:"pwd"`
}
// HistoryPwd history pwd
type HistoryPwd struct {
OldPwd string
OldSalt string
}

View File

@@ -0,0 +1,7 @@
package model
// ArgLoginLogs arg for RPC.LoginLogs.
type ArgLoginLogs struct {
Mid int64
Limit int
}

View File

@@ -0,0 +1,42 @@
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/passport/model:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["client.go"],
importpath = "go-common/app/service/main/passport/rpc/client",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport/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,35 @@
package client
import (
"context"
"go-common/app/service/main/passport/model"
"go-common/library/net/rpc"
)
const (
_appid = "passport.service"
)
// Client2 struct
type Client2 struct {
client *rpc.Client2
}
// New Client2 init
func New(c *rpc.ClientConfig) (s *Client2) {
s = &Client2{}
s.client = rpc.NewDiscoveryCli(_appid, c)
return
}
const (
_loginLogs = "RPC.LoginLogs"
)
// LoginLogs get the latest limit login logs.
func (c2 *Client2) LoginLogs(c context.Context, arg *model.ArgLoginLogs) (res []*model.LoginLog, err error) {
res = make([]*model.LoginLog, 0)
err = c2.client.Call(c, _loginLogs, arg, &res)
return
}

View File

@@ -0,0 +1,40 @@
package client
import (
"context"
"encoding/json"
"sync"
"testing"
"time"
"go-common/app/service/main/passport/model"
)
var (
once sync.Once
passportSvc *Client2
)
func startRPCServer() {
passportSvc = New(nil)
time.Sleep(time.Second * 2)
}
func TestService2_LoginLogs(t *testing.T) {
once.Do(startRPCServer)
arg := &model.ArgLoginLogs{
Mid: 88888970,
}
if res, err := passportSvc.LoginLogs(context.TODO(), arg); err != nil {
t.Errorf("failed to call rpc, passportSvc.LoginLogs(%v) error(%v)", arg, err)
t.FailNow()
} else if len(res) == 0 {
t.Errorf("res is incorrect, expected res length > 0 but got 0")
t.FailNow()
} else {
for i, v := range res {
str, _ := json.Marshal(v)
t.Logf("res[%d]: %s", i, str)
}
}
}

View File

@@ -0,0 +1,51 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["rpc_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/passport/conf:go_default_library",
"//app/service/main/passport/model:go_default_library",
"//app/service/main/passport/service:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["rpc.go"],
importpath = "go-common/app/service/main/passport/rpc/server",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport/conf:go_default_library",
"//app/service/main/passport/model:go_default_library",
"//app/service/main/passport/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,37 @@
package server
import (
"go-common/app/service/main/passport/conf"
"go-common/app/service/main/passport/model"
"go-common/app/service/main/passport/service"
"go-common/library/net/rpc"
"go-common/library/net/rpc/context"
)
// RPC server struct
type RPC struct {
s *service.Service
}
// New new 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
}
// LoginLogs get the latest limit login logs.
func (r *RPC) LoginLogs(c context.Context, arg *model.ArgLoginLogs, res *[]*model.LoginLog) (err error) {
if ms, err := r.s.LoginLogs(c, arg.Mid, arg.Limit); err == nil {
*res = ms
}
return
}

View File

@@ -0,0 +1,37 @@
package server
import (
"context"
"testing"
"time"
"go-common/app/service/main/passport/conf"
"go-common/app/service/main/passport/model"
"go-common/app/service/main/passport/service"
"go-common/library/log"
"go-common/library/net/rpc"
)
const (
_rpcLoginLogs = "RPC.LoginLogs"
)
func TestRPC_LoginLogs(t *testing.T) {
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Xlog)
s := service.New(conf.Conf)
r := New(conf.Conf, s)
defer r.Close()
c2 := rpc.NewDiscoveryCli("passport.service", nil)
time.Sleep(time.Second * 2)
ms := make([]*model.LoginLog, 0)
if err := c2.Call(context.TODO(), _rpcLoginLogs, &model.ArgLoginLogs{
Mid: 88888970,
}, &ms); err != nil {
t.Errorf("failed to call %s, error(%v)", _rpcLoginLogs, err)
t.FailNow()
}
}

View File

@@ -0,0 +1,54 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"login_log_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/passport/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"face.go",
"login_log.go",
"pwd.go",
"service.go",
],
importpath = "go-common/app/service/main/passport/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport/conf:go_default_library",
"//app/service/main/passport/dao:go_default_library",
"//app/service/main/passport/model: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,25 @@
package service
import (
"context"
"go-common/app/service/main/passport/model"
)
var (
_emptyFaceRecords = make([]*model.FaceApply, 0)
)
// FaceApplies get face applies range from and to.
func (s *Service) FaceApplies(c context.Context, mid int64, from, to int64, status, operator string) (res []*model.FaceApply, err error) {
if from > to {
return _emptyFaceRecords, nil
}
if res, err = s.d.FaceApplies(c, mid, from, to, status, operator); err != nil {
return
}
if len(res) == 0 {
res = _emptyFaceRecords
}
return
}

View File

@@ -0,0 +1,54 @@
package service
import (
"context"
"go-common/app/service/main/passport/model"
)
const (
_maxLimit = 1000
)
var (
_emptyLoginLogs = make([]*model.LoginLog, 0)
_emptyLoginLogResps = make([]*model.LoginLogResp, 0)
)
// FormattedLoginLogs get the latest limit login logs with formatting IP int to IP string.
func (s *Service) FormattedLoginLogs(c context.Context, mid int64, limit int) (res []*model.LoginLogResp, err error) {
ls, err := s.LoginLogs(c, mid, limit)
if err != nil {
return
}
if len(ls) == 0 {
res = _emptyLoginLogResps
return
}
res = make([]*model.LoginLogResp, 0)
for _, v := range ls {
res = append(res, model.Format(v))
}
return
}
// LoginLogs get the latest limit login logs.
// If the limit is less than or equal to 0, a empty result will be returned,
// else if the limit is greater than then max limit, then the limit will be set to max limit.
func (s *Service) LoginLogs(c context.Context, mid int64, limit int) (res []*model.LoginLog, err error) {
if mid < 0 || limit <= 0 {
res = _emptyLoginLogs
return
}
if limit > _maxLimit {
limit = _maxLimit
}
if res, err = s.d.LoginLogs(c, mid, limit); err != nil {
return
}
if len(res) == 0 {
res = _emptyLoginLogs
}
return
}

View File

@@ -0,0 +1,43 @@
package service
import (
"context"
"encoding/json"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_LoginLogs(t *testing.T) {
once.Do(startService)
Convey("get login logs", t, func() {
mid := int64(88888970)
res, err := s.LoginLogs(context.Background(), mid, _maxLimit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
str, _ := json.Marshal(res)
t.Logf("res: %s", str)
for _, m := range res {
str, _ := json.Marshal(m)
t.Logf("m: %s", str)
}
})
}
func TestService_FormattedLoginLogs(t *testing.T) {
once.Do(startService)
Convey("get formatted login logs", t, func() {
mid := int64(88888970)
res, err := s.FormattedLoginLogs(context.Background(), mid, _maxLimit)
So(err, ShouldBeNil)
So(len(res), ShouldBeGreaterThan, 0)
str, _ := json.Marshal(res)
t.Logf("res: %s", str)
for _, m := range res {
str, _ := json.Marshal(m)
t.Logf("m: %s", str)
}
})
}

View File

@@ -0,0 +1,46 @@
package service
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"strconv"
"strings"
"go-common/app/service/main/passport/model"
)
// HistoryPwdCheck history pwd check
func (s *Service) HistoryPwdCheck(c context.Context, param *model.HistoryPwdCheckParam) (result string, err error) {
var matchResult = make(map[string]int64, 3)
var historyPwds []*model.HistoryPwd
if historyPwds, err = s.d.HistoryPwds(c, param.Mid); err != nil {
return
}
pwds := strings.Split(param.Pwd, ",")
for _, history := range historyPwds {
for _, pwd := range pwds {
saltPwd := getSaltPwd(pwd, history.OldSalt)
if saltPwd == history.OldPwd {
matchResult[pwd] = 1
}
}
}
for _, pwd := range pwds {
result = result + "," + strconv.FormatInt(matchResult[pwd], 10)
}
if len(result) > 0 {
result = result[1:]
}
return
}
func getSaltPwd(pwd string, salt string) string {
return md5Hex(fmt.Sprintf("%s>>BiLiSaLt<<%s", pwd, salt))
}
func md5Hex(s string) string {
sum := md5.Sum([]byte(s))
return hex.EncodeToString(sum[:])
}

View File

@@ -0,0 +1,37 @@
package service
import (
"context"
"go-common/app/service/main/passport/conf"
"go-common/app/service/main/passport/dao"
)
// Service struct of service.
type Service struct {
d *dao.Dao
// conf
c *conf.Config
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
d: dao.New(c),
}
return
}
// Close dao.
func (s *Service) Close() {
s.d.Close()
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
if err = s.d.Ping(c); err != nil {
return
}
return
}

View File

@@ -0,0 +1,19 @@
package service
import (
"go-common/app/service/main/passport/conf"
"sync"
)
var (
once sync.Once
s *Service
)
func startService() {
if err := conf.Init(); err != nil {
panic(err)
}
// service init
s = New(conf.Conf)
}