add uid generate
This commit is contained in:
parent
518cb03b4b
commit
5aff70ae2f
18
Makefile
18
Makefile
|
@ -47,3 +47,21 @@ build-docker:
|
|||
docker buildx build -t $(DOCKER_REPO):$(VERSION) --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/ed_25519)" .
|
||||
rm -rf Dockerfile
|
||||
@echo "Generate core-api files successfully"
|
||||
|
||||
.PHONY: gen-model
|
||||
gen-model: # 建立 rpc 資料庫
|
||||
goctl model mysql ddl -c no -s ./generate/database/mysql/20230529020011_account_table.up.sql --style go_zero -d ./internal/model -i ''
|
||||
goctl model mysql ddl -c no -s ./generate/database/mysql/20230529020011_account_uid_table.up.sql --style go_zero -d ./internal/model -i ''
|
||||
goctl model mysql ddl -c no -s ./generate/database/mysql/20230529020011_user_table.up.sql --style go_zero -d ./internal/model -i ''
|
||||
goctl model mysql ddl -c no -s ./generate/database/mysql/20230719061241_machine_node.up.sql --style go_zero -d ./internal/model -i ''
|
||||
@echo "Generate model files successfully"
|
||||
# 只產生 Model 剩下的要自己撰寫,連欄位名稱也是
|
||||
goctl model mongo -t AutoId -c --dir ./internal/model/mongo --style go_zero
|
||||
|
||||
#goctl model mysql ddl -s ./generate/database/mysql/20240819090248_create_role_permission_table.up.sql --style go_zero -d ./internal/model -i '' (沒cache)
|
||||
#goctl model mysql ddl -c no -s ./generate/database/mysql/20240816014305_create_permission_table.up.sql --style go_zero -d ./internal/model -i '' (有cache)
|
||||
|
||||
#.PHONY: mock-gen
|
||||
#mock-gen: # 建立 mock 資料
|
||||
# mockgen -source=./order.go -destination=../../repository/mock/order.go -package=mock
|
||||
# @echo "Generate model files successfully"
|
|
@ -3,6 +3,11 @@ syntax = "proto3";
|
|||
package member;
|
||||
option go_package="./member";
|
||||
|
||||
// OKResp
|
||||
message OKResp {}
|
||||
// NoneReq
|
||||
message NoneReq {}
|
||||
|
||||
// ================ enum ================
|
||||
enum VerifyType {
|
||||
VERIFY_NONE = 0; // 初始(異常)
|
||||
|
@ -27,11 +32,6 @@ enum MemberStatus {
|
|||
STATUS_GA = 6; // GA 已綁定
|
||||
}
|
||||
|
||||
enum Gender {
|
||||
GENDER_NONE = 0; // 初始(未提供)
|
||||
GENDER_MALE = 1; // 男性
|
||||
GENDER_FEMALE = 2; // 女性
|
||||
}
|
||||
// ================ enum ================
|
||||
|
||||
|
||||
|
@ -41,17 +41,6 @@ message Pager {
|
|||
int64 size=2;
|
||||
int64 index=3;
|
||||
}
|
||||
|
||||
message Response {
|
||||
BaseResp status=1;
|
||||
}
|
||||
|
||||
message BaseResp {
|
||||
string code = 1;
|
||||
string message = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
// ================ common ================
|
||||
|
||||
|
||||
|
@ -81,8 +70,7 @@ message CreateUserInfoReq {
|
|||
}
|
||||
|
||||
message GetAccountInfoResp {
|
||||
BaseResp status = 1;
|
||||
CreateLoginUserReq data = 2;
|
||||
CreateLoginUserReq data = 1;
|
||||
}
|
||||
|
||||
// UpdateUserInfoReq 不處理邏輯給不給改,這裡只關新增修改刪除
|
||||
|
@ -91,24 +79,18 @@ message UpdateUserInfoReq {
|
|||
optional string language = 2;
|
||||
optional string currency = 3;
|
||||
optional string nick_name = 4;
|
||||
optional uint32 gender = 5;
|
||||
optional int64 birthday = 6;
|
||||
optional VerifyType verify_type = 7;
|
||||
optional AlarmType alarm_type = 8;
|
||||
optional MemberStatus status = 9;
|
||||
optional VerifyType verify_type = 5;
|
||||
optional AlarmType alarm_type = 6;
|
||||
optional MemberStatus status = 7;
|
||||
}
|
||||
|
||||
message GetUIDByAccountReq {
|
||||
string account = 1;
|
||||
}
|
||||
|
||||
message UID {
|
||||
string uid = 1;
|
||||
}
|
||||
|
||||
message GetUidByAccountResp {
|
||||
BaseResp status = 1;
|
||||
UID data = 2;
|
||||
string uid = 1;
|
||||
string account =2;
|
||||
}
|
||||
|
||||
message UpdateTokenReq {
|
||||
|
@ -126,8 +108,7 @@ message VerifyCode {
|
|||
}
|
||||
|
||||
message GenerateRefreshCodeResp {
|
||||
BaseResp status = 1;
|
||||
VerifyCode data = 2;
|
||||
VerifyCode data = 1;
|
||||
}
|
||||
|
||||
message VerifyRefreshCodeReq {
|
||||
|
@ -158,8 +139,7 @@ message UserInfo {
|
|||
}
|
||||
|
||||
message GetUserInfoResp {
|
||||
BaseResp status = 1;
|
||||
UserInfo data = 2;
|
||||
UserInfo data = 1;
|
||||
}
|
||||
|
||||
message ListUserInfoReq {
|
||||
|
@ -173,29 +153,28 @@ message ListUserInfoReq {
|
|||
}
|
||||
|
||||
message ListUserInfoResp {
|
||||
BaseResp status = 1;
|
||||
repeated UserInfo data = 2;
|
||||
Pager page =3;
|
||||
repeated UserInfo data = 1;
|
||||
Pager page =2;
|
||||
}
|
||||
|
||||
|
||||
service Account {
|
||||
// CreateUserAccount 建立帳號與密碼 -> 可登入,但可不可以做其他事情看業務流程,也可以只註冊就好
|
||||
rpc CreateUserAccount(CreateLoginUserReq) returns(Response);
|
||||
rpc CreateUserAccount(CreateLoginUserReq) returns(OKResp);
|
||||
// GetUserAccountInfo 取得帳號密碼資料
|
||||
rpc GetUserAccountInfo(GetUIDByAccountReq) returns(GetAccountInfoResp);
|
||||
// UpdateUserToken 更新密碼
|
||||
rpc UpdateUserToken(UpdateTokenReq) returns(Response);
|
||||
rpc UpdateUserToken(UpdateTokenReq) returns(OKResp);
|
||||
// GetUidByAccount 用帳號換取 UID
|
||||
rpc GetUidByAccount(GetUIDByAccountReq) returns(GetUidByAccountResp);
|
||||
// BindAccount 綁定帳號 -> account bind to UID
|
||||
rpc BindAccount(BindingUserReq) returns(Response);
|
||||
rpc BindAccount(BindingUserReq) returns(OKResp);
|
||||
// BindUserInfo 初次,綁定 User Info
|
||||
rpc BindUserInfo(CreateUserInfoReq) returns(Response);
|
||||
rpc BindUserInfo(CreateUserInfoReq) returns(OKResp);
|
||||
// UpdateUserInfo 更新 User Info
|
||||
rpc UpdateUserInfo(UpdateUserInfoReq) returns(Response);
|
||||
rpc UpdateUserInfo(UpdateUserInfoReq) returns(OKResp);
|
||||
// UpdateStatus 修改狀態
|
||||
rpc UpdateStatus(UpdateStatusReq) returns(Response);
|
||||
rpc UpdateStatus(UpdateStatusReq) returns(OKResp);
|
||||
// GetUserInfo 取得會員資訊
|
||||
rpc GetUserInfo(GetUserInfoReq) returns(GetUserInfoResp);
|
||||
// ListMember 取得會員列表
|
||||
|
@ -203,7 +182,7 @@ service Account {
|
|||
// GenerateRefreshCode 這個帳號驗證碼(十分鐘),通用的
|
||||
rpc GenerateRefreshCode(GenerateRefreshCodeReq) returns(GenerateRefreshCodeResp);
|
||||
// VerifyRefreshCode 驗證忘記密碼 token
|
||||
rpc VerifyRefreshCode(VerifyRefreshCodeReq) returns(Response);
|
||||
rpc VerifyRefreshCode(VerifyRefreshCodeReq) returns(OKResp);
|
||||
|
||||
}
|
||||
// ================ account ================
|
12
go.mod
12
go.mod
|
@ -3,12 +3,17 @@ module app-cloudep-member-server
|
|||
go 1.22.3
|
||||
|
||||
require (
|
||||
code.30cm.net/digimon/library-go/errors v1.0.1
|
||||
code.30cm.net/digimon/library-go/validator v1.0.0
|
||||
github.com/bwmarrin/snowflake v0.3.0
|
||||
github.com/zeromicro/go-zero v1.7.0
|
||||
go.uber.org/goleak v1.3.0
|
||||
google.golang.org/grpc v1.65.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
|
@ -18,11 +23,16 @@ require (
|
|||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.4 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
|
@ -33,6 +43,7 @@ require (
|
|||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
|
@ -65,6 +76,7 @@ require (
|
|||
go.uber.org/automaxprocs v1.5.3 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.25.0 // indirect
|
||||
golang.org/x/net v0.27.0 // indirect
|
||||
golang.org/x/oauth2 v0.20.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
|
|
|
@ -1,7 +1,33 @@
|
|||
package config
|
||||
|
||||
import "github.com/zeromicro/go-zero/zrpc"
|
||||
import (
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
"github.com/zeromicro/go-zero/zrpc"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
zrpc.RpcServerConf
|
||||
// 加上 DB 結構體
|
||||
DB struct {
|
||||
DsnString string
|
||||
}
|
||||
// 快取
|
||||
Cache cache.CacheConf
|
||||
// 密碼加密層數
|
||||
Bcrypt struct {
|
||||
Cost int
|
||||
}
|
||||
// Redis Cluster
|
||||
RedisCluster redis.RedisConf
|
||||
|
||||
Mongo struct {
|
||||
Schema string
|
||||
User string
|
||||
Password string
|
||||
Host string
|
||||
Port string
|
||||
Database string
|
||||
Collection string
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package domain
|
||||
|
||||
const (
|
||||
DefaultPageSize = 100
|
||||
DefaultPageIndex = 1
|
||||
Scope = 10
|
||||
)
|
||||
|
||||
const InitAutoId = 1000000
|
||||
const DefaultReferralCodeLen = 8
|
||||
|
||||
var ConvertTable = [...]string{
|
||||
"O", "D", "W", "X", "Y",
|
||||
"G", "B", "C", "H", "E",
|
||||
"F", "A", "Q", "I", "J",
|
||||
"L", "M", "N", "Z", "K",
|
||||
"P", "V", "R", "S", "T",
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package usecase
|
||||
|
||||
import (
|
||||
ers "code.30cm.net/digimon/library-go/errors"
|
||||
"code.30cm.net/digimon/library-go/errors/code"
|
||||
)
|
||||
|
||||
// 12 represents Scope
|
||||
// 100 represents Category
|
||||
// 9 represents Detail error code
|
||||
// full code 12009 只會有 系統以及錯誤碼,category 是給系統判定用的
|
||||
// 目前 Scope 以及分類要系統共用,係向的錯誤各自服務實作就好
|
||||
|
||||
const (
|
||||
UIDOutOfRangeErrorCode = iota + 1
|
||||
)
|
||||
|
||||
// UIDOutOfRangeErrorCodeError 20001 Token 簽名錯誤
|
||||
func UIDOutOfRangeErrorCodeError(msg string) *ers.LibError {
|
||||
return ers.NewErr(code.CloudEPMember, code.CatInput, UIDOutOfRangeErrorCode, msg)
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package usecase
|
||||
|
||||
import "context"
|
||||
|
||||
type UIDGenerateUseCase interface {
|
||||
Generate(ctx context.Context) (string, error)
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
ers "code.30cm.net/digimon/library-go/errors"
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultTimeout = 30 * time.Second
|
||||
|
||||
func TimeoutMiddleware(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
|
||||
|
||||
newCtx, cancelCtx := context.WithTimeout(ctx, defaultTimeout)
|
||||
defer func() {
|
||||
cancelCtx()
|
||||
|
||||
if errors.Is(newCtx.Err(), context.DeadlineExceeded) {
|
||||
err = ers.SystemTimeoutError(info.FullMethod)
|
||||
logx.Errorf("Method: %s, request %v, timeout: %d", info.FullMethod, req, defaultTimeout)
|
||||
}
|
||||
}()
|
||||
|
||||
return handler(ctx, req)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package snowflake
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NewNodeError struct {
|
||||
machineNodeID int64
|
||||
startTime time.Time
|
||||
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *NewNodeError) Error() string {
|
||||
return fmt.Sprintf("new node fail machineNodeID: %d, startTime: %s, err: %v",
|
||||
e.machineNodeID, e.startTime, e.Err)
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package snowflake
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNewNodeError_Error(t *testing.T) {
|
||||
startTime, err := time.Parse(time.DateOnly, "2023-07-20")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
machineNodeID int64
|
||||
startTime time.Time
|
||||
Err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
fields: fields{
|
||||
machineNodeID: 1,
|
||||
startTime: startTime,
|
||||
Err: nil,
|
||||
},
|
||||
want: fmt.Sprintf("new node fail machineNodeID: %d, startTime: %s, err: %v",
|
||||
1, "2023-07-20 00:00:00 +0000 UTC", nil),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
e := &NewNodeError{
|
||||
machineNodeID: tt.fields.machineNodeID,
|
||||
startTime: tt.fields.startTime,
|
||||
Err: tt.fields.Err,
|
||||
}
|
||||
if got := e.Error(); got != tt.want {
|
||||
t.Errorf("Error() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
###
|
||||
# snowflake
|
||||
|
||||
```go
|
||||
import "yt.com/backend/common.git/snowflake"
|
||||
```
|
||||
|
||||
### 量級超過1024 再來做解決
|
|
@ -0,0 +1,81 @@
|
|||
package snowflake
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/snowflake"
|
||||
)
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
// Snowflake provides a way to NewNode for Generate UID.
|
||||
type Snowflake struct {
|
||||
machineNodeID int64
|
||||
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
// Option is the options type to configure Snowflake.
|
||||
type Option func(*Snowflake)
|
||||
|
||||
// New returns a new Snowflake instance with the provided options.
|
||||
func New(opts ...Option) *Snowflake {
|
||||
s := &Snowflake{
|
||||
// default machine 1
|
||||
machineNodeID: 1,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// WithMachineNodeID adds machineID total 10bit = 1024 machine number.
|
||||
func WithMachineNodeID(machineNodeID int64) Option {
|
||||
return func(snowflake *Snowflake) {
|
||||
snowflake.machineNodeID = machineNodeID
|
||||
}
|
||||
}
|
||||
|
||||
// WithStartTime adds snowflake start timestamp in milliseconds.
|
||||
func WithStartTime(startTime time.Time) Option {
|
||||
return func(snowflake *Snowflake) {
|
||||
snowflake.startTime = startTime
|
||||
}
|
||||
}
|
||||
|
||||
// GetNowDate return nowTodayDate e.g. 2023-07-20 00:00:00 +0000 UTC.
|
||||
func GetNowDate() (time.Time, error) {
|
||||
startTime := time.Now().UTC().Format(time.DateOnly)
|
||||
|
||||
st, err := time.Parse(time.DateOnly, startTime)
|
||||
if err != nil {
|
||||
return time.Time{}, fmt.Errorf("time.Parse failed :%w", err)
|
||||
}
|
||||
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// NewNode return snowflake node use Generate UID.
|
||||
func (s *Snowflake) NewNode() (*snowflake.Node, error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
snowflake.Epoch = s.startTime.UnixMilli()
|
||||
|
||||
node, err := snowflake.NewNode(s.machineNodeID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("snowflake.NewNode, failed :%w",
|
||||
&NewNodeError{
|
||||
machineNodeID: s.machineNodeID,
|
||||
startTime: s.startTime,
|
||||
Err: err,
|
||||
})
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package snowflake
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go.uber.org/goleak"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
leak := flag.Bool("leak", false, "use leak detector")
|
||||
flag.Parse()
|
||||
|
||||
if *leak {
|
||||
goleak.VerifyTestMain(m)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestSnowflake(t *testing.T) {
|
||||
st, err := GetNowDate()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
machineNodeID int64
|
||||
startTime time.Time
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *Snowflake
|
||||
|
||||
wantDeepEqualErr bool
|
||||
wantNewNodeErr bool
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
args: args{
|
||||
machineNodeID: 10,
|
||||
startTime: st,
|
||||
},
|
||||
want: &Snowflake{
|
||||
machineNodeID: 10,
|
||||
startTime: st,
|
||||
},
|
||||
wantDeepEqualErr: false,
|
||||
wantNewNodeErr: false,
|
||||
},
|
||||
{
|
||||
name: "failed machine node ID negative number",
|
||||
args: args{
|
||||
machineNodeID: -1,
|
||||
startTime: time.Time{},
|
||||
},
|
||||
want: &Snowflake{
|
||||
machineNodeID: -1,
|
||||
startTime: time.Time{},
|
||||
},
|
||||
wantDeepEqualErr: false,
|
||||
wantNewNodeErr: true,
|
||||
},
|
||||
{
|
||||
name: "failed snowflake struct field by machine node ID",
|
||||
args: args{
|
||||
machineNodeID: 10,
|
||||
startTime: st,
|
||||
},
|
||||
want: &Snowflake{
|
||||
machineNodeID: 2,
|
||||
startTime: st,
|
||||
},
|
||||
wantDeepEqualErr: true,
|
||||
wantNewNodeErr: false,
|
||||
},
|
||||
{
|
||||
name: "failed snowflake struct field by startTime",
|
||||
args: args{
|
||||
machineNodeID: 2,
|
||||
startTime: st,
|
||||
},
|
||||
want: &Snowflake{
|
||||
machineNodeID: 2,
|
||||
startTime: time.Time{},
|
||||
},
|
||||
wantDeepEqualErr: true,
|
||||
wantNewNodeErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := New(
|
||||
WithMachineNodeID(tt.args.machineNodeID),
|
||||
WithStartTime(tt.args.startTime),
|
||||
)
|
||||
|
||||
if !reflect.DeepEqual(got, tt.want) != tt.wantDeepEqualErr {
|
||||
t.Errorf("Snowflake.New() = %v, want %v", got, tt.want)
|
||||
}
|
||||
|
||||
node, err := got.NewNode()
|
||||
if (err != nil) != tt.wantNewNodeErr {
|
||||
t.Errorf("NewNode() = %v, want %v", err != nil, tt.wantNewNodeErr)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
id := node.Generate().Int64()
|
||||
if id <= 0 {
|
||||
t.Errorf("node.Generate().Int64() = %v, want %s", id, "id > 0")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSnowflake(b *testing.B) {
|
||||
st, err := GetNowDate()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
snowflake := New(
|
||||
WithMachineNodeID(1),
|
||||
WithStartTime(st),
|
||||
)
|
||||
|
||||
node, err := snowflake.NewNode()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
node.Generate().Int64()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var _ AccountModel = (*customAccountModel)(nil)
|
||||
|
||||
type (
|
||||
// AccountModel is an interface to be customized, add more methods here,
|
||||
// and implement the added methods in customAccountModel.
|
||||
AccountModel interface {
|
||||
accountModel
|
||||
}
|
||||
|
||||
customAccountModel struct {
|
||||
*defaultAccountModel
|
||||
}
|
||||
)
|
||||
|
||||
// NewAccountModel returns a model for the database table.
|
||||
func NewAccountModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) AccountModel {
|
||||
return &customAccountModel{
|
||||
defaultAccountModel: newAccountModel(conn, c, opts...),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/core/stringx"
|
||||
)
|
||||
|
||||
var (
|
||||
accountFieldNames = builder.RawFieldNames(&Account{})
|
||||
accountRows = strings.Join(accountFieldNames, ",")
|
||||
accountRowsExpectAutoSet = strings.Join(stringx.Remove(accountFieldNames, "`id`"), ",")
|
||||
accountRowsWithPlaceHolder = strings.Join(stringx.Remove(accountFieldNames, "`id`"), "=?,") + "=?"
|
||||
|
||||
cacheAccountIdPrefix = "cache:account:id:"
|
||||
cacheAccountAccountPrefix = "cache:account:account:"
|
||||
)
|
||||
|
||||
type (
|
||||
accountModel interface {
|
||||
Insert(ctx context.Context, data *Account) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*Account, error)
|
||||
FindOneByAccount(ctx context.Context, account string) (*Account, error)
|
||||
Update(ctx context.Context, data *Account) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
defaultAccountModel struct {
|
||||
sqlc.CachedConn
|
||||
table string
|
||||
}
|
||||
|
||||
Account struct {
|
||||
Id int64 `db:"id"`
|
||||
Account string `db:"account"`
|
||||
Token string `db:"token"`
|
||||
Platform int64 `db:"platform"` // 平台類型 1. ark 2. google
|
||||
CreateTime int64 `db:"create_time"`
|
||||
UpdateTime int64 `db:"update_time"`
|
||||
}
|
||||
)
|
||||
|
||||
func newAccountModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultAccountModel {
|
||||
return &defaultAccountModel{
|
||||
CachedConn: sqlc.NewConn(conn, c, opts...),
|
||||
table: "`account`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) withSession(session sqlx.Session) *defaultAccountModel {
|
||||
return &defaultAccountModel{
|
||||
CachedConn: m.CachedConn.WithSession(session),
|
||||
table: "`account`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) Delete(ctx context.Context, id int64) error {
|
||||
data, err := m.FindOne(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, data.Account)
|
||||
accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, id)
|
||||
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||
return conn.ExecCtx(ctx, query, id)
|
||||
}, accountAccountKey, accountIdKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) FindOne(ctx context.Context, id int64) (*Account, error) {
|
||||
accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, id)
|
||||
var resp Account
|
||||
err := m.QueryRowCtx(ctx, &resp, accountIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", accountRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, id)
|
||||
})
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) FindOneByAccount(ctx context.Context, account string) (*Account, error) {
|
||||
accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, account)
|
||||
var resp Account
|
||||
err := m.QueryRowIndexCtx(ctx, &resp, accountAccountKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) {
|
||||
query := fmt.Sprintf("select %s from %s where `account` = ? limit 1", accountRows, m.table)
|
||||
if err := conn.QueryRowCtx(ctx, &resp, query, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Id, nil
|
||||
}, m.queryPrimary)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) Insert(ctx context.Context, data *Account) (sql.Result, error) {
|
||||
accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, data.Account)
|
||||
accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, data.Id)
|
||||
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, accountRowsExpectAutoSet)
|
||||
return conn.ExecCtx(ctx, query, data.Account, data.Token, data.Platform, data.CreateTime, data.UpdateTime)
|
||||
}, accountAccountKey, accountIdKey)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) Update(ctx context.Context, newData *Account) error {
|
||||
data, err := m.FindOne(ctx, newData.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, data.Account)
|
||||
accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, data.Id)
|
||||
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, accountRowsWithPlaceHolder)
|
||||
return conn.ExecCtx(ctx, query, newData.Account, newData.Token, newData.Platform, newData.CreateTime, newData.UpdateTime, newData.Id)
|
||||
}, accountAccountKey, accountIdKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) formatPrimary(primary any) string {
|
||||
return fmt.Sprintf("%s%v", cacheAccountIdPrefix, primary)
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", accountRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, primary)
|
||||
}
|
||||
|
||||
func (m *defaultAccountModel) tableName() string {
|
||||
return m.table
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var _ AccountToUidModel = (*customAccountToUidModel)(nil)
|
||||
|
||||
type (
|
||||
// AccountToUidModel is an interface to be customized, add more methods here,
|
||||
// and implement the added methods in customAccountToUidModel.
|
||||
AccountToUidModel interface {
|
||||
accountToUidModel
|
||||
}
|
||||
|
||||
customAccountToUidModel struct {
|
||||
*defaultAccountToUidModel
|
||||
}
|
||||
)
|
||||
|
||||
// NewAccountToUidModel returns a model for the database table.
|
||||
func NewAccountToUidModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) AccountToUidModel {
|
||||
return &customAccountToUidModel{
|
||||
defaultAccountToUidModel: newAccountToUidModel(conn, c, opts...),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/core/stringx"
|
||||
)
|
||||
|
||||
var (
|
||||
accountToUidFieldNames = builder.RawFieldNames(&AccountToUid{})
|
||||
accountToUidRows = strings.Join(accountToUidFieldNames, ",")
|
||||
accountToUidRowsExpectAutoSet = strings.Join(stringx.Remove(accountToUidFieldNames, "`id`"), ",")
|
||||
accountToUidRowsWithPlaceHolder = strings.Join(stringx.Remove(accountToUidFieldNames, "`id`"), "=?,") + "=?"
|
||||
|
||||
cacheAccountToUidIdPrefix = "cache:accountToUid:id:"
|
||||
cacheAccountToUidAccountPrefix = "cache:accountToUid:account:"
|
||||
)
|
||||
|
||||
type (
|
||||
accountToUidModel interface {
|
||||
Insert(ctx context.Context, data *AccountToUid) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*AccountToUid, error)
|
||||
FindOneByAccount(ctx context.Context, account string) (*AccountToUid, error)
|
||||
Update(ctx context.Context, data *AccountToUid) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
defaultAccountToUidModel struct {
|
||||
sqlc.CachedConn
|
||||
table string
|
||||
}
|
||||
|
||||
AccountToUid struct {
|
||||
Id int64 `db:"id"`
|
||||
Account string `db:"account"`
|
||||
Uid string `db:"uid"`
|
||||
Type int64 `db:"type"` // 1 手機 2 信箱 3 自定義帳號
|
||||
}
|
||||
)
|
||||
|
||||
func newAccountToUidModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultAccountToUidModel {
|
||||
return &defaultAccountToUidModel{
|
||||
CachedConn: sqlc.NewConn(conn, c, opts...),
|
||||
table: "`account_to_uid`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) withSession(session sqlx.Session) *defaultAccountToUidModel {
|
||||
return &defaultAccountToUidModel{
|
||||
CachedConn: m.CachedConn.WithSession(session),
|
||||
table: "`account_to_uid`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) Delete(ctx context.Context, id int64) error {
|
||||
data, err := m.FindOne(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accountToUidAccountKey := fmt.Sprintf("%s%v", cacheAccountToUidAccountPrefix, data.Account)
|
||||
accountToUidIdKey := fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, id)
|
||||
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||
return conn.ExecCtx(ctx, query, id)
|
||||
}, accountToUidAccountKey, accountToUidIdKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) FindOne(ctx context.Context, id int64) (*AccountToUid, error) {
|
||||
accountToUidIdKey := fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, id)
|
||||
var resp AccountToUid
|
||||
err := m.QueryRowCtx(ctx, &resp, accountToUidIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", accountToUidRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, id)
|
||||
})
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) FindOneByAccount(ctx context.Context, account string) (*AccountToUid, error) {
|
||||
accountToUidAccountKey := fmt.Sprintf("%s%v", cacheAccountToUidAccountPrefix, account)
|
||||
var resp AccountToUid
|
||||
err := m.QueryRowIndexCtx(ctx, &resp, accountToUidAccountKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) {
|
||||
query := fmt.Sprintf("select %s from %s where `account` = ? limit 1", accountToUidRows, m.table)
|
||||
if err := conn.QueryRowCtx(ctx, &resp, query, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Id, nil
|
||||
}, m.queryPrimary)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) Insert(ctx context.Context, data *AccountToUid) (sql.Result, error) {
|
||||
accountToUidAccountKey := fmt.Sprintf("%s%v", cacheAccountToUidAccountPrefix, data.Account)
|
||||
accountToUidIdKey := fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, data.Id)
|
||||
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, accountToUidRowsExpectAutoSet)
|
||||
return conn.ExecCtx(ctx, query, data.Account, data.Uid, data.Type)
|
||||
}, accountToUidAccountKey, accountToUidIdKey)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) Update(ctx context.Context, newData *AccountToUid) error {
|
||||
data, err := m.FindOne(ctx, newData.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accountToUidAccountKey := fmt.Sprintf("%s%v", cacheAccountToUidAccountPrefix, data.Account)
|
||||
accountToUidIdKey := fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, data.Id)
|
||||
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, accountToUidRowsWithPlaceHolder)
|
||||
return conn.ExecCtx(ctx, query, newData.Account, newData.Uid, newData.Type, newData.Id)
|
||||
}, accountToUidAccountKey, accountToUidIdKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) formatPrimary(primary any) string {
|
||||
return fmt.Sprintf("%s%v", cacheAccountToUidIdPrefix, primary)
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", accountToUidRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, primary)
|
||||
}
|
||||
|
||||
func (m *defaultAccountToUidModel) tableName() string {
|
||||
return m.table
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var _ MachineNodeModel = (*customMachineNodeModel)(nil)
|
||||
|
||||
type (
|
||||
// MachineNodeModel is an interface to be customized, add more methods here,
|
||||
// and implement the added methods in customMachineNodeModel.
|
||||
MachineNodeModel interface {
|
||||
machineNodeModel
|
||||
}
|
||||
|
||||
customMachineNodeModel struct {
|
||||
*defaultMachineNodeModel
|
||||
}
|
||||
)
|
||||
|
||||
// NewMachineNodeModel returns a model for the database table.
|
||||
func NewMachineNodeModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) MachineNodeModel {
|
||||
return &customMachineNodeModel{
|
||||
defaultMachineNodeModel: newMachineNodeModel(conn, c, opts...),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/core/stringx"
|
||||
)
|
||||
|
||||
var (
|
||||
machineNodeFieldNames = builder.RawFieldNames(&MachineNode{})
|
||||
machineNodeRows = strings.Join(machineNodeFieldNames, ",")
|
||||
machineNodeRowsExpectAutoSet = strings.Join(stringx.Remove(machineNodeFieldNames, "`id`"), ",")
|
||||
machineNodeRowsWithPlaceHolder = strings.Join(stringx.Remove(machineNodeFieldNames, "`id`"), "=?,") + "=?"
|
||||
|
||||
cacheMachineNodeIdPrefix = "cache:machineNode:id:"
|
||||
)
|
||||
|
||||
type (
|
||||
machineNodeModel interface {
|
||||
Insert(ctx context.Context, data *MachineNode) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*MachineNode, error)
|
||||
Update(ctx context.Context, data *MachineNode) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
defaultMachineNodeModel struct {
|
||||
sqlc.CachedConn
|
||||
table string
|
||||
}
|
||||
|
||||
MachineNode struct {
|
||||
Id int64 `db:"id"` // 流水號
|
||||
CreateTime int64 `db:"create_time"` // 創建時間
|
||||
UpdateTime int64 `db:"update_time"` // 更新時間
|
||||
HostName string `db:"host_name"` // host name
|
||||
}
|
||||
)
|
||||
|
||||
func newMachineNodeModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultMachineNodeModel {
|
||||
return &defaultMachineNodeModel{
|
||||
CachedConn: sqlc.NewConn(conn, c, opts...),
|
||||
table: "`machine_node`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultMachineNodeModel) withSession(session sqlx.Session) *defaultMachineNodeModel {
|
||||
return &defaultMachineNodeModel{
|
||||
CachedConn: m.CachedConn.WithSession(session),
|
||||
table: "`machine_node`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultMachineNodeModel) Delete(ctx context.Context, id int64) error {
|
||||
machineNodeIdKey := fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, id)
|
||||
_, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||
return conn.ExecCtx(ctx, query, id)
|
||||
}, machineNodeIdKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultMachineNodeModel) FindOne(ctx context.Context, id int64) (*MachineNode, error) {
|
||||
machineNodeIdKey := fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, id)
|
||||
var resp MachineNode
|
||||
err := m.QueryRowCtx(ctx, &resp, machineNodeIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", machineNodeRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, id)
|
||||
})
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultMachineNodeModel) Insert(ctx context.Context, data *MachineNode) (sql.Result, error) {
|
||||
machineNodeIdKey := fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, data.Id)
|
||||
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, machineNodeRowsExpectAutoSet)
|
||||
return conn.ExecCtx(ctx, query, data.CreateTime, data.UpdateTime, data.HostName)
|
||||
}, machineNodeIdKey)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *defaultMachineNodeModel) Update(ctx context.Context, data *MachineNode) error {
|
||||
machineNodeIdKey := fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, data.Id)
|
||||
_, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, machineNodeRowsWithPlaceHolder)
|
||||
return conn.ExecCtx(ctx, query, data.CreateTime, data.UpdateTime, data.HostName, data.Id)
|
||||
}, machineNodeIdKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultMachineNodeModel) formatPrimary(primary any) string {
|
||||
return fmt.Sprintf("%s%v", cacheMachineNodeIdPrefix, primary)
|
||||
}
|
||||
|
||||
func (m *defaultMachineNodeModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", machineNodeRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, primary)
|
||||
}
|
||||
|
||||
func (m *defaultMachineNodeModel) tableName() string {
|
||||
return m.table
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/monc"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
var _ AutoIdModel = (*customAutoIdModel)(nil)
|
||||
|
||||
type (
|
||||
// AutoIdModel is an interface to be customized, add more methods here,
|
||||
// and implement the added methods in customAutoIdModel.
|
||||
AutoIdModel interface {
|
||||
autoIdModel
|
||||
Inc(ctx context.Context, data *AutoId) error
|
||||
}
|
||||
|
||||
customAutoIdModel struct {
|
||||
*defaultAutoIdModel
|
||||
}
|
||||
)
|
||||
|
||||
// NewAutoIdModel returns a model for the mongo.
|
||||
func NewAutoIdModel(url, db, collection string, c cache.CacheConf) AutoIdModel {
|
||||
conn := monc.MustNewModel(url, db, collection, c)
|
||||
return &customAutoIdModel{
|
||||
defaultAutoIdModel: newDefaultAutoIdModel(conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customAutoIdModel) Inc(ctx context.Context, data *AutoId) error {
|
||||
filter := bson.M{"admin": "auto_id"}
|
||||
update := bson.M{"$inc": bson.M{"counter": 1}}
|
||||
|
||||
key := prefixAutoIdCacheKey + "count"
|
||||
|
||||
err := m.conn.FindOneAndUpdate(ctx, key, data, filter, update,
|
||||
options.FindOneAndUpdate().SetUpsert(true),
|
||||
options.FindOneAndUpdate().SetReturnDocument(options.After),
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/monc"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
var prefixAutoIdCacheKey = "cache:autoId:"
|
||||
|
||||
type autoIdModel interface {
|
||||
Insert(ctx context.Context, data *AutoId) error
|
||||
FindOne(ctx context.Context, id string) (*AutoId, error)
|
||||
Update(ctx context.Context, data *AutoId) (*mongo.UpdateResult, error)
|
||||
Delete(ctx context.Context, id string) (int64, error)
|
||||
}
|
||||
|
||||
type defaultAutoIdModel struct {
|
||||
conn *monc.Model
|
||||
}
|
||||
|
||||
func newDefaultAutoIdModel(conn *monc.Model) *defaultAutoIdModel {
|
||||
return &defaultAutoIdModel{conn: conn}
|
||||
}
|
||||
|
||||
func (m *defaultAutoIdModel) Insert(ctx context.Context, data *AutoId) error {
|
||||
if data.ID.IsZero() {
|
||||
data.ID = primitive.NewObjectID()
|
||||
data.CreateAt = time.Now()
|
||||
data.UpdateAt = time.Now()
|
||||
}
|
||||
|
||||
key := prefixAutoIdCacheKey + data.ID.Hex()
|
||||
_, err := m.conn.InsertOne(ctx, key, data)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultAutoIdModel) FindOne(ctx context.Context, id string) (*AutoId, error) {
|
||||
oid, err := primitive.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidObjectId
|
||||
}
|
||||
|
||||
var data AutoId
|
||||
key := prefixAutoIdCacheKey + id
|
||||
err = m.conn.FindOne(ctx, key, &data, bson.M{"_id": oid})
|
||||
switch err {
|
||||
case nil:
|
||||
return &data, nil
|
||||
case monc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultAutoIdModel) Update(ctx context.Context, data *AutoId) (*mongo.UpdateResult, error) {
|
||||
data.UpdateAt = time.Now()
|
||||
key := prefixAutoIdCacheKey + data.ID.Hex()
|
||||
res, err := m.conn.UpdateOne(ctx, key, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (m *defaultAutoIdModel) Delete(ctx context.Context, id string) (int64, error) {
|
||||
oid, err := primitive.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return 0, ErrInvalidObjectId
|
||||
}
|
||||
key := prefixAutoIdCacheKey + id
|
||||
res, err := m.conn.DeleteOne(ctx, key, bson.M{"_id": oid})
|
||||
return res, err
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
type AutoId struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||
Name string `bson:"name,omitempty" json:"name,omitempty"`
|
||||
Count uint64 `bson:"count,omitempty" json:"count,omitempty"`
|
||||
UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
|
||||
CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"`
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/mon"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotFound = mon.ErrNotFound
|
||||
ErrInvalidObjectId = errors.New("invalid objectId")
|
||||
)
|
|
@ -0,0 +1,27 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var _ UserTableModel = (*customUserTableModel)(nil)
|
||||
|
||||
type (
|
||||
// UserTableModel is an interface to be customized, add more methods here,
|
||||
// and implement the added methods in customUserTableModel.
|
||||
UserTableModel interface {
|
||||
userTableModel
|
||||
}
|
||||
|
||||
customUserTableModel struct {
|
||||
*defaultUserTableModel
|
||||
}
|
||||
)
|
||||
|
||||
// NewUserTableModel returns a model for the database table.
|
||||
func NewUserTableModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) UserTableModel {
|
||||
return &customUserTableModel{
|
||||
defaultUserTableModel: newUserTableModel(conn, c, opts...),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
// Code generated by goctl. DO NOT EDIT.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/core/stringx"
|
||||
)
|
||||
|
||||
var (
|
||||
userTableFieldNames = builder.RawFieldNames(&UserTable{})
|
||||
userTableRows = strings.Join(userTableFieldNames, ",")
|
||||
userTableRowsExpectAutoSet = strings.Join(stringx.Remove(userTableFieldNames, "`id`"), ",")
|
||||
userTableRowsWithPlaceHolder = strings.Join(stringx.Remove(userTableFieldNames, "`id`"), "=?,") + "=?"
|
||||
|
||||
cacheUserTableIdPrefix = "cache:userTable:id:"
|
||||
cacheUserTableUidPrefix = "cache:userTable:uid:"
|
||||
)
|
||||
|
||||
type (
|
||||
userTableModel interface {
|
||||
Insert(ctx context.Context, data *UserTable) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*UserTable, error)
|
||||
FindOneByUid(ctx context.Context, uid string) (*UserTable, error)
|
||||
Update(ctx context.Context, data *UserTable) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
defaultUserTableModel struct {
|
||||
sqlc.CachedConn
|
||||
table string
|
||||
}
|
||||
|
||||
UserTable struct {
|
||||
Id int64 `db:"id"`
|
||||
VerifyType int64 `db:"verify_type"` // 驗證類型 0. 異常 1.信箱 2.手機 3. GA 4.不驗證
|
||||
AlarmType int64 `db:"alarm_type"` // 告警狀態 0. 異常 1. 正常(未告警) 2.系統告警中
|
||||
Status int64 `db:"status"` // 會員狀態 0. 異常 1. 尚未驗證 2. 啟用 3. 停權中 4. 信箱以驗證 5. 手機以驗證 6. GA 以驗證
|
||||
Uid string `db:"uid"` // 唯一辨識碼
|
||||
NickName string `db:"nick_name"` // 暱稱
|
||||
Language string `db:"language"` // 使用語言
|
||||
Currency string `db:"currency"` // 使用幣別
|
||||
Avatar string `db:"avatar"` // 會員頭像
|
||||
CreateTime int64 `db:"create_time"`
|
||||
UpdateTime int64 `db:"update_time"`
|
||||
}
|
||||
)
|
||||
|
||||
func newUserTableModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) *defaultUserTableModel {
|
||||
return &defaultUserTableModel{
|
||||
CachedConn: sqlc.NewConn(conn, c, opts...),
|
||||
table: "`user_table`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) withSession(session sqlx.Session) *defaultUserTableModel {
|
||||
return &defaultUserTableModel{
|
||||
CachedConn: m.CachedConn.WithSession(session),
|
||||
table: "`user_table`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) Delete(ctx context.Context, id int64) error {
|
||||
data, err := m.FindOne(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, id)
|
||||
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid)
|
||||
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||
return conn.ExecCtx(ctx, query, id)
|
||||
}, userTableIdKey, userTableUidKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) FindOne(ctx context.Context, id int64) (*UserTable, error) {
|
||||
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, id)
|
||||
var resp UserTable
|
||||
err := m.QueryRowCtx(ctx, &resp, userTableIdKey, func(ctx context.Context, conn sqlx.SqlConn, v any) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userTableRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, id)
|
||||
})
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) FindOneByUid(ctx context.Context, uid string) (*UserTable, error) {
|
||||
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, uid)
|
||||
var resp UserTable
|
||||
err := m.QueryRowIndexCtx(ctx, &resp, userTableUidKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) {
|
||||
query := fmt.Sprintf("select %s from %s where `uid` = ? limit 1", userTableRows, m.table)
|
||||
if err := conn.QueryRowCtx(ctx, &resp, query, uid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Id, nil
|
||||
}, m.queryPrimary)
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) Insert(ctx context.Context, data *UserTable) (sql.Result, error) {
|
||||
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id)
|
||||
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid)
|
||||
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userTableRowsExpectAutoSet)
|
||||
return conn.ExecCtx(ctx, query, data.VerifyType, data.AlarmType, data.Status, data.Uid, data.NickName, data.Language, data.Currency, data.Avatar, data.CreateTime, data.UpdateTime)
|
||||
}, userTableIdKey, userTableUidKey)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) Update(ctx context.Context, newData *UserTable) error {
|
||||
data, err := m.FindOne(ctx, newData.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id)
|
||||
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid)
|
||||
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userTableRowsWithPlaceHolder)
|
||||
return conn.ExecCtx(ctx, query, newData.VerifyType, newData.AlarmType, newData.Status, newData.Uid, newData.NickName, newData.Language, newData.Currency, newData.Avatar, newData.CreateTime, newData.UpdateTime, newData.Id)
|
||||
}, userTableIdKey, userTableUidKey)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) formatPrimary(primary any) string {
|
||||
return fmt.Sprintf("%s%v", cacheUserTableIdPrefix, primary)
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userTableRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, primary)
|
||||
}
|
||||
|
||||
func (m *defaultUserTableModel) tableName() string {
|
||||
return m.table
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package model
|
||||
|
||||
import "github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
var ErrNotFound = sqlx.ErrNotFound
|
|
@ -1,13 +1,56 @@
|
|||
package svc
|
||||
|
||||
import "app-cloudep-member-server/internal/config"
|
||||
import (
|
||||
"app-cloudep-member-server/internal/config"
|
||||
"app-cloudep-member-server/internal/domain"
|
||||
domainUC "app-cloudep-member-server/internal/domain/usecase"
|
||||
"app-cloudep-member-server/internal/model"
|
||||
mgo "app-cloudep-member-server/internal/model/mongo"
|
||||
"app-cloudep-member-server/internal/usecase"
|
||||
ers "code.30cm.net/digimon/library-go/errors"
|
||||
vi "code.30cm.net/digimon/library-go/validator"
|
||||
"fmt"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type ServiceContext struct {
|
||||
Config config.Config
|
||||
Validate vi.Validate
|
||||
|
||||
AccountModel model.AccountModel
|
||||
UserModel model.UserTableModel
|
||||
AccountToUidModel model.AccountToUidModel
|
||||
GenUIDUseCase domainUC.UIDGenerateUseCase
|
||||
Redis redis.Redis
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
// 設置
|
||||
ers.Scope = domain.Scope
|
||||
|
||||
sqlConn := sqlx.NewMysql(c.DB.DsnString)
|
||||
newRedis, err := redis.NewRedis(c.RedisCluster, redis.Cluster())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mongo := mgo.NewAutoIdModel(
|
||||
fmt.Sprintf(
|
||||
"%s://%s:%s@%s:%s", c.Mongo.Schema,
|
||||
c.Mongo.User, c.Mongo.Password, c.Mongo.Host, c.Mongo.Port),
|
||||
c.Mongo.Database,
|
||||
c.Mongo.Collection,
|
||||
c.Cache)
|
||||
|
||||
return &ServiceContext{
|
||||
Config: c,
|
||||
Validate: vi.MustValidator(vi.WithAccount("account")),
|
||||
Redis: *newRedis,
|
||||
UserModel: model.NewUserTableModel(sqlConn, c.Cache),
|
||||
AccountToUidModel: model.NewAccountToUidModel(sqlConn, c.Cache),
|
||||
AccountModel: model.NewAccountModel(sqlConn, c.Cache),
|
||||
GenUIDUseCase: usecase.MustGenerateUseCase(usecase.GenerateUseCaseParam{
|
||||
GenerateUIDRepo: mongo,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
package usecase
|
|
@ -0,0 +1,75 @@
|
|||
package usecase
|
||||
|
||||
import (
|
||||
"app-cloudep-member-server/internal/domain"
|
||||
"app-cloudep-member-server/internal/domain/usecase"
|
||||
mgo "app-cloudep-member-server/internal/model/mongo"
|
||||
"context"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type GenerateUseCaseParam struct {
|
||||
GenerateUIDRepo mgo.AutoIdModel
|
||||
}
|
||||
|
||||
type GenerateUseCase struct {
|
||||
generateUIDRepo mgo.AutoIdModel
|
||||
}
|
||||
|
||||
func MustGenerateUseCase(param GenerateUseCaseParam) usecase.UIDGenerateUseCase {
|
||||
return &GenerateUseCase{
|
||||
generateUIDRepo: param.GenerateUIDRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate 利用 mongo 創立全局唯一的 ark id
|
||||
// 如果之後有效能問題,扛在同一個 mongo 資料庫,在改成雪花算法
|
||||
func (g GenerateUseCase) Generate(ctx context.Context) (string, error) {
|
||||
var data mgo.AutoId
|
||||
err := g.generateUIDRepo.Inc(ctx, &data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
uid := strconv.Itoa(int(domain.InitAutoId + data.Count))
|
||||
code, err := generateReferralCode(uid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
||||
// generateReferralCode 從 UID 生成 referralCode
|
||||
func generateReferralCode(uid string) (string, error) {
|
||||
uidInt, err := strconv.ParseInt(uid, 10, 64)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
maxReferralUIDBoundary := int64(math.Pow(float64(len(domain.ConvertTable)), float64(domain.DefaultReferralCodeLen)))
|
||||
if uidInt > maxReferralUIDBoundary {
|
||||
return "", usecase.UIDOutOfRangeErrorCodeError("uid encode out of range")
|
||||
}
|
||||
|
||||
encoded := encodeToBase(uidInt, len(domain.ConvertTable), domain.DefaultReferralCodeLen)
|
||||
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
func encodeToBase(num int64, base int, length int) string {
|
||||
result := ""
|
||||
for num > 0 {
|
||||
index := num % int64(base)
|
||||
result = domain.ConvertTable[index] + result
|
||||
num /= int64(base)
|
||||
}
|
||||
|
||||
// makes sure the length fo result feats the input length
|
||||
if len(result) < length {
|
||||
result = strings.Repeat(domain.ConvertTable[0], length-len(result)) + result
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
Loading…
Reference in New Issue