u
This commit is contained in:
1 parent
098a061308
commit
994321d049
40 files changed
+1401
-359
No files matched your search
@@ -1,14 +1,15 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"base-go-v2/internal/api/money"
|
||||
"base-go-v2/internal/db"
|
||||
response "base-go-v2/internal/reponse"
|
||||
"base-go-v2/internal/router"
|
||||
"base-go-v2/internal/routinex"
|
||||
"base-go-v2/internal/utils/idgen"
|
||||
"base-go-v2/internal/utils/jwtx"
|
||||
"base-go-v2/internal/utils/mapx"
|
||||
"base-go-v2/internal/utils/timex"
|
||||
"base-go-v2/internal/utils/uid"
|
||||
)
|
||||
|
||||
func InitAuthRouter(r *router.Router) {
|
||||
@@ -85,7 +86,7 @@ func loginDefault(c *router.Context) error {
|
||||
Send()
|
||||
}
|
||||
|
||||
userId := user.GetInt("id")
|
||||
userId := user.GetInt64("id")
|
||||
|
||||
// 创建 Access Token 和 Refresh Token
|
||||
accessToken, err := jwtx.CreateAccessToken(userId)
|
||||
@@ -99,8 +100,8 @@ func loginDefault(c *router.Context) error {
|
||||
|
||||
// 返回数据
|
||||
respData := mapx.New().
|
||||
SetIntToString("userId", userId).
|
||||
SetKV(
|
||||
"userId", userId,
|
||||
"username", user.GetString("username"),
|
||||
"seqNo", user.GetInt("seq_no"),
|
||||
"gender", user.GetInt("gender"),
|
||||
@@ -140,9 +141,10 @@ func registerDefault(c *router.Context) error {
|
||||
return response.Fail(c).Message("该账号已被注册").Send()
|
||||
}
|
||||
|
||||
userId := idgen.NextId()
|
||||
// 构造新用户数据
|
||||
newUserData := mapx.New().SetKV(
|
||||
"id", uid.NextID(),
|
||||
"id", userId,
|
||||
"account", account,
|
||||
"password", password,
|
||||
)
|
||||
@@ -150,10 +152,16 @@ func registerDefault(c *router.Context) error {
|
||||
// 插入新用户
|
||||
insertedRows, err := db.InsertOne("user_info", newUserData)
|
||||
if err != nil {
|
||||
return response.Fail(c).Message("注册失败").Send()
|
||||
}
|
||||
|
||||
if insertedRows != 1 {
|
||||
return response.Fail(c).Message("注册失败").Send()
|
||||
}
|
||||
|
||||
err = money.InitDefaultCategories(userId)
|
||||
if err != nil {
|
||||
return c.AddError(err)
|
||||
}
|
||||
return response.Success(c).Message("注册成功").Send()
|
||||
}
|
||||
@@ -21,7 +21,7 @@ func AuthMiddleware() router.HandlerFunc {
|
||||
|
||||
// Access Token 有效
|
||||
if tokenVerify.IsValid {
|
||||
c.Set("user_id", tokenVerify.Claims.UserID)
|
||||
c.SetUserID(tokenVerify.Claims.UserID)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"base-go-v2/internal/logx"
|
||||
"base-go-v2/internal/router"
|
||||
"base-go-v2/internal/routinex"
|
||||
"base-go-v2/internal/utils/uid"
|
||||
"base-go-v2/internal/utils/idgen"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ func LoggerMiddleware() router.HandlerFunc {
|
||||
start := time.Now() // 记录开始时间
|
||||
|
||||
// 生成 trackID 并存入 routinex
|
||||
trackID := uid.NextID()
|
||||
trackID := idgen.NextId()
|
||||
routinex.Set(logx.TrackID, trackID)
|
||||
|
||||
// 执行业务逻辑,并捕获错误
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package money
|
||||
|
||||
import (
|
||||
"base-go-v2/internal/db"
|
||||
response "base-go-v2/internal/reponse"
|
||||
"base-go-v2/internal/router"
|
||||
"base-go-v2/internal/utils/idgen"
|
||||
"base-go-v2/internal/utils/mapx"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func InitMoneyRouter(r *router.Router) {
|
||||
group := r.Group("money")
|
||||
group.GET("/category", getUserCategory)
|
||||
//group := r.Group("auth")
|
||||
}
|
||||
|
||||
// InitDefaultCategories 初始化系统默认分类到用户分类表
|
||||
func InitDefaultCategories(userID int64) error {
|
||||
fmt.Println("进入 InitDefaultCategories ===")
|
||||
|
||||
// 1. 查询系统分类表
|
||||
sysCategories, err := db.FindAll("money_sys_category", "sort_number")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("系统分类数量: %d\n", len(sysCategories))
|
||||
|
||||
// 2. 构建批量插入数据
|
||||
userCategories := make([]mapx.M, 0, len(sysCategories))
|
||||
for i, row := range sysCategories {
|
||||
m := mapx.New().SetKV(
|
||||
"id", idgen.NextId(),
|
||||
"user_id", userID,
|
||||
"name", row.GetString("name"),
|
||||
"icon", row.GetString("icon"),
|
||||
"type", row.GetInt("type"),
|
||||
"sort_number", row.GetInt("sort_number"),
|
||||
)
|
||||
fmt.Printf("用户分类 %d: %+v\n", i+1, m)
|
||||
userCategories = append(userCategories, m)
|
||||
}
|
||||
|
||||
// 3. 批量插入到用户分类表
|
||||
if _, err := db.InsertBatch("money_user_category", userCategories); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("初始化用户分类成功!")
|
||||
return nil
|
||||
}
|
||||
|
||||
func getUserCategory(c *router.Context) error {
|
||||
userId := c.GetUserID()
|
||||
|
||||
// 查询当前用户的分类
|
||||
userCategories, err := db.Find("money_user_category", mapx.New().Set("user_id", userId), "sort_number ASC")
|
||||
if err != nil {
|
||||
return c.AddError(err)
|
||||
}
|
||||
|
||||
// 按 type 分组
|
||||
result := map[string][]mapx.M{
|
||||
"income": {},
|
||||
"expense": {},
|
||||
}
|
||||
|
||||
for _, cat := range userCategories {
|
||||
switch cat.GetInt("type") {
|
||||
case 0:
|
||||
result["income"] = append(result["income"], cat)
|
||||
case 1:
|
||||
result["expense"] = append(result["expense"], cat)
|
||||
}
|
||||
}
|
||||
|
||||
return response.Success(c).Data(result).Send()
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"base-go-v2/internal/api/auth"
|
||||
"base-go-v2/internal/api/middleware"
|
||||
"base-go-v2/internal/api/money"
|
||||
"base-go-v2/internal/config"
|
||||
"base-go-v2/internal/router"
|
||||
)
|
||||
@@ -17,5 +18,7 @@ func InitAppRouter() *router.Router {
|
||||
r.Use(middleware.AuthMiddleware()).ExcludePaths("/auth/**")
|
||||
|
||||
auth.InitAuthRouter(r)
|
||||
money.InitMoneyRouter(r)
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -3,12 +3,14 @@ package db
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"base-go-v2/internal/utils/mapx"
|
||||
)
|
||||
|
||||
// ---------------- 内部辅助函数 ----------------
|
||||
|
||||
// buildInsertSQL 构建插入 SQL 和参数
|
||||
func buildInsertSQL(table string, data map[string]interface{}, returning string) (string, []interface{}) {
|
||||
func buildInsertSQL(table string, data mapx.M, returning string) (string, []interface{}) {
|
||||
columns := make([]string, 0, len(data))
|
||||
placeholders := make([]string, 0, len(data))
|
||||
values := make([]interface{}, 0, len(data))
|
||||
@@ -34,7 +36,7 @@ func buildInsertSQL(table string, data map[string]interface{}, returning string)
|
||||
// ---------------- 公共方法 ----------------
|
||||
|
||||
// InsertOne 插入单条记录,返回受影响行数
|
||||
func InsertOne(table string, data map[string]interface{}) (int64, error) {
|
||||
func InsertOne(table string, data mapx.M) (int64, error) {
|
||||
tx, err := DB.Beginx()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -55,7 +57,7 @@ func InsertOne(table string, data map[string]interface{}) (int64, error) {
|
||||
}
|
||||
|
||||
// InsertBatch 批量插入,返回总受影响行数
|
||||
func InsertBatch(table string, dataList []map[string]interface{}) (int64, error) {
|
||||
func InsertBatch(table string, dataList []mapx.M) (int64, error) {
|
||||
if len(dataList) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
@@ -90,7 +92,7 @@ func InsertBatch(table string, dataList []map[string]interface{}) (int64, error)
|
||||
}
|
||||
|
||||
// InsertOneReturnPK 插入单条记录,返回主键值
|
||||
func InsertOneReturnPK(table string, pkColumn string, data map[string]interface{}) (int64, error) {
|
||||
func InsertOneReturnPK(table string, pkColumn string, data mapx.M) (int64, error) {
|
||||
tx, err := DB.Beginx()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -113,7 +115,7 @@ func InsertOneReturnPK(table string, pkColumn string, data map[string]interface{
|
||||
}
|
||||
|
||||
// InsertBatchReturnPK 批量插入多条记录,返回主键数组
|
||||
func InsertBatchReturnPK(table string, pkColumn string, dataList []map[string]interface{}) ([]int64, error) {
|
||||
func InsertBatchReturnPK(table string, pkColumn string, dataList []mapx.M) ([]int64, error) {
|
||||
if len(dataList) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package logx
|
||||
import (
|
||||
"base-go-v2/internal/config"
|
||||
"base-go-v2/internal/routinex"
|
||||
"base-go-v2/internal/utils/idgen"
|
||||
"base-go-v2/internal/utils/strutil"
|
||||
"base-go-v2/internal/utils/uid"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -63,7 +63,7 @@ func (c *trackCore) Check(entry zapcore.Entry, ce *zapcore.CheckedEntry) *zapcor
|
||||
func (c *trackCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
|
||||
val := routinex.Get(TrackID)
|
||||
if val == nil {
|
||||
val = uid.NextID()
|
||||
val = idgen.NextId()
|
||||
routinex.Set(TrackID, val) // 保证同一请求复用同一 trackID
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,32 @@ func (c *Context) Get(key string) (interface{}, bool) {
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// SetUserID 存储 userId
|
||||
func (c *Context) SetUserID(userID int64) {
|
||||
c.Set("user_id", userID)
|
||||
}
|
||||
|
||||
// GetUserID 获取 userId
|
||||
func (c *Context) GetUserID() int64 {
|
||||
val, ok := c.Get("user_id")
|
||||
if !ok || val == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch v := val.(type) {
|
||||
case int64:
|
||||
return v
|
||||
case int:
|
||||
return int64(v)
|
||||
case uint64:
|
||||
return int64(v)
|
||||
case uint:
|
||||
return int64(v)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// JSON 返回 JSON 响应,支持返回 error
|
||||
func (c *Context) JSON(statusCode int, data interface{}) error {
|
||||
c.RequestCtx.SetStatusCode(statusCode)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package idgen
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DefaultIdGenerator struct {
|
||||
Options *IdGeneratorOptions
|
||||
SnowWorker ISnowWorker
|
||||
IdGeneratorException IdGeneratorException
|
||||
}
|
||||
|
||||
func NewDefaultIdGenerator(options *IdGeneratorOptions) *DefaultIdGenerator {
|
||||
if options == nil {
|
||||
panic("dig.Options error.")
|
||||
}
|
||||
|
||||
// 1.BaseTime
|
||||
minTime := int64(631123200000) // time.Now().AddDate(-30, 0, 0).UnixNano() / 1e6
|
||||
if options.BaseTime < minTime || options.BaseTime > time.Now().UnixNano()/1e6 {
|
||||
panic("BaseTime error.")
|
||||
}
|
||||
|
||||
// 2.WorkerIdBitLength
|
||||
if options.WorkerIdBitLength <= 0 {
|
||||
panic("WorkerIdBitLength error.(range:[1, 21])")
|
||||
}
|
||||
if options.WorkerIdBitLength+options.SeqBitLength > 22 {
|
||||
panic("error:WorkerIdBitLength + SeqBitLength <= 22")
|
||||
}
|
||||
|
||||
// 3.WorkerId
|
||||
maxWorkerIdNumber := uint16(1<<options.WorkerIdBitLength) - 1
|
||||
if maxWorkerIdNumber == 0 {
|
||||
maxWorkerIdNumber = 63
|
||||
}
|
||||
if options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber {
|
||||
panic("WorkerId error. (range:[0, " + strconv.FormatUint(uint64(maxWorkerIdNumber), 10) + "]")
|
||||
}
|
||||
|
||||
// 4.SeqBitLength
|
||||
if options.SeqBitLength < 2 || options.SeqBitLength > 21 {
|
||||
panic("SeqBitLength error. (range:[2, 21])")
|
||||
}
|
||||
|
||||
// 5.MaxSeqNumber
|
||||
maxSeqNumber := uint32(1<<options.SeqBitLength) - 1
|
||||
if maxSeqNumber == 0 {
|
||||
maxSeqNumber = 63
|
||||
}
|
||||
if options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber {
|
||||
panic("MaxSeqNumber error. (range:[1, " + strconv.FormatUint(uint64(maxSeqNumber), 10) + "]")
|
||||
}
|
||||
|
||||
// 6.MinSeqNumber
|
||||
if options.MinSeqNumber < 5 || options.MinSeqNumber > maxSeqNumber {
|
||||
panic("MinSeqNumber error. (range:[5, " + strconv.FormatUint(uint64(maxSeqNumber), 10) + "]")
|
||||
}
|
||||
|
||||
var snowWorker ISnowWorker
|
||||
switch options.Method {
|
||||
case 1:
|
||||
snowWorker = NewSnowWorkerM1(options)
|
||||
case 2:
|
||||
snowWorker = NewSnowWorkerM2(options)
|
||||
default:
|
||||
snowWorker = NewSnowWorkerM1(options)
|
||||
}
|
||||
|
||||
if options.Method == 1 {
|
||||
time.Sleep(time.Duration(500) * time.Microsecond)
|
||||
}
|
||||
|
||||
return &DefaultIdGenerator{
|
||||
Options: options,
|
||||
SnowWorker: snowWorker,
|
||||
}
|
||||
}
|
||||
|
||||
func (dig DefaultIdGenerator) NewLong() int64 {
|
||||
return dig.SnowWorker.NextId()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package idgen
|
||||
|
||||
type IIdGenerator interface {
|
||||
NewLong() uint64
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package idgen
|
||||
|
||||
type ISnowWorker interface {
|
||||
NextId() int64
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package idgen
|
||||
|
||||
import "fmt"
|
||||
|
||||
type IdGeneratorException struct {
|
||||
message string
|
||||
error error
|
||||
}
|
||||
|
||||
func (e IdGeneratorException) IdGeneratorException(message ...interface{}) {
|
||||
fmt.Println(message)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package idgen
|
||||
|
||||
type IdGeneratorOptions struct {
|
||||
Method uint16 // 雪花计算方法,(1-漂移算法|2-传统算法),默认1
|
||||
BaseTime int64 // 基础时间(ms单位),不能超过当前系统时间
|
||||
WorkerId uint16 // 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
|
||||
WorkerIdBitLength byte // 机器码位长,默认值6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过22)
|
||||
SeqBitLength byte // 序列数位长,默认值6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过22)
|
||||
MaxSeqNumber uint32 // 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1])
|
||||
MinSeqNumber uint32 // 最小序列数(含),默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位
|
||||
TopOverCostCount uint32 // 最大漂移次数(含),默认2000,推荐范围500-10000(与计算能力有关)
|
||||
}
|
||||
|
||||
func NewIdGeneratorOptions(workerId uint16) *IdGeneratorOptions {
|
||||
return &IdGeneratorOptions{
|
||||
Method: 1,
|
||||
WorkerId: workerId,
|
||||
BaseTime: 1582136402000,
|
||||
WorkerIdBitLength: 6,
|
||||
SeqBitLength: 6,
|
||||
MaxSeqNumber: 0,
|
||||
MinSeqNumber: 5,
|
||||
TopOverCostCount: 2000,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package idgen
|
||||
|
||||
type OverCostActionArg struct {
|
||||
ActionType int32
|
||||
TimeTick int64
|
||||
WorkerId uint16
|
||||
OverCostCountInOneTerm int32
|
||||
GenCountInOneTerm int32
|
||||
TermIndex int32
|
||||
}
|
||||
|
||||
func (ocaa OverCostActionArg) OverCostActionArg(workerId uint16, timeTick int64, actionType int32, overCostCountInOneTerm int32, genCountWhenOverCost int32, index int32) {
|
||||
ocaa.ActionType = actionType
|
||||
ocaa.TimeTick = timeTick
|
||||
ocaa.WorkerId = workerId
|
||||
ocaa.OverCostCountInOneTerm = overCostCountInOneTerm
|
||||
ocaa.GenCountInOneTerm = genCountWhenOverCost
|
||||
ocaa.TermIndex = index
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package idgen
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SnowWorkerM1 .
|
||||
type SnowWorkerM1 struct {
|
||||
BaseTime int64 //基础时间
|
||||
WorkerId uint16 //机器码
|
||||
WorkerIdBitLength byte //机器码位长
|
||||
SeqBitLength byte //自增序列数位长
|
||||
MaxSeqNumber uint32 //最大序列数(含)
|
||||
MinSeqNumber uint32 //最小序列数(含)
|
||||
TopOverCostCount uint32 //最大漂移次数
|
||||
_TimestampShift byte
|
||||
_CurrentSeqNumber uint32
|
||||
|
||||
_LastTimeTick int64
|
||||
_TurnBackTimeTick int64
|
||||
_TurnBackIndex byte
|
||||
_IsOverCost bool
|
||||
_OverCostCountInOneTerm uint32
|
||||
_GenCountInOneTerm uint32
|
||||
_TermIndex uint32
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// NewSnowWorkerM1 .
|
||||
func NewSnowWorkerM1(options *IdGeneratorOptions) ISnowWorker {
|
||||
var workerIdBitLength byte
|
||||
var seqBitLength byte
|
||||
var maxSeqNumber uint32
|
||||
|
||||
// 1.BaseTime
|
||||
var baseTime int64
|
||||
if options.BaseTime != 0 {
|
||||
baseTime = options.BaseTime
|
||||
} else {
|
||||
baseTime = 1582136402000
|
||||
}
|
||||
|
||||
// 2.WorkerIdBitLength
|
||||
if options.WorkerIdBitLength == 0 {
|
||||
workerIdBitLength = 6
|
||||
} else {
|
||||
workerIdBitLength = options.WorkerIdBitLength
|
||||
}
|
||||
|
||||
// 3.WorkerId
|
||||
var workerId = options.WorkerId
|
||||
|
||||
// 4.SeqBitLength
|
||||
if options.SeqBitLength == 0 {
|
||||
seqBitLength = 6
|
||||
} else {
|
||||
seqBitLength = options.SeqBitLength
|
||||
}
|
||||
|
||||
// 5.MaxSeqNumber
|
||||
if options.MaxSeqNumber <= 0 {
|
||||
maxSeqNumber = (1 << seqBitLength) - 1
|
||||
} else {
|
||||
maxSeqNumber = options.MaxSeqNumber
|
||||
}
|
||||
|
||||
// 6.MinSeqNumber
|
||||
var minSeqNumber = options.MinSeqNumber
|
||||
|
||||
// 7.Others
|
||||
var topOverCostCount = options.TopOverCostCount
|
||||
if topOverCostCount == 0 {
|
||||
topOverCostCount = 2000
|
||||
}
|
||||
|
||||
timestampShift := (byte)(workerIdBitLength + seqBitLength)
|
||||
currentSeqNumber := minSeqNumber
|
||||
|
||||
return &SnowWorkerM1{
|
||||
BaseTime: baseTime,
|
||||
WorkerIdBitLength: workerIdBitLength,
|
||||
WorkerId: workerId,
|
||||
SeqBitLength: seqBitLength,
|
||||
MaxSeqNumber: maxSeqNumber,
|
||||
MinSeqNumber: minSeqNumber,
|
||||
TopOverCostCount: topOverCostCount,
|
||||
_TimestampShift: timestampShift,
|
||||
_CurrentSeqNumber: currentSeqNumber,
|
||||
|
||||
_LastTimeTick: 0,
|
||||
_TurnBackTimeTick: 0,
|
||||
_TurnBackIndex: 0,
|
||||
_IsOverCost: false,
|
||||
_OverCostCountInOneTerm: 0,
|
||||
_GenCountInOneTerm: 0,
|
||||
_TermIndex: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// DoGenIDAction .
|
||||
func (m1 *SnowWorkerM1) DoGenIdAction(arg *OverCostActionArg) {
|
||||
|
||||
}
|
||||
|
||||
func (m1 *SnowWorkerM1) BeginOverCostAction(useTimeTick int64) {
|
||||
|
||||
}
|
||||
|
||||
func (m1 *SnowWorkerM1) EndOverCostAction(useTimeTick int64) {
|
||||
if m1._TermIndex > 10000 {
|
||||
m1._TermIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (m1 *SnowWorkerM1) BeginTurnBackAction(useTimeTick int64) {
|
||||
|
||||
}
|
||||
|
||||
func (m1 *SnowWorkerM1) EndTurnBackAction(useTimeTick int64) {
|
||||
|
||||
}
|
||||
|
||||
func (m1 *SnowWorkerM1) NextOverCostId() int64 {
|
||||
currentTimeTick := m1.GetCurrentTimeTick()
|
||||
if currentTimeTick > m1._LastTimeTick {
|
||||
m1.EndOverCostAction(currentTimeTick)
|
||||
m1._LastTimeTick = currentTimeTick
|
||||
m1._CurrentSeqNumber = m1.MinSeqNumber
|
||||
m1._IsOverCost = false
|
||||
m1._OverCostCountInOneTerm = 0
|
||||
m1._GenCountInOneTerm = 0
|
||||
return m1.CalcId(m1._LastTimeTick)
|
||||
}
|
||||
if m1._OverCostCountInOneTerm >= m1.TopOverCostCount {
|
||||
m1.EndOverCostAction(currentTimeTick)
|
||||
m1._LastTimeTick = m1.GetNextTimeTick()
|
||||
m1._CurrentSeqNumber = m1.MinSeqNumber
|
||||
m1._IsOverCost = false
|
||||
m1._OverCostCountInOneTerm = 0
|
||||
m1._GenCountInOneTerm = 0
|
||||
return m1.CalcId(m1._LastTimeTick)
|
||||
}
|
||||
if m1._CurrentSeqNumber > m1.MaxSeqNumber {
|
||||
m1._LastTimeTick++
|
||||
m1._CurrentSeqNumber = m1.MinSeqNumber
|
||||
m1._IsOverCost = true
|
||||
m1._OverCostCountInOneTerm++
|
||||
m1._GenCountInOneTerm++
|
||||
|
||||
return m1.CalcId(m1._LastTimeTick)
|
||||
}
|
||||
|
||||
m1._GenCountInOneTerm++
|
||||
return m1.CalcId(m1._LastTimeTick)
|
||||
}
|
||||
|
||||
// NextNormalID .
|
||||
func (m1 *SnowWorkerM1) NextNormalId() int64 {
|
||||
currentTimeTick := m1.GetCurrentTimeTick()
|
||||
if currentTimeTick < m1._LastTimeTick {
|
||||
if m1._TurnBackTimeTick < 1 {
|
||||
m1._TurnBackTimeTick = m1._LastTimeTick - 1
|
||||
m1._TurnBackIndex++
|
||||
// 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序
|
||||
// 最多4次回拨(防止回拨重叠)
|
||||
if m1._TurnBackIndex > 4 {
|
||||
m1._TurnBackIndex = 1
|
||||
}
|
||||
m1.BeginTurnBackAction(m1._TurnBackTimeTick)
|
||||
}
|
||||
|
||||
// time.Sleep(time.Duration(1) * time.Millisecond)
|
||||
return m1.CalcTurnBackId(m1._TurnBackTimeTick)
|
||||
}
|
||||
|
||||
// 时间追平时,_TurnBackTimeTick清零
|
||||
if m1._TurnBackTimeTick > 0 {
|
||||
m1.EndTurnBackAction(m1._TurnBackTimeTick)
|
||||
m1._TurnBackTimeTick = 0
|
||||
}
|
||||
|
||||
if currentTimeTick > m1._LastTimeTick {
|
||||
m1._LastTimeTick = currentTimeTick
|
||||
m1._CurrentSeqNumber = m1.MinSeqNumber
|
||||
return m1.CalcId(m1._LastTimeTick)
|
||||
}
|
||||
|
||||
if m1._CurrentSeqNumber > m1.MaxSeqNumber {
|
||||
m1.BeginOverCostAction(currentTimeTick)
|
||||
m1._TermIndex++
|
||||
m1._LastTimeTick++
|
||||
m1._CurrentSeqNumber = m1.MinSeqNumber
|
||||
m1._IsOverCost = true
|
||||
m1._OverCostCountInOneTerm = 1
|
||||
m1._GenCountInOneTerm = 1
|
||||
|
||||
return m1.CalcId(m1._LastTimeTick)
|
||||
}
|
||||
|
||||
return m1.CalcId(m1._LastTimeTick)
|
||||
}
|
||||
|
||||
// CalcID .
|
||||
func (m1 *SnowWorkerM1) CalcId(useTimeTick int64) int64 {
|
||||
result := int64(useTimeTick<<m1._TimestampShift) + int64(m1.WorkerId<<m1.SeqBitLength) + int64(m1._CurrentSeqNumber)
|
||||
m1._CurrentSeqNumber++
|
||||
return result
|
||||
}
|
||||
|
||||
// CalcTurnBackID .
|
||||
func (m1 *SnowWorkerM1) CalcTurnBackId(useTimeTick int64) int64 {
|
||||
result := int64(useTimeTick<<m1._TimestampShift) + int64(m1.WorkerId<<m1.SeqBitLength) + int64(m1._TurnBackIndex)
|
||||
m1._TurnBackTimeTick--
|
||||
return result
|
||||
}
|
||||
|
||||
// GetCurrentTimeTick .
|
||||
func (m1 *SnowWorkerM1) GetCurrentTimeTick() int64 {
|
||||
var millis = time.Now().UnixNano() / 1e6
|
||||
return millis - m1.BaseTime
|
||||
}
|
||||
|
||||
// GetNextTimeTick .
|
||||
func (m1 *SnowWorkerM1) GetNextTimeTick() int64 {
|
||||
tempTimeTicker := m1.GetCurrentTimeTick()
|
||||
for tempTimeTicker <= m1._LastTimeTick {
|
||||
tempTimeTicker = m1.GetCurrentTimeTick()
|
||||
}
|
||||
return tempTimeTicker
|
||||
}
|
||||
|
||||
// NextId .
|
||||
func (m1 *SnowWorkerM1) NextId() int64 {
|
||||
m1.Lock()
|
||||
defer m1.Unlock()
|
||||
if m1._IsOverCost {
|
||||
return m1.NextOverCostId()
|
||||
} else {
|
||||
return m1.NextNormalId()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package idgen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SnowWorkerM2 struct {
|
||||
*SnowWorkerM1
|
||||
}
|
||||
|
||||
func NewSnowWorkerM2(options *IdGeneratorOptions) ISnowWorker {
|
||||
return &SnowWorkerM2{
|
||||
NewSnowWorkerM1(options).(*SnowWorkerM1),
|
||||
}
|
||||
}
|
||||
|
||||
func (m2 SnowWorkerM2) NextId() int64 {
|
||||
m2.Lock()
|
||||
defer m2.Unlock()
|
||||
currentTimeTick := m2.GetCurrentTimeTick()
|
||||
if m2._LastTimeTick == currentTimeTick {
|
||||
m2._CurrentSeqNumber++
|
||||
if m2._CurrentSeqNumber > m2.MaxSeqNumber {
|
||||
m2._CurrentSeqNumber = m2.MinSeqNumber
|
||||
currentTimeTick = m2.GetNextTimeTick()
|
||||
}
|
||||
} else {
|
||||
m2._CurrentSeqNumber = m2.MinSeqNumber
|
||||
}
|
||||
if currentTimeTick < m2._LastTimeTick {
|
||||
fmt.Println("Time error for {0} milliseconds", strconv.FormatInt(m2._LastTimeTick-currentTimeTick, 10))
|
||||
}
|
||||
m2._LastTimeTick = currentTimeTick
|
||||
result := int64(currentTimeTick<<m2._TimestampShift) + int64(m2.WorkerId<<m2.SeqBitLength) + int64(m2._CurrentSeqNumber)
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package idgen
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var singletonMutex sync.Mutex
|
||||
var idGenerator *DefaultIdGenerator
|
||||
|
||||
// SetIdGenerator .
|
||||
func SetIdGenerator(options *IdGeneratorOptions) {
|
||||
singletonMutex.Lock()
|
||||
idGenerator = NewDefaultIdGenerator(options)
|
||||
singletonMutex.Unlock()
|
||||
}
|
||||
|
||||
// NextId .
|
||||
func NextId() int64 {
|
||||
if idGenerator == nil {
|
||||
singletonMutex.Lock()
|
||||
defer singletonMutex.Unlock()
|
||||
if idGenerator == nil {
|
||||
options := NewIdGeneratorOptions(1)
|
||||
idGenerator = NewDefaultIdGenerator(options)
|
||||
}
|
||||
}
|
||||
|
||||
return idGenerator.NewLong()
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
// CustomClaims 自定义 payload,可扩展其他信息
|
||||
type CustomClaims struct {
|
||||
UserID int `json:"user_id"` // 改为 int
|
||||
UserID int64 `json:"user_id"` // 改为 int
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
@@ -21,17 +21,17 @@ type TokenResult struct {
|
||||
}
|
||||
|
||||
// CreateAccessToken 创建 Access Token,只返回 token 和 error
|
||||
func CreateAccessToken(userID int) (string, error) {
|
||||
func CreateAccessToken(userID int64) (string, error) {
|
||||
return createToken(userID, config.App.JWT.AccessExpiry)
|
||||
}
|
||||
|
||||
// CreateRefreshToken 创建 Refresh Token,只返回 token 和 error
|
||||
func CreateRefreshToken(userID int) (string, error) {
|
||||
func CreateRefreshToken(userID int64) (string, error) {
|
||||
return createToken(userID, config.App.JWT.RefreshExpiry)
|
||||
}
|
||||
|
||||
// 内部方法,根据过期时间生成 token
|
||||
func createToken(userID int, expiry time.Duration) (string, error) {
|
||||
func createToken(userID int64, expiry time.Duration) (string, error) {
|
||||
claims := &CustomClaims{
|
||||
UserID: userID,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
|
||||
@@ -13,6 +13,10 @@ func New() M {
|
||||
return M{}
|
||||
}
|
||||
|
||||
func NewArr() {
|
||||
//return make([]M, 0, len())
|
||||
}
|
||||
|
||||
// Set 设置单个键值,支持链式调用
|
||||
func (m M) Set(key string, value interface{}) M {
|
||||
m[key] = value
|
||||
@@ -78,33 +82,68 @@ func (m M) GetString(key string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetInt 获取整数类型
|
||||
func (m M) GetInt(key string) int {
|
||||
if v, ok := m[key]; ok {
|
||||
// 核心获取整数的方法,返回 int64
|
||||
func (m M) getIntValue(key string) int64 {
|
||||
if v, ok := m[key]; ok && v != nil {
|
||||
switch val := v.(type) {
|
||||
case int:
|
||||
return val
|
||||
return int64(val)
|
||||
case int8:
|
||||
return int(val)
|
||||
return int64(val)
|
||||
case int16:
|
||||
return int(val)
|
||||
return int64(val)
|
||||
case int32:
|
||||
return int(val)
|
||||
return int64(val)
|
||||
case int64:
|
||||
return int(val)
|
||||
return val
|
||||
case uint:
|
||||
return int64(val)
|
||||
case uint8:
|
||||
return int64(val)
|
||||
case uint16:
|
||||
return int64(val)
|
||||
case uint32:
|
||||
return int64(val)
|
||||
case uint64:
|
||||
return int64(val) // 注意溢出
|
||||
case float32:
|
||||
return int(val)
|
||||
return int64(val)
|
||||
case float64:
|
||||
return int(val)
|
||||
return int64(val)
|
||||
case string:
|
||||
if i, err := strconv.ParseInt(val, 10, 64); err == nil {
|
||||
return int(i)
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetInt 返回默认 int 类型
|
||||
func (m M) GetInt(key string) int {
|
||||
return int(m.getIntValue(key))
|
||||
}
|
||||
|
||||
// GetInt64 返回 int64
|
||||
func (m M) GetInt64(key string) int64 {
|
||||
return m.getIntValue(key)
|
||||
}
|
||||
|
||||
// GetInt32 返回 int32
|
||||
func (m M) GetInt32(key string) int32 {
|
||||
return int32(m.getIntValue(key))
|
||||
}
|
||||
|
||||
// GetInt16 返回 int16
|
||||
func (m M) GetInt16(key string) int16 {
|
||||
return int16(m.getIntValue(key))
|
||||
}
|
||||
|
||||
// GetInt8 返回 int8
|
||||
func (m M) GetInt8(key string) int8 {
|
||||
return int8(m.getIntValue(key))
|
||||
}
|
||||
|
||||
// Merge 合并另一个 M,后者会覆盖前者同名字段
|
||||
func (m M) Merge(other M) M {
|
||||
for k, v := range other {
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
package uid
|
||||
|
||||
import (
|
||||
"base-go-v2/internal/config"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
datacenterBits = uint64(5)
|
||||
workerBits = uint64(5)
|
||||
sequenceBits = uint64(12)
|
||||
|
||||
maxSequence = -1 ^ (-1 << sequenceBits)
|
||||
workerShift = sequenceBits
|
||||
datacenterShift = sequenceBits + workerBits
|
||||
timestampShift = sequenceBits + workerBits + datacenterBits
|
||||
|
||||
epoch = int64(1672531200000) // 2023-01-01
|
||||
)
|
||||
|
||||
type Snowflake struct {
|
||||
lastStamp uint64 // 上一次时间戳 (毫秒)
|
||||
sequence uint64 // 序列号
|
||||
dcID uint64
|
||||
workerID uint64
|
||||
}
|
||||
|
||||
var (
|
||||
sfInstance *Snowflake
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// lazy 初始化实例
|
||||
func initInstance() {
|
||||
var dcID, wID uint64
|
||||
|
||||
dcID = config.App.Snowflake.DatacenterID
|
||||
wID = config.App.Snowflake.WorkerID
|
||||
|
||||
sfInstance = &Snowflake{
|
||||
dcID: dcID,
|
||||
workerID: wID,
|
||||
}
|
||||
}
|
||||
|
||||
// NextID 生成全局唯一 ID,无锁版本
|
||||
func NextID() uint64 {
|
||||
once.Do(initInstance)
|
||||
|
||||
for {
|
||||
now := uint64(time.Now().UnixNano() / 1e6)
|
||||
|
||||
last := atomic.LoadUint64(&sfInstance.lastStamp)
|
||||
seq := atomic.LoadUint64(&sfInstance.sequence)
|
||||
|
||||
if now < last {
|
||||
// 系统时钟回拨,等待
|
||||
now = waitNextMillis(last)
|
||||
}
|
||||
|
||||
if now == last {
|
||||
seq = (seq + 1) & uint64(maxSequence)
|
||||
if seq == 0 {
|
||||
now = waitNextMillis(last)
|
||||
}
|
||||
} else {
|
||||
seq = 0
|
||||
}
|
||||
|
||||
if atomic.CompareAndSwapUint64(&sfInstance.lastStamp, last, now) {
|
||||
atomic.StoreUint64(&sfInstance.sequence, seq)
|
||||
id := ((now - uint64(epoch)) << timestampShift) |
|
||||
(sfInstance.dcID << datacenterShift) |
|
||||
(sfInstance.workerID << workerShift) |
|
||||
seq
|
||||
return id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 等待下一个毫秒
|
||||
func waitNextMillis(last uint64) uint64 {
|
||||
now := uint64(time.Now().UnixNano() / 1e6)
|
||||
for now <= last {
|
||||
now = uint64(time.Now().UnixNano() / 1e6)
|
||||
}
|
||||
return now
|
||||
}
|
||||
Reference in new issue
Block a user