snowflake/snowflake.go

142 lines
3.0 KiB
Go
Raw Normal View History

2016-06-01 16:12:53 -05:00
// Package snowflake provides a very simple Twitter snowflake generator and parser.
package snowflake
2016-05-25 14:57:33 -05:00
2016-06-01 14:59:26 -05:00
import (
"encoding/base64"
"errors"
2016-06-01 14:59:26 -05:00
"strconv"
"sync"
"time"
)
2016-05-25 14:57:33 -05:00
const (
nodeBits = 10
stepBits = 12
nodeMax = -1 ^ (-1 << nodeBits)
stepMask int64 = -1 ^ (-1 << stepBits)
2016-06-01 14:59:26 -05:00
timeShift uint8 = nodeBits + stepBits
nodeShift uint8 = stepBits
2016-05-25 14:57:33 -05:00
)
2016-06-01 14:59:26 -05:00
// Epoch is set to the twitter snowflake epoch of 2006-03-21:20:50:14 GMT
// You may customize this to set a different epoch for your application.
var Epoch int64 = 1288834974657
2016-05-25 14:57:33 -05:00
2016-06-01 16:12:53 -05:00
// A Node struct holds the basic information needed for a snowflake generator
// node
2016-06-01 14:59:26 -05:00
type Node struct {
sync.Mutex
time int64
node int64
step int64
2016-05-25 14:57:33 -05:00
}
2016-06-01 14:59:26 -05:00
// 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
2016-06-01 16:12:53 -05:00
// NewNode returns a new snowflake node that can be used to generate snowflake
// IDs
2016-06-01 14:59:26 -05:00
func NewNode(node int64) (*Node, error) {
2016-05-25 14:57:33 -05:00
2016-06-01 14:59:26 -05:00
if node < 0 || node > nodeMax {
return nil, errors.New("Node number must be between 0 and 1024")
2016-05-25 14:57:33 -05:00
}
return &Node{
2016-06-01 14:59:26 -05:00
time: 0,
node: node,
step: 0,
2016-05-25 14:57:33 -05:00
}, nil
}
2016-06-01 14:59:26 -05:00
// Generate creates and returns a unique snowflake ID
func (n *Node) Generate() (ID, error) {
2016-05-25 14:57:33 -05:00
n.Lock()
defer n.Unlock()
now := time.Now().UnixNano() / 1000000
2016-06-01 14:59:26 -05:00
if n.time == now {
n.step = (n.step + 1) & stepMask
2016-05-25 16:25:52 -05:00
if n.step == 0 {
2016-06-01 14:59:26 -05:00
for now <= n.time {
2016-05-25 16:25:52 -05:00
now = time.Now().UnixNano() / 1000000
}
}
} else {
n.step = 0
}
2016-06-01 14:59:26 -05:00
n.time = now
2016-05-25 16:25:52 -05:00
2016-06-01 14:59:26 -05:00
return ID((now-Epoch)<<timeShift |
(n.node << nodeShift) |
2016-05-25 16:25:52 -05:00
(n.step),
), nil
}
2016-06-01 14:59:26 -05:00
// Int64 returns an int64 of the snowflake ID
func (f ID) Int64() int64 {
return int64(f)
2016-05-25 16:25:52 -05:00
}
2016-06-01 14:59:26 -05:00
// String returns a string of the snowflake ID
func (f ID) String() string {
return strconv.FormatInt(int64(f), 10)
2016-05-25 14:57:33 -05:00
}
2016-06-01 14:59:26 -05:00
// Base2 returns a string base2 of the snowflake ID
func (f ID) Base2() string {
2016-05-25 14:57:33 -05:00
return strconv.FormatInt(int64(f), 2)
}
2016-06-01 14:59:26 -05:00
// Base36 returns a base36 string of the snowflake ID
func (f ID) Base36() string {
2016-05-25 14:57:33 -05:00
return strconv.FormatInt(int64(f), 36)
}
2016-06-01 14:59:26 -05:00
// Base64 returns a base64 string of the snowflake ID
func (f ID) Base64() string {
return base64.StdEncoding.EncodeToString(f.Bytes())
2016-05-25 14:57:33 -05:00
}
2016-06-01 14:59:26 -05:00
// Bytes returns a byte array of the snowflake ID
func (f ID) Bytes() []byte {
2016-05-25 14:57:33 -05:00
return []byte(f.String())
}
2016-06-01 14:59:26 -05:00
// Time returns an int64 unix timestamp of the snowflake ID time
func (f ID) Time() int64 {
2016-05-25 14:57:33 -05:00
return (int64(f) >> 22) + Epoch
}
2016-06-01 14:59:26 -05:00
// Node returns an int64 of the snowflake ID node number
func (f ID) Node() int64 {
2016-05-25 14:57:33 -05:00
return int64(f) & 0x00000000003FF000 >> 12
}
2016-06-01 14:59:26 -05:00
// Step returns an int64 of the snowflake step (or sequence) number
func (f ID) Step() int64 {
2016-05-25 14:57:33 -05:00
return int64(f) & 0x0000000000000FFF
}
2016-06-01 14:59:26 -05:00
2016-06-04 15:52:39 -05:00
// MarshalJSON returns a json byte array string of the snowflake ID.
2016-06-01 14:59:26 -05:00
func (f ID) MarshalJSON() ([]byte, error) {
return []byte(`"` + f.String() + `"`), nil
}
// UnmarshalJSON converts a json byte array of a snowflake ID into an ID type.
func (f *ID) UnmarshalJSON(b []byte) error {
i, err := strconv.ParseInt(string(b[1:len(b)-1]), 10, 64)
2016-06-01 14:59:26 -05:00
if err != nil {
return err
}
*f = ID(i)
return nil
}