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,5 @@
### v1.0.1
1. fix expires
### v1.0.0
1. init

View File

@@ -0,0 +1,7 @@
# Owner
wanghuan01
wutao
# Author
# Reviewer

View File

@@ -0,0 +1,11 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wanghuan01
- wutao
labels:
- job
- job/main/passport-sns
- main
options:
no_parent_owners: true

View File

@@ -0,0 +1,14 @@
# passport-sns
# 项目简介
1.
# 编译环境
# 依赖包
# 编译执行

View File

@@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["passport-sns-job.toml"],
importpath = "go-common/app/job/main/passport-sns/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/passport-sns/conf:go_default_library",
"//app/job/main/passport-sns/http:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,41 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/job/main/passport-sns/conf"
"go-common/app/job/main/passport-sns/http"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
log.Init(conf.Conf.Xlog)
defer log.Close()
log.Info("passport-sns-job start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
http.Init(conf.Conf)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("passport-sns-job get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("passport-sns-job exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,89 @@
[db.aso]
addr = "172.16.33.205:3306"
dsn = "aso:hA0DAnENNFz78kYB@tcp(172.16.33.205:3306)/aso?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
queryTimeout = "1s"
execTimeout = "2s"
tranTimeout = "2s"
[db.aso.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.sns]
addr = "127.0.0.1:3306"
dsn = "root:root@tcp(127.0.0.1:3306)/passport_sns?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
queryTimeout = "1s"
execTimeout = "2s"
tranTimeout = "2s"
[db.sns.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[memcache]
name = "passport-sns-service"
proto = "tcp"
addr = "172.22.33.137:11219"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "24h"
[databus.snsLogSub]
key = "4ba46ba31f9a44ef"
secret = "e4c5a7fce28695209e6b4f0af8cf91c5"
group = "PassportSnsLog-MainAccount-S"
topic = "PassportSnsLog-T"
action = "sub"
offset = "old"
buffer = 2048
name = "passport-sns/databus"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 2
active = 10
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databus.asoBinLogSub]
key = "4ba46ba31f9a44ef"
secret = "e4c5a7fce28695209e6b4f0af8cf91c5"
group = "PassportUserBinlog-MainAccount-SNS-S"
topic = "PassportUserBinlog-T"
action = "sub"
offset = "old"
buffer = 2048
name = "passport-user/databus"
proto = "tcp"
addr = "172.22.33.174:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[databusUtil]
size = 100
num = 8
ticker = "1s"
chan = 100
[syncConf]
incSwitch = false
fullSwitch = true
checkSwitch = true
chanNum = 200
chanSize = 10240
checkTicker = "1h"

View File

@@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/job/main/passport-sns/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//library/queue/databus/databusutil: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,123 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"go-common/library/queue/databus/databusutil"
xtime "go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
// Conf conf.
Conf = &Config{}
client *conf.Client
)
// Config config.
type Config struct {
// log
Xlog *log.Config
// Tracer tracer
Tracer *trace.Config
// http
BM *bm.ServerConfig
// DB
DB *DB
Memcache *Memcache
//Databus databus
DataBus *DataBus
// DataUtil config
DatabusUtil *databusutil.Config
// SyncConf
SyncConf *SyncConf
}
// DB db config
type DB struct {
Aso *sql.Config
Sns *sql.Config
}
// Memcache memcache
type Memcache struct {
*memcache.Config
Expire xtime.Duration
}
// DataBus databus.
type DataBus struct {
SnsLogSub *databus.Config
AsoBinLogSub *databus.Config
}
// SyncConf sync conf
type SyncConf struct {
IncSwitch bool
FullSwitch bool
CheckSwitch bool
ChanNum int
ChanSize int
CheckTicker xtime.Duration
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init config.
func Init() (err error) {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf = &Config{}
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,62 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"aso_test.go",
"dao_test.go",
"mc_test.go",
"qq_test.go",
"sns_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/job/main/passport-sns/conf:go_default_library",
"//app/job/main/passport-sns/model:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"aso.go",
"dao.go",
"mc.go",
"qq.go",
"sns.go",
],
importpath = "go-common/app/job/main/passport-sns/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/passport-sns/conf:go_default_library",
"//app/job/main/passport-sns/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,67 @@
package dao
import (
"context"
"database/sql"
"go-common/app/job/main/passport-sns/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_addSnsLogSQL = "INSERT INTO sns_log (mid,openid,unionid,appid,platform,operator,operate,description) VALUES(?,?,?,?,?,?,?,?)"
_getAsoAccountSnsAllSQL = "SELECT mid,sina_uid,sina_access_token,sina_access_expires,qq_openid,qq_access_token,qq_access_expires FROM aso_account_sns WHERE mid > ? order by mid limit 20000"
_getAsoAccountSnsSQL = "SELECT mid,sina_uid,sina_access_token,sina_access_expires,qq_openid,qq_access_token,qq_access_expires FROM aso_account_sns WHERE (qq_openid != '' or sina_uid != 0) and mid > ? order by mid limit 20000"
)
// AddSnsLog add sns log.
func (d *Dao) AddSnsLog(c context.Context, a *model.SnsLog) (affected int64, err error) {
var res sql.Result
if res, err = d.snsDB.Exec(c, _addSnsLogSQL, a.Mid, a.OpenID, a.UnionID, a.AppID, a.Platform, a.Operator, a.Operate, a.Description); err != nil {
log.Error("AddSnsLog(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// AsoAccountSnsAll get account sns
func (d *Dao) AsoAccountSnsAll(c context.Context, start int64) (res []*model.AsoAccountSns, err error) {
var rows *xsql.Rows
if rows, err = d.asoDB.Query(c, _getAsoAccountSnsAllSQL, start); err != nil {
log.Error("fail to get AsoAccountSns, dao.asoDB.Query() error(%+v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.AsoAccountSns)
if err = rows.Scan(&r.Mid, &r.SinaUID, &r.SinaAccessToken, &r.SinaAccessExpires, &r.QQOpenid, &r.QQAccessToken, &r.QQAccessExpires); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
// AsoAccountSns get account sns by id.
func (d *Dao) AsoAccountSns(c context.Context, start int64) (res []*model.AsoAccountSns, err error) {
var rows *xsql.Rows
if rows, err = d.asoDB.Query(c, _getAsoAccountSnsSQL, start); err != nil {
log.Error("fail to get AsoAccountSns, dao.asoDB.Query() error(%+v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.AsoAccountSns)
if err = rows.Scan(&r.Mid, &r.SinaUID, &r.SinaAccessToken, &r.SinaAccessExpires, &r.QQOpenid, &r.QQAccessToken, &r.QQAccessExpires); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
return
}

View File

@@ -0,0 +1,70 @@
package dao
import (
"context"
"database/sql"
"database/sql/driver"
"reflect"
"testing"
"go-common/app/job/main/passport-sns/model"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
func TestDao_AddSnsLog(t *testing.T) {
convey.Convey("AddSnsLog", t, func(ctx convey.C) {
var (
c = context.Background()
a = &model.SnsLog{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(d.asoDB), "Exec", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.AddSnsLog(c, a)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
ctx.Convey("Then affected should not be nil.", func(ctx convey.C) {
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_AsoAccountSns(t *testing.T) {
convey.Convey("AsoAccountSns", t, func(ctx convey.C) {
var (
c = context.Background()
start = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.AsoAccountSns(c, start)
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 TestDao_AsoAccountSnsAll(t *testing.T) {
convey.Convey("AsoAccountSnsAll", t, func(ctx convey.C) {
var (
c = context.Background()
start = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.AsoAccountSnsAll(c, start)
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,54 @@
package dao
import (
"context"
"time"
"go-common/app/job/main/passport-sns/conf"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
// Dao dao
type Dao struct {
c *conf.Config
asoDB *xsql.DB
snsDB *xsql.DB
mc *memcache.Pool
mcExpire int32
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
asoDB: xsql.NewMySQL(c.DB.Aso),
snsDB: xsql.NewMySQL(c.DB.Sns),
mc: memcache.NewPool(c.Memcache.Config),
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
}
return
}
// Close close the resource.
func (d *Dao) Close() (err error) {
if err = d.asoDB.Close(); err != nil {
log.Error("srv.asoDB.Close() error(%v)", err)
}
if err = d.snsDB.Close(); err != nil {
log.Error("srv.snsDB.Close() error(%v)", err)
}
return
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}
// BeginSnsTran begin sns transcation.
func (d *Dao) BeginSnsTran(c context.Context) (tx *sql.Tx, err error) {
return d.snsDB.Begin(c)
}

View File

@@ -0,0 +1,68 @@
package dao
import (
"context"
"flag"
"os"
"reflect"
"testing"
"go-common/app/job/main/passport-sns/conf"
"go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.passport.passport-sns-job")
flag.Set("conf_token", "5aa702b77df8a25d5af539aea08b2d03")
flag.Set("tree_id", "80868")
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/passport-sns-job.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func TestDaoPing(t *testing.T) {
var c = context.Background()
convey.Convey("Ping", t, func(ctx convey.C) {
err := d.Ping(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoClose(t *testing.T) {
convey.Convey("Close", t, func(ctx convey.C) {
monkey.PatchInstanceMethod(reflect.TypeOf(d.asoDB), "Close", func(_ *sql.DB) error {
return nil
})
monkey.PatchInstanceMethod(reflect.TypeOf(d.snsDB), "Close", func(_ *sql.DB) error {
return nil
})
defer monkey.UnpatchAll()
var err error
d.Close()
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,58 @@
package dao
import (
"context"
"fmt"
"go-common/app/job/main/passport-sns/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
func snsKey(platform string, mid int64) string {
return fmt.Sprintf("sns_%s_%d", platform, mid)
}
// SetSnsCache set sns to cache
func (d *Dao) SetSnsCache(c context.Context, mid int64, platform string, sns *model.SnsProto) (err error) {
key := snsKey(platform, mid)
conn := d.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Object: sns, Flags: memcache.FlagProtobuf, Expiration: d.mcExpire}
if err = conn.Set(item); err != nil {
log.Error("fail to set sns to mc, key(%s) expire(%d) error(%+v)", key, d.mcExpire, err)
}
return
}
// DelSnsCache del sns cache
func (d *Dao) DelSnsCache(c context.Context, mid int64, platform string) (err error) {
key := snsKey(platform, mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("fail to del sns cache, key(%s) error(%+v)", key, err)
}
return
}
// GetUnionIDCache .
func (d *Dao) GetUnionIDCache(c context.Context, key string) (v string, err error) {
conn := d.mc.Get(c)
r, err := conn.Get(key)
conn.Close()
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("GetUnionIDCache, key(%s) error(%+v)", key, err)
return
}
v = string(r.Value)
return
}

View File

@@ -0,0 +1,74 @@
package dao
import (
"context"
"testing"
"go-common/app/job/main/passport-sns/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDao_snsKey(t *testing.T) {
convey.Convey("snsKey", t, func(ctx convey.C) {
var (
platform = model.PlatformQQStr
mid = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res := snsKey(platform, mid)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_SetSnsCache(t *testing.T) {
convey.Convey("SetSnsCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQStr
qq = &model.SnsProto{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SetSnsCache(c, mid, platform, qq)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDao_DelSnsCache(t *testing.T) {
convey.Convey("DelSnsCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQStr
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.DelSnsCache(c, mid, platform)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDao_GetUnionIDCache(t *testing.T) {
convey.Convey("GetUnionIDCache", t, func(ctx convey.C) {
var (
c = context.Background()
key = "test"
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.GetUnionIDCache(c, key)
ctx.Convey("Then err should be nil.res should be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldBeEmpty)
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,63 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"go-common/app/job/main/passport-sns/model"
"go-common/library/log"
)
const (
_qqGetUnionidUrl = "https://graph.qq.com/oauth2.0/get_unionid"
_respCodeSuccess = 0
_respCodeInvalidOpenid = 100050
_respCodeInvalidOpenidLength = 100058
)
// QQUnionID .
func (d *Dao) QQUnionID(c context.Context, openID string) (unionID string, err error) {
var (
res *http.Response
bs []byte
params = url.Values{}
)
params.Set("client_id", model.OldAppID)
params.Set("openid", openID)
if res, err = http.Get(_qqGetUnionidUrl + "?" + params.Encode()); err != nil {
log.Error("d.QQUnionID error(%+v) openID(%s)", err, openID)
return "", err
}
defer res.Body.Close()
if bs, err = ioutil.ReadAll(res.Body); err != nil {
log.Error("ioutil.ReadAll() error(%+v) openID(%s)", err, openID)
return "", err
}
respStr := string(bs)
if strings.HasPrefix(respStr, "callback") {
start := strings.Index(respStr, "{")
end := strings.Index(respStr, "}")
respStr = respStr[start : end+1]
}
unionRes := new(model.QQUnionIDResp)
if err = json.Unmarshal([]byte(respStr), unionRes); err != nil {
log.Error("json.Unmarshal() error(%+v) respStr(%s) openID(%s)", err, respStr, openID)
return "", err
}
if unionRes.Code == _respCodeSuccess && unionRes.UnionID != "" {
return unionRes.UnionID, nil
}
log.Error("request qq get_unionid failed with code(%d) desc(%s) openID(%s)", unionRes.Code, unionRes.Description, openID)
if unionRes.Code == _respCodeInvalidOpenidLength || unionRes.Code == _respCodeInvalidOpenid {
return "", nil
}
return "", fmt.Errorf("request qq get_unionid failed with code(%d) desc(%s) openID(%s)", unionRes.Code, unionRes.Description, openID)
}

View File

@@ -0,0 +1,24 @@
package dao
import (
"context"
"fmt"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDao_QQUnionID(t *testing.T) {
var (
c = context.Background()
openID = "2A9FE674CE0810761DC3F420239A8CD7"
)
convey.Convey("QQUnionID", t, func(ctx convey.C) {
res, err := d.QQUnionID(c, openID)
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)
})
fmt.Printf("(%+v) error(%+v)", res, err)
})
}

View File

@@ -0,0 +1,164 @@
package dao
import (
"context"
"database/sql"
"fmt"
"hash/crc32"
"go-common/app/job/main/passport-sns/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_getSnsUserByMidSQL = "SELECT mid,unionid,platform,expires FROM sns_user WHERE mid = ? and platform = ?"
_getSnsUserByUnionIDSQL = "SELECT mid,unionid,platform FROM sns_user WHERE unionid = ? and platform = ?"
_addSnsUserSQL = "INSERT INTO sns_user (mid,unionid,platform,expires) VALUES(?,?,?,?)"
_addSnsOpenIDSQL = "INSERT IGNORE INTO sns_openid_%02d (openid,unionid,appid,platform) VALUES(?,?,?,?)"
_addSnsTokenSQL = "INSERT INTO sns_token (mid,openid,unionid,platform,token,expires,appid) VALUES(?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE mid=?, openid =?, token =?, expires =?, appid =?"
_delSnsUserSQL = "DELETE FROM sns_user WHERE mid = ? and platform = ?"
_updateSnsUserExpiresSQL = "UPDATE sns_user SET expires = ? where mid = ? and platform = ?"
_updateSnsUserSQL = "UPDATE sns_user SET unionid = ?, expires = ? where mid = ? and platform = ?"
_updateSnsTokenSQL = "UPDATE sns_token SET token =?, expires =? WHERE mid =? and platform = ?"
)
// SnsUserByMid get sns user by mid and platform
func (d *Dao) SnsUserByMid(c context.Context, mid int64, platform int) (res *model.SnsUser, err error) {
res = new(model.SnsUser)
row := d.snsDB.QueryRow(c, _getSnsUserByMidSQL, mid, platform)
if err = row.Scan(&res.Mid, &res.UnionID, &res.Platform, &res.Expires); err != nil {
if err == xsql.ErrNoRows {
err = nil
res = nil
return
}
log.Error("SnsUserByMid mid(%d) platform(%d) row.Scan() error(%+v)", mid, platform, err)
return
}
return
}
// SnsUserByUnionID get sns user by unionID and platform
func (d *Dao) SnsUserByUnionID(c context.Context, unionID string, platform int) (res *model.SnsUser, err error) {
res = new(model.SnsUser)
row := d.snsDB.QueryRow(c, _getSnsUserByUnionIDSQL, unionID, platform)
if err = row.Scan(&res.Mid, &res.UnionID, &res.Platform); err != nil {
if err == xsql.ErrNoRows {
err = nil
res = nil
return
}
log.Error("SnsUserByUnionID unionID(%d) platform(%d) row.Scan() error(%+v)", unionID, platform, err)
return
}
return
}
// AddSnsUser add sns user.
func (d *Dao) AddSnsUser(c context.Context, mid, expires int64, unionID string, platform int) (affected int64, err error) {
var res sql.Result
if res, err = d.snsDB.Exec(c, _addSnsUserSQL, mid, unionID, platform, expires); err != nil {
log.Error("AddSnsUser mid(%d) platform(%d) unionID(%s) expires(%d) d.snsDB.Exec() error(%+v)", mid, platform, unionID, platform, err)
return
}
return res.RowsAffected()
}
// TxAddSnsUser add sns user.
func (d *Dao) TxAddSnsUser(tx *xsql.Tx, a *model.SnsUser) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_addSnsUserSQL, a.Mid, a.UnionID, a.Platform, a.Expires); err != nil {
log.Error("TxAddSnsUser(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// TxAddSnsOpenID add sns openid.
func (d *Dao) TxAddSnsOpenID(tx *xsql.Tx, a *model.SnsOpenID) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(fmt.Sprintf(_addSnsOpenIDSQL, openIDSuffix(a.OpenID)), a.OpenID, a.UnionID, a.AppID, a.Platform); err != nil {
log.Error("TxAddSnsOpenID(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// TxAddSnsToken add sns token.
func (d *Dao) TxAddSnsToken(tx *xsql.Tx, a *model.SnsToken) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_addSnsTokenSQL, a.Mid, a.OpenID, a.UnionID, a.Platform, a.Token, a.Expires, a.AppID, a.Mid, a.OpenID, a.Token, a.Expires, a.AppID); err != nil {
log.Error("TxAddSnsToken(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// DelSnsUser del sns user.
func (d *Dao) DelSnsUser(c context.Context, mid int64, platform int) (affected int64, err error) {
var res sql.Result
if res, err = d.snsDB.Exec(c, _delSnsUserSQL, mid, platform); err != nil {
log.Error("DelSnsUser mid(%d) platform(%d) d.snsDB.Exec() error(%+v)", mid, platform, err)
return
}
return res.RowsAffected()
}
// TxUpdateSnsUserExpires update sns user expires.
func (d *Dao) TxUpdateSnsUserExpires(tx *xsql.Tx, a *model.SnsUser) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updateSnsUserExpiresSQL, a.Expires, a.Mid, a.Platform); err != nil {
log.Error("TxUpdateSnsUser(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// TxUpdateSnsUser update sns user.
func (d *Dao) TxUpdateSnsUser(tx *xsql.Tx, mid, expires int64, unionID string, platform int) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updateSnsUserSQL, unionID, expires, mid, platform); err != nil {
log.Error("TxUpdateSnsUser mid(%d) platform(%d) unionID(%s) expires(%d) d.snsDB.Exec() error(%+v)", mid, platform, unionID, platform, err)
return
}
return res.RowsAffected()
}
// UpdateSnsUser update sns user.
func (d *Dao) UpdateSnsUser(c context.Context, mid, expires int64, unionID string, platform int) (affected int64, err error) {
var res sql.Result
if res, err = d.snsDB.Exec(c, _updateSnsUserSQL, unionID, expires, mid, platform); err != nil {
log.Error("UpdateSnsUser mid(%d) platform(%d) unionID(%s) expires(%d) d.snsDB.Exec() error(%+v)", mid, platform, unionID, platform, err)
return
}
return res.RowsAffected()
}
// TxUpdateSnsToken update sns token.
func (d *Dao) TxUpdateSnsToken(tx *xsql.Tx, a *model.SnsToken) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updateSnsTokenSQL, a.Token, a.Expires, a.Mid, a.Platform); err != nil {
log.Error("TxUpdateSnsToken(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// UpdateSnsToken update sns token.
func (d *Dao) UpdateSnsToken(c context.Context, a *model.SnsToken) (affected int64, err error) {
var res sql.Result
if res, err = d.snsDB.Exec(c, _updateSnsTokenSQL, a.Token, a.Expires, a.Mid, a.Platform); err != nil {
log.Error("UpdateSnsToken(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
func openIDSuffix(openID string) int {
v := int(crc32.ChecksumIEEE([]byte(openID)))
if v < 0 {
v = -v
}
return v % 100
}

View File

@@ -0,0 +1,268 @@
package dao
import (
"context"
"database/sql"
"database/sql/driver"
"reflect"
"testing"
"go-common/app/job/main/passport-sns/model"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
func TestDao_SnsUserByMid(t *testing.T) {
convey.Convey("SnsUserByMid", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQ
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.SnsUserByMid(c, mid, platform)
ctx.Convey("Then err should be nil.res should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
})
}
func TestDao_SnsUserByUnionID(t *testing.T) {
convey.Convey("SnsUserByUnionID", t, func(ctx convey.C) {
var (
c = context.Background()
unionID = ""
platform = model.PlatformQQ
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.SnsUserByUnionID(c, unionID, platform)
ctx.Convey("Then err should be nil.res should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
})
}
func TestDao_AddSnsUser(t *testing.T) {
convey.Convey("AddSnsUser", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQ
expires = int64(0)
unionID = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(d.snsDB), "Exec", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.AddSnsUser(c, mid, expires, unionID, platform)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_UpdateSnsUser(t *testing.T) {
convey.Convey("UpdateSnsUser", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQ
expires = int64(0)
unionID = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(d.snsDB), "Exec", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.UpdateSnsUser(c, mid, expires, unionID, platform)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_UpdateSnsToken(t *testing.T) {
convey.Convey("UpdateSnsToken", t, func(ctx convey.C) {
var (
c = context.Background()
a = &model.SnsToken{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(d.snsDB), "Exec", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.UpdateSnsToken(c, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxAddSnsUser(t *testing.T) {
convey.Convey("TxAddSnsUser", t, func(ctx convey.C) {
var (
tx, _ = d.BeginSnsTran(context.Background())
a = &model.SnsUser{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxAddSnsUser(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxAddSnsOpenID(t *testing.T) {
convey.Convey("TxAddSnsOpenID", t, func(ctx convey.C) {
var (
tx, _ = d.BeginSnsTran(context.Background())
a = &model.SnsOpenID{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxAddSnsOpenID(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxAddSnsToken(t *testing.T) {
convey.Convey("TxAddSnsToken", t, func(ctx convey.C) {
var (
tx, _ = d.BeginSnsTran(context.Background())
a = &model.SnsToken{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxAddSnsToken(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_DelSnsUser(t *testing.T) {
convey.Convey("DelSnsUser", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQ
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(d.snsDB), "Exec", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.DelSnsUser(c, mid, platform)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxUpdateSnsUserExpires(t *testing.T) {
convey.Convey("TxUpdateSnsUserExpires", t, func(ctx convey.C) {
var (
tx, _ = d.BeginSnsTran(context.Background())
a = &model.SnsUser{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxUpdateSnsUserExpires(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxUpdateSnsUser(t *testing.T) {
convey.Convey("TxUpdateSnsUser", t, func(ctx convey.C) {
var (
tx, _ = d.BeginSnsTran(context.Background())
mid = int64(0)
platform = model.PlatformQQ
expires = int64(0)
unionID = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxUpdateSnsUser(tx, mid, expires, unionID, platform)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxUpdateSnsToken(t *testing.T) {
convey.Convey("TxUpdateSnsToken", t, func(ctx convey.C) {
var (
tx, _ = d.BeginSnsTran(context.Background())
a = &model.SnsToken{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxUpdateSnsToken(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_openIDSuffix(t *testing.T) {
convey.Convey("openIDSuffix", t, func(ctx convey.C) {
res := openIDSuffix("")
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,34 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["http.go"],
importpath = "go-common/app/job/main/passport-sns/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/passport-sns/conf:go_default_library",
"//app/job/main/passport-sns/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster: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,38 @@
package http
import (
"net/http"
"go-common/app/job/main/passport-sns/conf"
"go-common/app/job/main/passport-sns/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
srv *service.Service
)
// Init init http sever instance.
func Init(c *conf.Config) {
srv = service.New(c)
engine := bm.DefaultServer(c.BM)
innerRouter(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start() error(%v)", err)
panic(err)
}
}
// innerRouter init inner router.
func innerRouter(e *bm.Engine) {
e.Ping(ping)
}
// ping service
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -0,0 +1,58 @@
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",
)
go_library(
name = "go_default_library",
srcs = [
"const.go",
"message.go",
"model.go",
],
embed = [":model_go_proto"],
importpath = "go-common/app/job/main/passport-sns/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
proto_library(
name = "model_proto",
srcs = ["sns.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
importpath = "go-common/app/job/main/passport-sns/model",
proto = ":model_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)

View File

@@ -0,0 +1,15 @@
package model
// appid
const (
OldAppID = "101135748"
)
// platform
const (
PlatformQQ = 1
PlatformWEIBO = 2
PlatformQQStr = "qq"
PlatformWEIBOStr = "weibo"
)

View File

@@ -0,0 +1,12 @@
package model
import "encoding/json"
// BMsg databus binlog message.
type BMsg struct {
Action string `json:"action"`
Table string `json:"table"`
New json.RawMessage `json:"new"`
Old json.RawMessage `json:"old"`
Timestamp int64 `json:"timestamp"`
}

View File

@@ -0,0 +1,59 @@
package model
// SnsLog .
type SnsLog struct {
Mid int64 `json:"mid"`
OpenID string `json:"openid"`
UnionID string `json:"unionid"`
AppID string `json:"appid"`
Platform int `json:"platform"`
Operator string `json:"operator"`
Operate int `json:"operate"`
Description string `json:"description"`
}
// SnsUser .
type SnsUser struct {
Mid int64 `json:"mid"`
UnionID string `json:"unionid"`
Platform int `json:"platform"`
Expires int64 `json:"expires"`
}
// SnsOpenID .
type SnsOpenID struct {
Mid int64 `json:"mid"`
OpenID string `json:"openid"`
UnionID string `json:"unionid"`
AppID string `json:"appid"`
Platform int `json:"platform"`
}
// SnsToken .
type SnsToken struct {
Mid int64 `json:"mid"`
OpenID string `json:"openid"`
UnionID string `json:"unionid"`
Platform int `json:"platform"`
Token string `json:"token"`
Expires int64 `json:"expires"`
AppID string `json:"appid"`
}
// AsoAccountSns aso account sns.
type AsoAccountSns struct {
Mid int64 `json:"mid"`
SinaUID int64 `json:"sina_uid"`
SinaAccessToken string `json:"sina_access_token"`
SinaAccessExpires int64 `json:"sina_access_expires"`
QQOpenid string `json:"qq_openid"`
QQAccessToken string `json:"qq_access_token"`
QQAccessExpires int64 `json:"qq_access_expires"`
}
// QQUnionIDResp qq unionid resp.
type QQUnionIDResp struct {
Code int `json:"error"`
Description string `json:"error_description"`
UnionID string `json:"unionid"`
}

View File

@@ -0,0 +1,7 @@
#! /bin/sh
# proto.sh
gopath=$GOPATH/src
gogopath=$GOPATH/src/go-common/vendor/github.com/gogo/protobuf
protoc --gofast_out=. --proto_path=$gopath:$gogopath:. *.proto

View File

@@ -0,0 +1,416 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: sns.proto
/*
Package model is a generated protocol buffer package.
It is generated from these files:
sns.proto
It has these top-level messages:
SnsProto
*/
package model
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type SnsProto struct {
Mid int64 `protobuf:"varint,1,opt,name=Mid,proto3" json:"mid"`
UnionID string `protobuf:"bytes,2,opt,name=UnionID,proto3" json:"unionid"`
Platform int32 `protobuf:"varint,3,opt,name=Platform,proto3" json:"platform"`
Expires int64 `protobuf:"varint,4,opt,name=Expires,proto3" json:"expires"`
}
func (m *SnsProto) Reset() { *m = SnsProto{} }
func (m *SnsProto) String() string { return proto.CompactTextString(m) }
func (*SnsProto) ProtoMessage() {}
func (*SnsProto) Descriptor() ([]byte, []int) { return fileDescriptorSns, []int{0} }
func (m *SnsProto) GetMid() int64 {
if m != nil {
return m.Mid
}
return 0
}
func (m *SnsProto) GetUnionID() string {
if m != nil {
return m.UnionID
}
return ""
}
func (m *SnsProto) GetPlatform() int32 {
if m != nil {
return m.Platform
}
return 0
}
func (m *SnsProto) GetExpires() int64 {
if m != nil {
return m.Expires
}
return 0
}
func init() {
proto.RegisterType((*SnsProto)(nil), "passport.service.sns.SnsProto")
}
func (m *SnsProto) 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 *SnsProto) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Mid != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintSns(dAtA, i, uint64(m.Mid))
}
if len(m.UnionID) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintSns(dAtA, i, uint64(len(m.UnionID)))
i += copy(dAtA[i:], m.UnionID)
}
if m.Platform != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintSns(dAtA, i, uint64(m.Platform))
}
if m.Expires != 0 {
dAtA[i] = 0x20
i++
i = encodeVarintSns(dAtA, i, uint64(m.Expires))
}
return i, nil
}
func encodeVarintSns(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 *SnsProto) Size() (n int) {
var l int
_ = l
if m.Mid != 0 {
n += 1 + sovSns(uint64(m.Mid))
}
l = len(m.UnionID)
if l > 0 {
n += 1 + l + sovSns(uint64(l))
}
if m.Platform != 0 {
n += 1 + sovSns(uint64(m.Platform))
}
if m.Expires != 0 {
n += 1 + sovSns(uint64(m.Expires))
}
return n
}
func sovSns(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozSns(x uint64) (n int) {
return sovSns(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *SnsProto) 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 ErrIntOverflowSns
}
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: SnsProto: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: SnsProto: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType)
}
m.Mid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSns
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Mid |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field UnionID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSns
}
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 ErrInvalidLengthSns
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.UnionID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Platform", wireType)
}
m.Platform = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSns
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Platform |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Expires", wireType)
}
m.Expires = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSns
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Expires |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipSns(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthSns
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipSns(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, ErrIntOverflowSns
}
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, ErrIntOverflowSns
}
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, ErrIntOverflowSns
}
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, ErrInvalidLengthSns
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowSns
}
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 := skipSns(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 (
ErrInvalidLengthSns = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowSns = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("sns.proto", fileDescriptorSns) }
var fileDescriptorSns = []byte{
// 236 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2c, 0xce, 0x2b, 0xd6,
0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x29, 0x48, 0x2c, 0x2e, 0x2e, 0xc8, 0x2f, 0x2a, 0xd1,
0x2b, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0xd5, 0x2b, 0xce, 0x2b, 0x96, 0xd2, 0x4d, 0xcf, 0x2c,
0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0x4f, 0xcf, 0xd7, 0x07, 0x2b, 0x4e,
0x2a, 0x4d, 0x03, 0xf3, 0xc0, 0x1c, 0x30, 0x0b, 0x62, 0x88, 0xd2, 0x5c, 0x46, 0x2e, 0x8e, 0xe0,
0xbc, 0xe2, 0x00, 0xb0, 0x89, 0x92, 0x5c, 0xcc, 0xbe, 0x99, 0x29, 0x12, 0x8c, 0x0a, 0x8c, 0x1a,
0xcc, 0x4e, 0xec, 0xaf, 0xee, 0xc9, 0x33, 0xe7, 0x66, 0xa6, 0x04, 0x81, 0xc4, 0x84, 0x54, 0xb9,
0xd8, 0x43, 0xf3, 0x32, 0xf3, 0xf3, 0x3c, 0x5d, 0x24, 0x98, 0x14, 0x18, 0x35, 0x38, 0x9d, 0xb8,
0x5f, 0xdd, 0x93, 0x67, 0x2f, 0x05, 0x09, 0x65, 0xa6, 0x04, 0xc1, 0xe4, 0x84, 0x34, 0xb8, 0x38,
0x02, 0x72, 0x12, 0x4b, 0xd2, 0xf2, 0x8b, 0x72, 0x25, 0x98, 0x15, 0x18, 0x35, 0x58, 0x9d, 0x78,
0x5e, 0xdd, 0x93, 0xe7, 0x28, 0x80, 0x8a, 0x05, 0xc1, 0x65, 0x41, 0x06, 0xba, 0x56, 0x14, 0x64,
0x16, 0xa5, 0x16, 0x4b, 0xb0, 0x80, 0xed, 0x03, 0x1b, 0x98, 0x0a, 0x11, 0x0a, 0x82, 0xc9, 0x39,
0x89, 0x9f, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x33, 0x1e,
0xcb, 0x31, 0x44, 0xb1, 0xe6, 0xe6, 0xa7, 0xa4, 0xe6, 0x24, 0xb1, 0x81, 0xdd, 0x6f, 0x0c, 0x08,
0x00, 0x00, 0xff, 0xff, 0xdb, 0x0a, 0x19, 0x68, 0x11, 0x01, 0x00, 0x00,
}

View File

@@ -0,0 +1,12 @@
syntax = "proto3";
package passport.service.sns;
option go_package = "model";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
message SnsProto {
int64 Mid = 1 [(gogoproto.jsontag) = "mid"];
string UnionID = 2 [(gogoproto.jsontag) = "unionid"];
int32 Platform = 3 [(gogoproto.jsontag) = "platform"];
int64 Expires = 4 [(gogoproto.jsontag) = "expires"];
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"service.go",
"sns_log.go",
"sync_sns.go",
],
importpath = "go-common/app/job/main/passport-sns/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/passport-sns/conf:go_default_library",
"//app/job/main/passport-sns/dao:go_default_library",
"//app/job/main/passport-sns/model:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/queue/databus/databusutil:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
"//vendor/github.com/go-sql-driver/mysql: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,83 @@
package service
import (
"context"
"go-common/app/job/main/passport-sns/conf"
"go-common/app/job/main/passport-sns/dao"
"go-common/app/job/main/passport-sns/model"
"go-common/library/queue/databus"
"go-common/library/queue/databus/databusutil"
"go-common/library/sync/pipeline/fanout"
)
// Service service.
type Service struct {
c *conf.Config
d *dao.Dao
snsLogConsumer *databus.Databus
asoBinLogConsumer *databus.Databus
group *databusutil.Group
snsChan []chan *model.AsoAccountSns
checkChan []chan *model.AsoAccountSns
cache *fanout.Fanout
}
// New new a service instance.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
d: dao.New(c),
snsLogConsumer: databus.New(c.DataBus.SnsLogSub),
snsChan: make([]chan *model.AsoAccountSns, c.SyncConf.ChanNum),
checkChan: make([]chan *model.AsoAccountSns, c.SyncConf.ChanNum),
cache: fanout.New("cache", fanout.Worker(10), fanout.Buffer(10240)),
}
go s.snsLogConsume()
if c.SyncConf.IncSwitch {
s.asoBinLogConsumer = databus.New(c.DataBus.AsoBinLogSub)
s.group = databusutil.NewGroup(
c.DatabusUtil,
s.asoBinLogConsumer.Messages(),
)
s.asoBinLogConsume()
}
if c.SyncConf.FullSwitch {
for i := 0; i < c.SyncConf.ChanNum; i++ {
ch := make(chan *model.AsoAccountSns, c.SyncConf.ChanSize)
s.snsChan[i] = ch
go s.fullSyncSnsConsume(ch)
}
go s.fullSyncSns()
}
if c.SyncConf.CheckSwitch {
for i := 0; i < c.SyncConf.ChanNum; i++ {
ch := make(chan *model.AsoAccountSns, c.SyncConf.ChanSize)
s.checkChan[i] = ch
go s.checkConsume(ch)
}
go s.checkAll()
}
return
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
return s.d.Ping(c)
}
// Close close service, including databus and outer service.
func (s *Service) Close() (err error) {
s.d.Close()
return
}
func parsePlatformStr(platform int) string {
switch platform {
case model.PlatformQQ:
return model.PlatformQQStr
case model.PlatformWEIBO:
return model.PlatformWEIBOStr
}
return ""
}

View File

@@ -0,0 +1,33 @@
package service
import (
"context"
"encoding/json"
"time"
"go-common/app/job/main/passport-sns/model"
"go-common/library/log"
)
func (s *Service) snsLogConsume() {
for {
msg, ok := <-s.snsLogConsumer.Messages()
if !ok {
log.Error("s.snsLogConsumer.Messages closed")
return
}
snsLog := &model.SnsLog{}
if err := json.Unmarshal(msg.Value, snsLog); err != nil {
log.Error("json.Unmarshal(%s) error(%+v)", string(msg.Value), err)
continue
}
log.Info("receive msg snsLog(%+v)", snsLog)
for {
if _, err := s.d.AddSnsLog(context.Background(), snsLog); err != nil {
time.Sleep(100 * time.Millisecond)
continue
}
break
}
}
}

View File

@@ -0,0 +1,844 @@
package service
import (
"context"
"encoding/json"
"strconv"
"time"
"go-common/app/job/main/passport-sns/model"
"go-common/library/log"
"go-common/library/queue/databus"
"github.com/go-sql-driver/mysql"
"github.com/pkg/errors"
)
const (
_asoAccountSnsTable = "aso_account_sns"
_insertAction = "insert"
_updateAction = "update"
_deleteAction = "delete"
_mySQLErrCodeDuplicateEntry = 1062
)
type asoAccountSnsBMsg struct {
Action string
Table string
New *model.AsoAccountSns
Old *model.AsoAccountSns
Timestamp int64
}
func (s *Service) asoBinLogConsume() {
s.group.New = func(msg *databus.Message) (res interface{}, err error) {
bmsg := new(model.BMsg)
if err = json.Unmarshal(msg.Value, bmsg); err != nil {
log.Error("json.Unmarshal(%s) error(%+v)", string(msg.Value), err)
return
}
log.Info("receive msg action(%s) table(%s) key(%s) partition(%d) offset(%d) timestamp(%d) New(%s) Old(%s)",
bmsg.Action, bmsg.Table, msg.Key, msg.Partition, msg.Offset, msg.Timestamp, string(bmsg.New), string(bmsg.Old))
if bmsg.Table == _asoAccountSnsTable {
asoAccountSnsBMsg := &asoAccountSnsBMsg{
Action: bmsg.Action,
Table: bmsg.Table,
Timestamp: msg.Timestamp,
}
newAccountSns := new(model.AsoAccountSns)
if err = json.Unmarshal(bmsg.New, newAccountSns); err != nil {
log.Error("json.Unmarshal(%s) error(%+v)", string(bmsg.New), err)
return
}
asoAccountSnsBMsg.New = newAccountSns
if bmsg.Action == _updateAction {
oldAccountSns := new(model.AsoAccountSns)
if err = json.Unmarshal(bmsg.Old, oldAccountSns); err != nil {
log.Error("json.Unmarshal(%s) error(%+v)", string(bmsg.Old), err)
return
}
asoAccountSnsBMsg.Old = oldAccountSns
}
return asoAccountSnsBMsg, nil
}
return
}
s.group.Split = func(msg *databus.Message, data interface{}) int {
if t, ok := data.(*asoAccountSnsBMsg); ok {
return int(t.New.Mid)
}
return 0
}
s.group.Do = func(msgs []interface{}) {
for _, m := range msgs {
if msg, ok := m.(*asoAccountSnsBMsg); ok {
for {
if err := s.handleAsoAccountSns(msg); err != nil {
log.Error("fail to handleAsoAccountSns msg(%+v) new(%+v) error(%+v)", msg, msg.New, err)
time.Sleep(100 * time.Millisecond)
continue
}
break
}
}
}
}
// start the group
s.group.Start()
log.Info("s.group.Start()")
}
func (s *Service) handleAsoAccountSns(msg *asoAccountSnsBMsg) (err error) {
switch msg.Action {
case _insertAction:
if msg.New.QQOpenid != "" {
if err = s.addSnsQQ(msg.New); err != nil {
return
}
}
if msg.New.SinaUID != 0 {
if err = s.addSnsWeibo(msg.New); err != nil {
return
}
}
case _updateAction:
if msg.New.QQOpenid != msg.Old.QQOpenid {
if msg.New.QQOpenid == "" {
if _, err = s.d.DelSnsUser(context.Background(), msg.New.Mid, model.PlatformQQ); err != nil {
return
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.DelSnsCache(c, msg.New.Mid, model.PlatformQQStr)
})
}
if msg.New.QQOpenid != "" {
var user *model.SnsUser
if user, err = s.d.SnsUserByMid(context.Background(), msg.New.Mid, model.PlatformQQ); err != nil {
return
}
if user == nil {
if err = s.addSnsQQ(msg.New); err != nil {
return
}
} else {
if err = s.updateSnsQQ(msg.New); err != nil {
return
}
}
}
return
}
if msg.New.SinaUID != msg.Old.SinaUID {
if msg.New.SinaUID == 0 {
if _, err = s.d.DelSnsUser(context.Background(), msg.New.Mid, model.PlatformWEIBO); err != nil {
return
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.DelSnsCache(c, msg.New.Mid, model.PlatformWEIBOStr)
})
}
if msg.New.SinaUID != 0 {
var user *model.SnsUser
if user, err = s.d.SnsUserByMid(context.Background(), msg.New.Mid, model.PlatformWEIBO); err != nil {
return
}
if user == nil {
if err = s.addSnsWeibo(msg.New); err != nil {
return
}
} else {
if err = s.updateSnsWeibo(msg.New); err != nil {
return
}
}
}
return
}
if msg.New.SinaAccessExpires != msg.Old.SinaAccessExpires {
return s.updateSns(msg.New.Mid, msg.New.SinaAccessExpires, strconv.FormatInt(msg.New.SinaUID, 10), msg.New.SinaAccessToken, model.PlatformWEIBO)
}
if msg.New.QQAccessExpires != msg.Old.QQAccessExpires {
var qqUnionID string
if qqUnionID, err = s.d.QQUnionID(context.Background(), msg.New.QQOpenid); err != nil {
return
}
if qqUnionID == "" {
log.Error("update qq expires, qqUnionID is null, oldMsg(%+v) newMsg(%+v)", msg.Old, msg.New)
return
}
return s.updateSns(msg.New.Mid, msg.New.QQAccessExpires, qqUnionID, msg.New.QQAccessToken, model.PlatformQQ)
}
case _deleteAction:
if _, err = s.d.DelSnsUser(context.Background(), msg.New.Mid, model.PlatformQQ); err != nil {
return
}
if _, err = s.d.DelSnsUser(context.Background(), msg.New.Mid, model.PlatformWEIBO); err != nil {
return
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.DelSnsCache(c, msg.New.Mid, model.PlatformQQStr)
})
s.cache.Do(context.Background(), func(c context.Context) {
s.d.DelSnsCache(c, msg.New.Mid, model.PlatformWEIBOStr)
})
}
return
}
func (s *Service) updateSns(mid, expires int64, unionID, token string, platform int) (err error) {
tx, err := s.d.BeginSnsTran(context.Background())
if err != nil {
log.Error("s.d.BeginTran error(%+v)", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback() error(%v)", err1)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}()
snsUser := &model.SnsUser{
Mid: mid,
UnionID: unionID,
Platform: platform,
Expires: expires,
}
if _, err = s.d.TxUpdateSnsUserExpires(tx, snsUser); err != nil {
return
}
snsToken := &model.SnsToken{
Mid: mid,
Platform: platform,
Token: token,
Expires: expires,
}
if _, err = s.d.TxUpdateSnsToken(tx, snsToken); err != nil {
return
}
s.cache.Do(context.Background(), func(c context.Context) {
proto := &model.SnsProto{
Mid: snsUser.Mid,
Platform: int32(platform),
UnionID: snsUser.UnionID,
Expires: snsUser.Expires,
}
s.d.SetSnsCache(c, mid, parsePlatformStr(platform), proto)
})
return
}
func (s *Service) addSnsQQ(sns *model.AsoAccountSns) (err error) {
unionID, err := s.d.GetUnionIDCache(context.Background(), sns.QQOpenid)
if err != nil || unionID == "" {
unionID, err = s.d.QQUnionID(context.Background(), sns.QQOpenid)
if err != nil || unionID == "" {
return
}
}
tx, err := s.d.BeginSnsTran(context.Background())
if err != nil {
log.Error("s.d.BeginTran error(%+v)", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback() error(%v)", err1)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}()
snsUser := &model.SnsUser{
Mid: sns.Mid,
UnionID: unionID,
Platform: model.PlatformQQ,
Expires: sns.QQAccessExpires,
}
if _, err = s.d.TxAddSnsUser(tx, snsUser); err != nil {
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
u, e := s.d.SnsUserByMid(context.Background(), snsUser.Mid, snsUser.Platform)
if e != nil {
return e
}
err = nil
if u != nil && u.Mid == snsUser.Mid {
return
}
log.Error("add sns qq duplicate (%+v)", snsUser)
return
}
}
return
}
snsOpenID := &model.SnsOpenID{
Mid: sns.Mid,
OpenID: sns.QQOpenid,
UnionID: unionID,
AppID: model.OldAppID,
Platform: model.PlatformQQ,
}
if _, err = s.d.TxAddSnsOpenID(tx, snsOpenID); err != nil {
return
}
snsToken := &model.SnsToken{
Mid: sns.Mid,
OpenID: sns.QQOpenid,
UnionID: unionID,
Platform: model.PlatformQQ,
Token: sns.QQAccessToken,
Expires: sns.QQAccessExpires,
AppID: model.OldAppID,
}
if _, err = s.d.TxAddSnsToken(tx, snsToken); err != nil {
return
}
proto := &model.SnsProto{
Mid: snsUser.Mid,
Platform: model.PlatformQQ,
UnionID: snsUser.UnionID,
Expires: snsUser.Expires,
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.SetSnsCache(c, sns.Mid, model.PlatformQQStr, proto)
})
return
}
func (s *Service) addSnsWeibo(sns *model.AsoAccountSns) (err error) {
tx, err := s.d.BeginSnsTran(context.Background())
if err != nil {
log.Error("s.d.BeginTran error(%+v)", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback() error(%v)", err1)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}()
snsUser := &model.SnsUser{
Mid: sns.Mid,
UnionID: strconv.FormatInt(sns.SinaUID, 10),
Platform: model.PlatformWEIBO,
Expires: sns.SinaAccessExpires,
}
if _, err = s.d.TxAddSnsUser(tx, snsUser); err != nil {
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
u, e := s.d.SnsUserByMid(context.Background(), snsUser.Mid, snsUser.Platform)
if e != nil {
return e
}
err = nil
if u != nil && u.Mid == snsUser.Mid {
return
}
log.Error("add sns weibo duplicate (%+v)", snsUser)
return
}
}
return
}
snsOpenID := &model.SnsOpenID{
Mid: sns.Mid,
OpenID: strconv.FormatInt(sns.SinaUID, 10),
UnionID: strconv.FormatInt(sns.SinaUID, 10),
AppID: model.OldAppID,
Platform: model.PlatformWEIBO,
}
if _, err = s.d.TxAddSnsOpenID(tx, snsOpenID); err != nil {
return
}
snsToken := &model.SnsToken{
Mid: sns.Mid,
OpenID: strconv.FormatInt(sns.SinaUID, 10),
UnionID: strconv.FormatInt(sns.SinaUID, 10),
Platform: model.PlatformWEIBO,
Token: sns.SinaAccessToken,
Expires: sns.SinaAccessExpires,
AppID: model.OldAppID,
}
if _, err = s.d.TxAddSnsToken(tx, snsToken); err != nil {
return
}
proto := &model.SnsProto{
Mid: snsUser.Mid,
Platform: model.PlatformWEIBO,
UnionID: snsUser.UnionID,
Expires: snsUser.Expires,
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.SetSnsCache(c, sns.Mid, model.PlatformWEIBOStr, proto)
})
return
}
func (s *Service) updateSnsQQ(sns *model.AsoAccountSns) (err error) {
unionID, err := s.d.GetUnionIDCache(context.Background(), sns.QQOpenid)
if err != nil || unionID == "" {
unionID, err = s.d.QQUnionID(context.Background(), sns.QQOpenid)
if err != nil || unionID == "" {
return
}
}
tx, err := s.d.BeginSnsTran(context.Background())
if err != nil {
log.Error("s.d.BeginTran error(%+v)", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback() error(%v)", err1)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}()
if _, err = s.d.TxUpdateSnsUser(tx, sns.Mid, sns.QQAccessExpires, unionID, model.PlatformQQ); err != nil {
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
u, e := s.d.SnsUserByMid(context.Background(), sns.Mid, model.PlatformQQ)
if e != nil {
return e
}
err = nil
if u != nil && u.Mid == sns.Mid {
return
}
log.Error("update sns qq duplicate, mid(%d) unionID(%s)", sns.Mid, unionID)
return
}
}
return
}
snsToken := &model.SnsToken{
Mid: sns.Mid,
OpenID: sns.QQOpenid,
UnionID: unionID,
Platform: model.PlatformQQ,
Token: sns.QQAccessToken,
Expires: sns.QQAccessExpires,
AppID: model.OldAppID,
}
if _, err = s.d.TxAddSnsToken(tx, snsToken); err != nil {
return
}
proto := &model.SnsProto{
Mid: sns.Mid,
Platform: model.PlatformQQ,
UnionID: unionID,
Expires: sns.QQAccessExpires,
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.SetSnsCache(c, sns.Mid, model.PlatformQQStr, proto)
})
return
}
func (s *Service) updateSnsWeibo(sns *model.AsoAccountSns) (err error) {
tx, err := s.d.BeginSnsTran(context.Background())
if err != nil {
log.Error("s.d.BeginTran error(%+v)", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback() error(%v)", err1)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}()
if _, err = s.d.TxUpdateSnsUser(tx, sns.Mid, sns.SinaAccessExpires, strconv.FormatInt(sns.SinaUID, 10), model.PlatformWEIBO); err != nil {
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
u, e := s.d.SnsUserByMid(context.Background(), sns.Mid, model.PlatformWEIBO)
if e != nil {
return e
}
err = nil
if u != nil && u.Mid == sns.Mid {
return
}
log.Error("update sns weibo duplicate, mid(%d) unionID(%s)", sns.Mid, strconv.FormatInt(sns.SinaUID, 10))
return
}
}
return
}
snsToken := &model.SnsToken{
Mid: sns.Mid,
OpenID: strconv.FormatInt(sns.SinaUID, 10),
UnionID: strconv.FormatInt(sns.SinaUID, 10),
Platform: model.PlatformWEIBO,
Token: sns.SinaAccessToken,
Expires: sns.SinaAccessExpires,
AppID: model.OldAppID,
}
if _, err = s.d.TxAddSnsToken(tx, snsToken); err != nil {
return
}
proto := &model.SnsProto{
Mid: sns.Mid,
Platform: model.PlatformWEIBO,
UnionID: strconv.FormatInt(sns.SinaUID, 10),
Expires: sns.SinaAccessExpires,
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.SetSnsCache(c, sns.Mid, model.PlatformWEIBOStr, proto)
})
return
}
func (s *Service) fullSyncSns() {
var (
start int64
chanNum = int64(s.c.SyncConf.ChanNum)
)
for {
log.Info("fullSyncSns, start %d", start)
res, err := s.d.AsoAccountSns(context.Background(), start)
if err != nil {
log.Error("fail to get AsoAccountSns error(%+v)", err)
time.Sleep(100 * time.Millisecond)
continue
}
for _, a := range res {
s.snsChan[a.Mid%chanNum] <- a
}
if len(res) == 0 {
log.Info("fullSyncSns finished! endID(%d)", start)
break
}
start = res[len(res)-1].Mid
}
}
func (s *Service) fullSyncSnsConsume(c chan *model.AsoAccountSns) {
for {
a, ok := <-c
if !ok {
log.Error("snsChan closed")
return
}
for {
if a.SinaUID != 0 {
if err := s.addSnsWeibo(a); err != nil {
continue
}
}
if a.QQOpenid != "" {
if err := s.addSnsQQ(a); err != nil {
continue
}
}
break
}
}
}
func (s *Service) checkAll() {
ticker := time.NewTicker(time.Duration(s.c.SyncConf.CheckTicker))
for {
s.checkSnsUser()
<-ticker.C
}
}
func (s *Service) checkConsume(c chan *model.AsoAccountSns) {
for {
a, ok := <-c
if !ok {
log.Error("snsChan closed")
return
}
for {
if err := s.checkWeibo(a); err != nil {
time.Sleep(100 * time.Millisecond)
continue
}
if err := s.checkQQ(a); err != nil {
time.Sleep(100 * time.Millisecond)
continue
}
break
}
}
}
func (s *Service) checkSnsUser() {
var (
start int64
chanNum = int64(s.c.SyncConf.ChanNum)
)
for {
log.Info("checkSnsUser, start %d", start)
res, err := s.d.AsoAccountSnsAll(context.Background(), start)
if err != nil {
log.Error("fail to get AsoAccountSns error(%+v)", err)
time.Sleep(100 * time.Millisecond)
continue
}
for _, a := range res {
s.checkChan[a.Mid%chanNum] <- a
}
if len(res) == 0 {
log.Info("checkSnsUser finished! endID(%d)", start)
break
}
start = res[len(res)-1].Mid
}
}
func (s *Service) checkQQ(a *model.AsoAccountSns) (err error) {
sns, err := s.d.SnsUserByMid(context.Background(), a.Mid, model.PlatformQQ)
if err != nil {
return
}
if a.QQOpenid == "" {
if sns != nil {
log.Error("qq not match, old is nil,old(%+v) new(%+v)", a, sns)
if _, err = s.d.DelSnsUser(context.Background(), a.Mid, model.PlatformQQ); err != nil {
return
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.DelSnsCache(c, a.Mid, model.PlatformQQStr)
})
}
return
}
qqUnionID, err := s.d.QQUnionID(context.Background(), a.QQOpenid)
if err != nil || qqUnionID == "" {
return
}
if sns == nil {
log.Error("qq not match, new not exists, old(%+v), ", a)
if _, err = s.d.AddSnsUser(context.Background(), a.Mid, a.QQAccessExpires, qqUnionID, model.PlatformQQ); err != nil {
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
log.Error("checkQQ, add qq duplicate, mid(%d) unionid(%s)", a.Mid, qqUnionID)
err = nil
//var (
// u *model.SnsUser
// aso *model.AsoAccountSns
//)
//if u, err = s.d.SnsUserByUnionID(context.Background(), qqUnionID, model.PlatformQQ); err != nil {
// return
//}
//if _, err = s.d.DelSnsUser(context.Background(), u.Mid, model.PlatformQQ); err != nil {
// return
//}
//if _, err = s.d.AddSnsUser(context.Background(), a.Mid, a.QQAccessExpires, qqUnionID, model.PlatformQQ); err != nil {
// return
//}
//if aso, err = s.d.AsoAccountSnsByMid(context.Background(), u.Mid); err != nil {
// return
//}
//if qqUnionID, err = s.d.QQUnionID(context.Background(), a.QQOpenid); err != nil {
// return
//}
//if _, err = s.d.AddSnsUser(context.Background(), aso.Mid, aso.QQAccessExpires, qqUnionID, model.PlatformQQ); err != nil {
// return
//}
}
}
return
}
} else if sns.UnionID != qqUnionID {
log.Error("qq not match, new(%s), mid(%d) oldOpenID(%s) oldUnionID(%s) ", sns.UnionID, a.Mid, a.QQOpenid, qqUnionID)
if _, err = s.d.UpdateSnsUser(context.Background(), a.Mid, a.QQAccessExpires, qqUnionID, model.PlatformQQ); err != nil {
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
log.Error("checkQQ, update qq duplicate, mid(%d) unionid(%s)", a.Mid, qqUnionID)
err = nil
//var (
// u *model.SnsUser
// aso *model.AsoAccountSns
//)
//if u, err = s.d.SnsUserByUnionID(context.Background(), qqUnionID, model.PlatformQQ); err != nil {
// return
//}
//if _, err = s.d.DelSnsUser(context.Background(), u.Mid, model.PlatformQQ); err != nil {
// return
//}
//if _, err = s.d.UpdateSnsUser(context.Background(), a.Mid, a.QQAccessExpires, qqUnionID, model.PlatformQQ); err != nil {
// return
//}
//if aso, err = s.d.AsoAccountSnsByMid(context.Background(), u.Mid); err != nil {
// return
//}
//if qqUnionID, err = s.d.QQUnionID(context.Background(), a.QQOpenid); err != nil {
// return
//}
//if _, err = s.d.AddSnsUser(context.Background(), aso.Mid, aso.QQAccessExpires, qqUnionID, model.PlatformQQ); err != nil {
// return
//}
}
}
return
}
} else if sns.Expires != a.QQAccessExpires {
log.Error("qq expires not match, new(%+v), old(%+v)", sns, a)
if err = s.updateSns(a.Mid, a.QQAccessExpires, a.QQOpenid, a.QQAccessToken, model.PlatformQQ); err != nil {
return
}
return
}
s.cache.Do(context.Background(), func(c context.Context) {
proto := &model.SnsProto{
Mid: a.Mid,
Platform: int32(model.PlatformQQ),
UnionID: qqUnionID,
Expires: a.QQAccessExpires,
}
s.d.SetSnsCache(c, a.Mid, model.PlatformQQStr, proto)
})
return
}
func (s *Service) checkWeibo(a *model.AsoAccountSns) (err error) {
sns, err := s.d.SnsUserByMid(context.Background(), a.Mid, model.PlatformWEIBO)
if err != nil {
return
}
if a.SinaUID == 0 {
if sns != nil {
log.Error("weibo not match, old is nil,old(%+v) new(%+v)", a, sns)
if _, err = s.d.DelSnsUser(context.Background(), a.Mid, model.PlatformWEIBO); err != nil {
return
}
s.cache.Do(context.Background(), func(c context.Context) {
s.d.DelSnsCache(c, a.Mid, model.PlatformWEIBOStr)
})
}
return
}
if sns == nil {
log.Error("weibo not match, new not exists, old(%+v)", a)
if _, err = s.d.AddSnsUser(context.Background(), a.Mid, a.SinaAccessExpires, strconv.FormatInt(a.SinaUID, 10), model.PlatformWEIBO); err != nil {
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
log.Error("checkWeibo, add weibo duplicate, mid(%d) unionid(%s)", a.Mid, strconv.FormatInt(a.SinaUID, 10))
err = nil
//var (
// u *model.SnsUser
// aso *model.AsoAccountSns
//)
//if u, err = s.d.SnsUserByUnionID(context.Background(), strconv.FormatInt(a.SinaUID, 10), model.PlatformWEIBO); err != nil {
// return
//}
//if _, err = s.d.DelSnsUser(context.Background(), u.Mid, model.PlatformWEIBO); err != nil {
// return
//}
//if _, err = s.d.AddSnsUser(context.Background(), a.Mid, a.SinaAccessExpires, strconv.FormatInt(a.SinaUID, 10), model.PlatformWEIBO); err != nil {
// return
//}
//if aso, err = s.d.AsoAccountSnsByMid(context.Background(), u.Mid); err != nil {
// return
//}
//if _, err = s.d.AddSnsUser(context.Background(), aso.Mid, aso.SinaAccessExpires, strconv.FormatInt(aso.SinaUID, 10), model.PlatformWEIBO); err != nil {
// return
//}
}
}
return
}
} else if sns.UnionID != strconv.FormatInt(a.SinaUID, 10) {
log.Error("weibo not match, new(%s), mid(%d) old(%d)", sns.UnionID, a.Mid, a.SinaUID)
if _, err = s.d.UpdateSnsUser(context.Background(), a.Mid, a.SinaAccessExpires, strconv.FormatInt(a.SinaUID, 10), model.PlatformWEIBO); err != nil {
switch nErr := errors.Cause(err).(type) {
case *mysql.MySQLError:
if nErr.Number == _mySQLErrCodeDuplicateEntry {
log.Error("checkWeibo, update weibo duplicate, mid(%d) unionid(%s)", a.Mid, strconv.FormatInt(a.SinaUID, 10))
err = nil
//var (
// u *model.SnsUser
// aso *model.AsoAccountSns
//)
//if u, err = s.d.SnsUserByUnionID(context.Background(), strconv.FormatInt(a.SinaUID, 10), model.PlatformWEIBO); err != nil {
// return
//}
//if _, err = s.d.DelSnsUser(context.Background(), u.Mid, model.PlatformWEIBO); err != nil {
// return
//}
//if _, err = s.d.UpdateSnsUser(context.Background(), a.Mid, a.SinaAccessExpires, strconv.FormatInt(a.SinaUID, 10), model.PlatformWEIBO); err != nil {
// return
//}
//if aso, err = s.d.AsoAccountSnsByMid(context.Background(), u.Mid); err != nil {
// return
//}
//if _, err = s.d.AddSnsUser(context.Background(), aso.Mid, aso.SinaAccessExpires, strconv.FormatInt(aso.SinaUID, 10), model.PlatformWEIBO); err != nil {
// return
//}
}
}
return
}
} else if sns.Expires != a.SinaAccessExpires {
log.Error("weibo expires not match, new(%+v), old(%+v)", sns, a)
if err = s.updateSns(a.Mid, a.SinaAccessExpires, strconv.FormatInt(a.SinaUID, 10), a.SinaAccessToken, model.PlatformWEIBO); err != nil {
return
}
return
}
s.cache.Do(context.Background(), func(c context.Context) {
proto := &model.SnsProto{
Mid: a.Mid,
Platform: int32(model.PlatformWEIBO),
UnionID: strconv.FormatInt(a.SinaUID, 10),
Expires: a.SinaAccessExpires,
}
s.d.SetSnsCache(c, a.Mid, model.PlatformWEIBOStr, proto)
})
return
}