mirror of
https://github.com/xxjwxc/public.git
synced 2025-09-26 20:01:19 +08:00
添加全局唯一id
This commit is contained in:
@@ -5,5 +5,5 @@ golang 工具包。
|
||||
|
||||
包括:
|
||||
|
||||
`文件功能`,`leveldb`,`restful风格消息包头定义`,`cache缓存`,`绘图函数`,`elastic`,`echarts`,`http`,`日志`,`nsq抽取`,`线程安全队列`,`签名`,`gorm封装`,`时间函数`,`国际化i18n`,`gocui 界面类`,`驼峰命名转换工具`,`大驼峰到网络标准json串自动转换`,`剪切板`,`微信`,`ast`,`swagger 文档支持`,`mindoc/markdown 文档支持`
|
||||
`文件功能`,`leveldb`,`restful风格消息包头定义`,`cache缓存`,`绘图函数`,`elastic`,`echarts`,`http`,`日志`,`nsq抽取`,`线程安全队列`,`签名`,`gorm封装`,`时间函数`,`国际化i18n`,`gocui 界面类`,`驼峰命名转换工具`,`大驼峰到网络标准json串自动转换`,`剪切板`,`微信`,`ast`,`swagger 文档支持`,`mindoc/markdown 文档支持`,`分布式全局唯一id(myglobal)`
|
||||
......
|
||||
|
13
message/error.go
Normal file
13
message/error.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package message
|
||||
|
||||
import "github.com/xxjwxc/public/errors"
|
||||
|
||||
// GetErrFromID 通过id返回错误信息
|
||||
func GetErrFromID(codeID int) error {
|
||||
if _, ok := MessageMap[codeID]; ok {
|
||||
return errors.New(MessageMap[codeID])
|
||||
}
|
||||
|
||||
// 返回默认值
|
||||
return errors.New(MessageMap[-1])
|
||||
}
|
50
myglobal/myglobal.go
Normal file
50
myglobal/myglobal.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package myglobal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/xxjwxc/public/myglobal/snowflake"
|
||||
"github.com/xxjwxc/public/mylog"
|
||||
)
|
||||
|
||||
// NodeInfo 节点信息
|
||||
type NodeInfo struct {
|
||||
ID int64
|
||||
snowflake *snowflake.Node // 雪花算法获取全局唯一id
|
||||
}
|
||||
|
||||
var node NodeInfo
|
||||
|
||||
func init() {
|
||||
SetNodeID(1) //默认值
|
||||
}
|
||||
|
||||
// SetNodeID 设置当前机器节点ID(一般程序启动时就需要设置,且初始化)
|
||||
func SetNodeID(nodeID int64) {
|
||||
node.ID = nodeID
|
||||
Init()
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func Init() {
|
||||
var err error
|
||||
node.snowflake, err = snowflake.NewNode(node.ID)
|
||||
if err != nil {
|
||||
mylog.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetNode 获取node节点
|
||||
func GetNode() *NodeInfo {
|
||||
return &node
|
||||
}
|
||||
|
||||
// GetID 获取全局唯一id
|
||||
func (n *NodeInfo) GetID() int64 {
|
||||
return n.snowflake.Generate().Int64()
|
||||
}
|
||||
|
||||
// GetIDStr 获取全局唯一id
|
||||
func (n *NodeInfo) GetIDStr() string {
|
||||
return fmt.Sprintf("%v", n.snowflake.Generate().Int64())
|
||||
}
|
365
myglobal/snowflake/snowflake.go
Normal file
365
myglobal/snowflake/snowflake.go
Normal file
@@ -0,0 +1,365 @@
|
||||
// Package snowflake provides a very simple Twitter snowflake generator and parser.
|
||||
package snowflake
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// Epoch is set to the twitter snowflake epoch of Nov 04 2010 01:42:54 UTC in milliseconds
|
||||
// You may customize this to set a different epoch for your application.
|
||||
Epoch int64 = 1288834974657
|
||||
|
||||
// NodeBits holds the number of bits to use for Node
|
||||
// Remember, you have a total 22 bits to share between Node/Step
|
||||
NodeBits uint8 = 10
|
||||
|
||||
// StepBits holds the number of bits to use for Step
|
||||
// Remember, you have a total 22 bits to share between Node/Step
|
||||
StepBits uint8 = 12
|
||||
|
||||
// DEPRECATED: the below four variables will be removed in a future release.
|
||||
mu sync.Mutex
|
||||
nodeMax int64 = -1 ^ (-1 << NodeBits)
|
||||
nodeMask = nodeMax << StepBits
|
||||
stepMask int64 = -1 ^ (-1 << StepBits)
|
||||
timeShift = NodeBits + StepBits
|
||||
nodeShift = StepBits
|
||||
)
|
||||
|
||||
const encodeBase32Map = "ybndrfg8ejkmcpqxot1uwisza345h769"
|
||||
|
||||
var decodeBase32Map [256]byte
|
||||
|
||||
const encodeBase58Map = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
||||
|
||||
var decodeBase58Map [256]byte
|
||||
|
||||
// A JSONSyntaxError is returned from UnmarshalJSON if an invalid ID is provided.
|
||||
type JSONSyntaxError struct{ original []byte }
|
||||
|
||||
func (j JSONSyntaxError) Error() string {
|
||||
return fmt.Sprintf("invalid snowflake ID %q", string(j.original))
|
||||
}
|
||||
|
||||
// ErrInvalidBase58 is returned by ParseBase58 when given an invalid []byte
|
||||
var ErrInvalidBase58 = errors.New("invalid base58")
|
||||
|
||||
// ErrInvalidBase32 is returned by ParseBase32 when given an invalid []byte
|
||||
var ErrInvalidBase32 = errors.New("invalid base32")
|
||||
|
||||
// Create maps for decoding Base58/Base32.
|
||||
// This speeds up the process tremendously.
|
||||
func init() {
|
||||
|
||||
for i := 0; i < len(encodeBase58Map); i++ {
|
||||
decodeBase58Map[i] = 0xFF
|
||||
}
|
||||
|
||||
for i := 0; i < len(encodeBase58Map); i++ {
|
||||
decodeBase58Map[encodeBase58Map[i]] = byte(i)
|
||||
}
|
||||
|
||||
for i := 0; i < len(encodeBase32Map); i++ {
|
||||
decodeBase32Map[i] = 0xFF
|
||||
}
|
||||
|
||||
for i := 0; i < len(encodeBase32Map); i++ {
|
||||
decodeBase32Map[encodeBase32Map[i]] = byte(i)
|
||||
}
|
||||
}
|
||||
|
||||
// A Node struct holds the basic information needed for a snowflake generator
|
||||
// node
|
||||
type Node struct {
|
||||
mu sync.Mutex
|
||||
epoch time.Time
|
||||
time int64
|
||||
node int64
|
||||
step int64
|
||||
|
||||
nodeMax int64
|
||||
nodeMask int64
|
||||
stepMask int64
|
||||
timeShift uint8
|
||||
nodeShift uint8
|
||||
}
|
||||
|
||||
// An ID is a custom type used for a snowflake ID. This is used so we can
|
||||
// attach methods onto the ID.
|
||||
type ID int64
|
||||
|
||||
// NewNode returns a new snowflake node that can be used to generate snowflake
|
||||
// IDs
|
||||
func NewNode(node int64) (*Node, error) {
|
||||
|
||||
// re-calc in case custom NodeBits or StepBits were set
|
||||
// DEPRECATED: the below block will be removed in a future release.
|
||||
mu.Lock()
|
||||
nodeMax = -1 ^ (-1 << NodeBits)
|
||||
nodeMask = nodeMax << StepBits
|
||||
stepMask = -1 ^ (-1 << StepBits)
|
||||
timeShift = NodeBits + StepBits
|
||||
nodeShift = StepBits
|
||||
mu.Unlock()
|
||||
|
||||
n := Node{}
|
||||
n.node = node
|
||||
n.nodeMax = -1 ^ (-1 << NodeBits)
|
||||
n.nodeMask = n.nodeMax << StepBits
|
||||
n.stepMask = -1 ^ (-1 << StepBits)
|
||||
n.timeShift = NodeBits + StepBits
|
||||
n.nodeShift = StepBits
|
||||
|
||||
if n.node < 0 || n.node > n.nodeMax {
|
||||
return nil, errors.New("Node number must be between 0 and " + strconv.FormatInt(n.nodeMax, 10))
|
||||
}
|
||||
|
||||
var curTime = time.Now()
|
||||
// add time.Duration to curTime to make sure we use the monotonic clock if available
|
||||
n.epoch = curTime.Add(time.Unix(Epoch/1000, (Epoch%1000)*1000000).Sub(curTime))
|
||||
|
||||
return &n, nil
|
||||
}
|
||||
|
||||
// Generate creates and returns a unique snowflake ID
|
||||
// To help guarantee uniqueness
|
||||
// - Make sure your system is keeping accurate system time
|
||||
// - Make sure you never have multiple nodes running with the same node ID
|
||||
func (n *Node) Generate() ID {
|
||||
|
||||
n.mu.Lock()
|
||||
|
||||
now := time.Since(n.epoch).Nanoseconds() / 1000000
|
||||
|
||||
if now == n.time {
|
||||
n.step = (n.step + 1) & n.stepMask
|
||||
|
||||
if n.step == 0 {
|
||||
for now <= n.time {
|
||||
now = time.Since(n.epoch).Nanoseconds() / 1000000
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n.step = 0
|
||||
}
|
||||
|
||||
n.time = now
|
||||
|
||||
r := ID((now)<<n.timeShift |
|
||||
(n.node << n.nodeShift) |
|
||||
(n.step),
|
||||
)
|
||||
|
||||
n.mu.Unlock()
|
||||
return r
|
||||
}
|
||||
|
||||
// Int64 returns an int64 of the snowflake ID
|
||||
func (f ID) Int64() int64 {
|
||||
return int64(f)
|
||||
}
|
||||
|
||||
// ParseInt64 converts an int64 into a snowflake ID
|
||||
func ParseInt64(id int64) ID {
|
||||
return ID(id)
|
||||
}
|
||||
|
||||
// String returns a string of the snowflake ID
|
||||
func (f ID) String() string {
|
||||
return strconv.FormatInt(int64(f), 10)
|
||||
}
|
||||
|
||||
// ParseString converts a string into a snowflake ID
|
||||
func ParseString(id string) (ID, error) {
|
||||
i, err := strconv.ParseInt(id, 10, 64)
|
||||
return ID(i), err
|
||||
|
||||
}
|
||||
|
||||
// Base2 returns a string base2 of the snowflake ID
|
||||
func (f ID) Base2() string {
|
||||
return strconv.FormatInt(int64(f), 2)
|
||||
}
|
||||
|
||||
// ParseBase2 converts a Base2 string into a snowflake ID
|
||||
func ParseBase2(id string) (ID, error) {
|
||||
i, err := strconv.ParseInt(id, 2, 64)
|
||||
return ID(i), err
|
||||
}
|
||||
|
||||
// Base32 uses the z-base-32 character set but encodes and decodes similar
|
||||
// to base58, allowing it to create an even smaller result string.
|
||||
// NOTE: There are many different base32 implementations so becareful when
|
||||
// doing any interoperation.
|
||||
func (f ID) Base32() string {
|
||||
|
||||
if f < 32 {
|
||||
return string(encodeBase32Map[f])
|
||||
}
|
||||
|
||||
b := make([]byte, 0, 12)
|
||||
for f >= 32 {
|
||||
b = append(b, encodeBase32Map[f%32])
|
||||
f /= 32
|
||||
}
|
||||
b = append(b, encodeBase32Map[f])
|
||||
|
||||
for x, y := 0, len(b)-1; x < y; x, y = x+1, y-1 {
|
||||
b[x], b[y] = b[y], b[x]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// ParseBase32 parses a base32 []byte into a snowflake ID
|
||||
// NOTE: There are many different base32 implementations so becareful when
|
||||
// doing any interoperation.
|
||||
func ParseBase32(b []byte) (ID, error) {
|
||||
|
||||
var id int64
|
||||
|
||||
for i := range b {
|
||||
if decodeBase32Map[b[i]] == 0xFF {
|
||||
return -1, ErrInvalidBase32
|
||||
}
|
||||
id = id*32 + int64(decodeBase32Map[b[i]])
|
||||
}
|
||||
|
||||
return ID(id), nil
|
||||
}
|
||||
|
||||
// Base36 returns a base36 string of the snowflake ID
|
||||
func (f ID) Base36() string {
|
||||
return strconv.FormatInt(int64(f), 36)
|
||||
}
|
||||
|
||||
// ParseBase36 converts a Base36 string into a snowflake ID
|
||||
func ParseBase36(id string) (ID, error) {
|
||||
i, err := strconv.ParseInt(id, 36, 64)
|
||||
return ID(i), err
|
||||
}
|
||||
|
||||
// Base58 returns a base58 string of the snowflake ID
|
||||
func (f ID) Base58() string {
|
||||
|
||||
if f < 58 {
|
||||
return string(encodeBase58Map[f])
|
||||
}
|
||||
|
||||
b := make([]byte, 0, 11)
|
||||
for f >= 58 {
|
||||
b = append(b, encodeBase58Map[f%58])
|
||||
f /= 58
|
||||
}
|
||||
b = append(b, encodeBase58Map[f])
|
||||
|
||||
for x, y := 0, len(b)-1; x < y; x, y = x+1, y-1 {
|
||||
b[x], b[y] = b[y], b[x]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// ParseBase58 parses a base58 []byte into a snowflake ID
|
||||
func ParseBase58(b []byte) (ID, error) {
|
||||
|
||||
var id int64
|
||||
|
||||
for i := range b {
|
||||
if decodeBase58Map[b[i]] == 0xFF {
|
||||
return -1, ErrInvalidBase58
|
||||
}
|
||||
id = id*58 + int64(decodeBase58Map[b[i]])
|
||||
}
|
||||
|
||||
return ID(id), nil
|
||||
}
|
||||
|
||||
// Base64 returns a base64 string of the snowflake ID
|
||||
func (f ID) Base64() string {
|
||||
return base64.StdEncoding.EncodeToString(f.Bytes())
|
||||
}
|
||||
|
||||
// ParseBase64 converts a base64 string into a snowflake ID
|
||||
func ParseBase64(id string) (ID, error) {
|
||||
b, err := base64.StdEncoding.DecodeString(id)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return ParseBytes(b)
|
||||
|
||||
}
|
||||
|
||||
// Bytes returns a byte slice of the snowflake ID
|
||||
func (f ID) Bytes() []byte {
|
||||
return []byte(f.String())
|
||||
}
|
||||
|
||||
// ParseBytes converts a byte slice into a snowflake ID
|
||||
func ParseBytes(id []byte) (ID, error) {
|
||||
i, err := strconv.ParseInt(string(id), 10, 64)
|
||||
return ID(i), err
|
||||
}
|
||||
|
||||
// IntBytes returns an array of bytes of the snowflake ID, encoded as a
|
||||
// big endian integer.
|
||||
func (f ID) IntBytes() [8]byte {
|
||||
var b [8]byte
|
||||
binary.BigEndian.PutUint64(b[:], uint64(f))
|
||||
return b
|
||||
}
|
||||
|
||||
// ParseIntBytes converts an array of bytes encoded as big endian integer as
|
||||
// a snowflake ID
|
||||
func ParseIntBytes(id [8]byte) ID {
|
||||
return ID(int64(binary.BigEndian.Uint64(id[:])))
|
||||
}
|
||||
|
||||
// Time returns an int64 unix timestamp in milliseconds of the snowflake ID time
|
||||
// DEPRECATED: the below function will be removed in a future release.
|
||||
func (f ID) Time() int64 {
|
||||
return (int64(f) >> timeShift) + Epoch
|
||||
}
|
||||
|
||||
// Node returns an int64 of the snowflake ID node number
|
||||
// DEPRECATED: the below function will be removed in a future release.
|
||||
func (f ID) Node() int64 {
|
||||
return int64(f) & nodeMask >> nodeShift
|
||||
}
|
||||
|
||||
// Step returns an int64 of the snowflake step (or sequence) number
|
||||
// DEPRECATED: the below function will be removed in a future release.
|
||||
func (f ID) Step() int64 {
|
||||
return int64(f) & stepMask
|
||||
}
|
||||
|
||||
// MarshalJSON returns a json byte array string of the snowflake ID.
|
||||
func (f ID) MarshalJSON() ([]byte, error) {
|
||||
buff := make([]byte, 0, 22)
|
||||
buff = append(buff, '"')
|
||||
buff = strconv.AppendInt(buff, int64(f), 10)
|
||||
buff = append(buff, '"')
|
||||
return buff, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON converts a json byte array of a snowflake ID into an ID type.
|
||||
func (f *ID) UnmarshalJSON(b []byte) error {
|
||||
if len(b) < 3 || b[0] != '"' || b[len(b)-1] != '"' {
|
||||
return JSONSyntaxError{b}
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(string(b[1:len(b)-1]), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*f = ID(i)
|
||||
return nil
|
||||
}
|
476
myglobal/snowflake/snowflake_test.go
Normal file
476
myglobal/snowflake/snowflake_test.go
Normal file
@@ -0,0 +1,476 @@
|
||||
package snowflake
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
//******************************************************************************
|
||||
// General Test funcs
|
||||
|
||||
func TestNewNode(t *testing.T) {
|
||||
|
||||
_, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
_, err = NewNode(5000)
|
||||
if err == nil {
|
||||
t.Fatalf("no error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// lazy check if Generate will create duplicate IDs
|
||||
// would be good to later enhance this with more smarts
|
||||
func TestGenerateDuplicateID(t *testing.T) {
|
||||
|
||||
node, _ := NewNode(1)
|
||||
|
||||
var x, y ID
|
||||
for i := 0; i < 1000000; i++ {
|
||||
y = node.Generate()
|
||||
if x == y {
|
||||
t.Errorf("x(%d) & y(%d) are the same", x, y)
|
||||
}
|
||||
x = y
|
||||
}
|
||||
}
|
||||
|
||||
// I feel like there's probably a better way
|
||||
func TestRace(t *testing.T) {
|
||||
|
||||
node, _ := NewNode(1)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 1000000000; i++ {
|
||||
|
||||
NewNode(1)
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < 4000; i++ {
|
||||
|
||||
node.Generate()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Converters/Parsers Test funcs
|
||||
// We should have funcs here to test conversion both ways for everything
|
||||
|
||||
func TestPrintAll(t *testing.T) {
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
id := node.Generate()
|
||||
|
||||
t.Logf("Int64 : %#v", id.Int64())
|
||||
t.Logf("String : %#v", id.String())
|
||||
t.Logf("Base2 : %#v", id.Base2())
|
||||
t.Logf("Base32 : %#v", id.Base32())
|
||||
t.Logf("Base36 : %#v", id.Base36())
|
||||
t.Logf("Base58 : %#v", id.Base58())
|
||||
t.Logf("Base64 : %#v", id.Base64())
|
||||
t.Logf("Bytes : %#v", id.Bytes())
|
||||
t.Logf("IntBytes : %#v", id.IntBytes())
|
||||
|
||||
}
|
||||
|
||||
func TestInt64(t *testing.T) {
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
oID := node.Generate()
|
||||
i := oID.Int64()
|
||||
|
||||
pID := ParseInt64(i)
|
||||
if pID != oID {
|
||||
t.Fatalf("pID %v != oID %v", pID, oID)
|
||||
}
|
||||
|
||||
mi := int64(1116766490855473152)
|
||||
pID = ParseInt64(mi)
|
||||
if pID.Int64() != mi {
|
||||
t.Fatalf("pID %v != mi %v", pID.Int64(), mi)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
oID := node.Generate()
|
||||
si := oID.String()
|
||||
|
||||
pID, err := ParseString(si)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
|
||||
if pID != oID {
|
||||
t.Fatalf("pID %v != oID %v", pID, oID)
|
||||
}
|
||||
|
||||
ms := `1116766490855473152`
|
||||
_, err = ParseString(ms)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
|
||||
ms = `1112316766490855473152`
|
||||
_, err = ParseString(ms)
|
||||
if err == nil {
|
||||
t.Fatalf("no error parsing %s", ms)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase2(t *testing.T) {
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
oID := node.Generate()
|
||||
i := oID.Base2()
|
||||
|
||||
pID, err := ParseBase2(i)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
if pID != oID {
|
||||
t.Fatalf("pID %v != oID %v", pID, oID)
|
||||
}
|
||||
|
||||
ms := `111101111111101110110101100101001000000000000000000000000000`
|
||||
_, err = ParseBase2(ms)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
|
||||
ms = `1112316766490855473152`
|
||||
_, err = ParseBase2(ms)
|
||||
if err == nil {
|
||||
t.Fatalf("no error parsing %s", ms)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase32(t *testing.T) {
|
||||
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
|
||||
sf := node.Generate()
|
||||
b32i := sf.Base32()
|
||||
psf, err := ParseBase32([]byte(b32i))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sf != psf {
|
||||
t.Fatal("Parsed does not match String.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase36(t *testing.T) {
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
oID := node.Generate()
|
||||
i := oID.Base36()
|
||||
|
||||
pID, err := ParseBase36(i)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
if pID != oID {
|
||||
t.Fatalf("pID %v != oID %v", pID, oID)
|
||||
}
|
||||
|
||||
ms := `8hgmw4blvlkw`
|
||||
_, err = ParseBase36(ms)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
|
||||
ms = `68h5gmw443blv2lk1w`
|
||||
_, err = ParseBase36(ms)
|
||||
if err == nil {
|
||||
t.Fatalf("no error parsing, %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase58(t *testing.T) {
|
||||
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
|
||||
sf := node.Generate()
|
||||
b58 := sf.Base58()
|
||||
psf, err := ParseBase58([]byte(b58))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sf != psf {
|
||||
t.Fatal("Parsed does not match String.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase64(t *testing.T) {
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
oID := node.Generate()
|
||||
i := oID.Base64()
|
||||
|
||||
pID, err := ParseBase64(i)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
if pID != oID {
|
||||
t.Fatalf("pID %v != oID %v", pID, oID)
|
||||
}
|
||||
|
||||
ms := `MTExNjgxOTQ5NDY2MDk5NzEyMA==`
|
||||
_, err = ParseBase64(ms)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
|
||||
ms = `MTExNjgxOTQ5NDY2MDk5NzEyMA`
|
||||
_, err = ParseBase64(ms)
|
||||
if err == nil {
|
||||
t.Fatalf("no error parsing, %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
oID := node.Generate()
|
||||
i := oID.Bytes()
|
||||
|
||||
pID, err := ParseBytes(i)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %s", err)
|
||||
}
|
||||
if pID != oID {
|
||||
t.Fatalf("pID %v != oID %v", pID, oID)
|
||||
}
|
||||
|
||||
ms := []byte{0x31, 0x31, 0x31, 0x36, 0x38, 0x32, 0x31, 0x36, 0x37, 0x39, 0x35, 0x37, 0x30, 0x34, 0x31, 0x39, 0x37, 0x31, 0x32}
|
||||
_, err = ParseBytes(ms)
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing, %#v", err)
|
||||
}
|
||||
|
||||
ms = []byte{0xFF, 0xFF, 0xFF, 0x31, 0x31, 0x31, 0x36, 0x38, 0x32, 0x31, 0x36, 0x37, 0x39, 0x35, 0x37, 0x30, 0x34, 0x31, 0x39, 0x37, 0x31, 0x32}
|
||||
_, err = ParseBytes(ms)
|
||||
if err == nil {
|
||||
t.Fatalf("no error parsing, %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntBytes(t *testing.T) {
|
||||
node, err := NewNode(0)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating NewNode, %s", err)
|
||||
}
|
||||
|
||||
oID := node.Generate()
|
||||
i := oID.IntBytes()
|
||||
|
||||
pID := ParseIntBytes(i)
|
||||
if pID != oID {
|
||||
t.Fatalf("pID %v != oID %v", pID, oID)
|
||||
}
|
||||
|
||||
ms := [8]uint8{0xf, 0x7f, 0xc0, 0xfc, 0x2f, 0x80, 0x0, 0x0}
|
||||
mi := int64(1116823421972381696)
|
||||
pID = ParseIntBytes(ms)
|
||||
if pID.Int64() != mi {
|
||||
t.Fatalf("pID %v != mi %v", pID.Int64(), mi)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Marshall Test Methods
|
||||
|
||||
func TestMarshalJSON(t *testing.T) {
|
||||
id := ID(13587)
|
||||
expected := "\"13587\""
|
||||
|
||||
bytes, err := id.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error during MarshalJSON")
|
||||
}
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Got %s, expected %s", string(bytes), expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalsIntBytes(t *testing.T) {
|
||||
id := ID(13587).IntBytes()
|
||||
expected := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x35, 0x13}
|
||||
if !bytes.Equal(id[:], expected) {
|
||||
t.Fatalf("Expected ID to be encoded as %v, got %v", expected, id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalJSON(t *testing.T) {
|
||||
tt := []struct {
|
||||
json string
|
||||
expectedID ID
|
||||
expectedErr error
|
||||
}{
|
||||
{`"13587"`, 13587, nil},
|
||||
{`1`, 0, JSONSyntaxError{[]byte(`1`)}},
|
||||
{`"invalid`, 0, JSONSyntaxError{[]byte(`"invalid`)}},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
var id ID
|
||||
err := id.UnmarshalJSON([]byte(tc.json))
|
||||
if !reflect.DeepEqual(err, tc.expectedErr) {
|
||||
t.Fatalf("Expected to get error '%s' decoding JSON, but got '%s'", tc.expectedErr, err)
|
||||
}
|
||||
|
||||
if id != tc.expectedID {
|
||||
t.Fatalf("Expected to get ID '%s' decoding JSON, but got '%s'", tc.expectedID, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Benchmark Methods
|
||||
|
||||
func BenchmarkParseBase32(b *testing.B) {
|
||||
|
||||
node, _ := NewNode(1)
|
||||
sf := node.Generate()
|
||||
b32i := sf.Base32()
|
||||
|
||||
b.ReportAllocs()
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
ParseBase32([]byte(b32i))
|
||||
}
|
||||
}
|
||||
func BenchmarkBase32(b *testing.B) {
|
||||
|
||||
node, _ := NewNode(1)
|
||||
sf := node.Generate()
|
||||
|
||||
b.ReportAllocs()
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
sf.Base32()
|
||||
}
|
||||
}
|
||||
func BenchmarkParseBase58(b *testing.B) {
|
||||
|
||||
node, _ := NewNode(1)
|
||||
sf := node.Generate()
|
||||
b58 := sf.Base58()
|
||||
|
||||
b.ReportAllocs()
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
ParseBase58([]byte(b58))
|
||||
}
|
||||
}
|
||||
func BenchmarkBase58(b *testing.B) {
|
||||
|
||||
node, _ := NewNode(1)
|
||||
sf := node.Generate()
|
||||
|
||||
b.ReportAllocs()
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
sf.Base58()
|
||||
}
|
||||
}
|
||||
func BenchmarkGenerate(b *testing.B) {
|
||||
|
||||
node, _ := NewNode(1)
|
||||
|
||||
b.ReportAllocs()
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = node.Generate()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGenerateMaxSequence(b *testing.B) {
|
||||
|
||||
NodeBits = 1
|
||||
StepBits = 21
|
||||
node, _ := NewNode(1)
|
||||
|
||||
b.ReportAllocs()
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = node.Generate()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnmarshal(b *testing.B) {
|
||||
// Generate the ID to unmarshal
|
||||
node, _ := NewNode(1)
|
||||
id := node.Generate()
|
||||
bytes, _ := id.MarshalJSON()
|
||||
|
||||
var id2 ID
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = id2.UnmarshalJSON(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMarshal(b *testing.B) {
|
||||
// Generate the ID to marshal
|
||||
node, _ := NewNode(1)
|
||||
id := node.Generate()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
_, _ = id.MarshalJSON()
|
||||
}
|
||||
}
|
@@ -33,7 +33,7 @@ func (i *MySqlDB) OnGetDBOrm(dataSourceName string) (orm *gorm.DB) {
|
||||
}
|
||||
|
||||
i.DB.SingularTable(true) //全局禁用表名复数
|
||||
if dev.OnIsDev() {
|
||||
if dev.IsDev() {
|
||||
i.DB.LogMode(true)
|
||||
//beedb.OnDebug = true
|
||||
} else {
|
||||
|
@@ -32,14 +32,14 @@ func InitWxinfo(info WxInfo) {
|
||||
rootcaFile = tools.GetModelPath() + rootcaFileLoc
|
||||
|
||||
//使用memcache保存access_token,也可选择redis或自定义cache
|
||||
memCache := NewGocache("_winxin_access")
|
||||
//memCache := NewGocache("_winxin_access")
|
||||
//配置微信参数
|
||||
cfg = wechat.Config{
|
||||
AppID: wxInfo.APIKey,
|
||||
AppSecret: wxInfo.AppSecret,
|
||||
Token: wxInfo.Token,
|
||||
EncodingAESKey: wxInfo.EncodingAESKey,
|
||||
Cache: memCache,
|
||||
//Cache: memCache,
|
||||
}
|
||||
client = wxpay.NewClient(wxInfo.AppID, wxInfo.MchID, wxInfo.APIKey)
|
||||
client.WithCert(certFile, keyFile, rootcaFile)
|
||||
|
Reference in New Issue
Block a user