Rename to snowflake
This commit is contained in:
150
snowflake.go
Normal file
150
snowflake.go
Normal file
@@ -0,0 +1,150 @@
|
||||
// Package snowflake provides a very simple Twitter snowflake generator and parser.
|
||||
package snowflake
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
timeBits = 41
|
||||
nodeBits = 10
|
||||
stepBits = 12
|
||||
|
||||
timeMask int64 = -1 ^ (-1 << timeBits)
|
||||
nodeMask int64 = -1 ^ (-1 << nodeBits)
|
||||
stepMask int64 = -1 ^ (-1 << stepBits)
|
||||
|
||||
nodeMax = -1 ^ (-1 << nodeBits)
|
||||
|
||||
timeShift uint8 = nodeBits + stepBits
|
||||
nodeShift uint8 = stepBits
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
// A Node struct holds the basic information needed for a snowflake generator
|
||||
// node
|
||||
type Node struct {
|
||||
sync.Mutex
|
||||
time int64
|
||||
node int64
|
||||
step int64
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
if node < 0 || node > nodeMax {
|
||||
return nil, fmt.Errorf("Node number must be between 0 and 1023")
|
||||
}
|
||||
|
||||
return &Node{
|
||||
time: 0,
|
||||
node: node,
|
||||
step: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Generate creates and returns a unique snowflake ID
|
||||
func (n *Node) Generate() (ID, error) {
|
||||
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
now := time.Now().UnixNano() / 1000000
|
||||
|
||||
if n.time == now {
|
||||
n.step = (n.step + 1) & stepMask
|
||||
|
||||
if n.step == 0 {
|
||||
for now <= n.time {
|
||||
now = time.Now().UnixNano() / 1000000
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n.step = 0
|
||||
}
|
||||
|
||||
n.time = now
|
||||
|
||||
return ID((now-Epoch)<<timeShift |
|
||||
(n.node << nodeShift) |
|
||||
(n.step),
|
||||
), nil
|
||||
}
|
||||
|
||||
// Int64 returns an int64 of the snowflake ID
|
||||
func (f ID) Int64() int64 {
|
||||
return int64(f)
|
||||
}
|
||||
|
||||
// String returns a string of the snowflake ID
|
||||
func (f ID) String() string {
|
||||
return fmt.Sprintf("%d", f)
|
||||
}
|
||||
|
||||
// Base2 returns a string base2 of the snowflake ID
|
||||
func (f ID) Base2() string {
|
||||
return strconv.FormatInt(int64(f), 2)
|
||||
}
|
||||
|
||||
// Base36 returns a base36 string of the snowflake ID
|
||||
func (f ID) Base36() string {
|
||||
return strconv.FormatInt(int64(f), 36)
|
||||
}
|
||||
|
||||
// Base64 returns a base64 string of the snowflake ID
|
||||
func (f ID) Base64() string {
|
||||
return base64.StdEncoding.EncodeToString(f.Bytes())
|
||||
}
|
||||
|
||||
// Bytes returns a byte array of the snowflake ID
|
||||
func (f ID) Bytes() []byte {
|
||||
return []byte(f.String())
|
||||
}
|
||||
|
||||
// Time returns an int64 unix timestamp of the snowflake ID time
|
||||
func (f ID) Time() int64 {
|
||||
return (int64(f) >> 22) + Epoch
|
||||
}
|
||||
|
||||
// Node returns an int64 of the snowflake ID node number
|
||||
func (f ID) Node() int64 {
|
||||
return int64(f) & 0x00000000003FF000 >> 12
|
||||
}
|
||||
|
||||
// Step returns an int64 of the snowflake step (or sequence) number
|
||||
func (f ID) Step() int64 {
|
||||
return int64(f) & 0x0000000000000FFF
|
||||
}
|
||||
|
||||
// MarshalJSON returns a json byte array string of the snowflake ID.
|
||||
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 {
|
||||
|
||||
s := strings.Replace(string(b), `"`, ``, 2)
|
||||
i, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*f = ID(i)
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user