github.com/wfusion/gofusion@v1.1.14/common/infra/drivers/orm/idgen/snowflake.go (about)

     1  package idgen
     2  
     3  import (
     4  	"fmt"
     5  	"hash/fnv"
     6  	"log"
     7  	"net"
     8  	"os"
     9  	"reflect"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/sony/sonyflake"
    14  
    15  	"github.com/wfusion/gofusion/common/utils"
    16  )
    17  
    18  var (
    19  	// NewSnowflakeType FIXME: should not be deleted to avoid compiler optimized
    20  	NewSnowflakeType = reflect.TypeOf(NewSnowflake)
    21  
    22  	snowflakeOnce     sync.Once
    23  	snowflakeInstance *snowflake
    24  )
    25  
    26  type snowflake struct {
    27  	instance *sonyflake.Sonyflake
    28  }
    29  
    30  // NewSnowflake it should be only one snowflake generator per service instance
    31  func NewSnowflake() Generator {
    32  	snowflakeOnce.Do(func() {
    33  		flake := sonyflake.NewSonyflake(sonyflake.Settings{
    34  			StartTime: time.Time{},
    35  			// machine id: hash(host ip + local ip + pid)(8 bit) - local ip(8 bit)
    36  			MachineID: func() (id uint16, err error) {
    37  				pid := os.Getpid()
    38  				hostIP := utils.HostIPInDocker()
    39  				localIP := utils.ClientIP()
    40  				log.Printf("[Common] snowflake get machine id base [host[%s] local[%s] pid[%v]]", hostIP, localIP, pid)
    41  				if hostIP == "" {
    42  					hostIP = utils.ClientIP()
    43  				}
    44  				hash := fnv.New32a()
    45  				_, err = hash.Write([]byte(fmt.Sprintf("%s%s%v", hostIP, localIP, pid)))
    46  				if err != nil {
    47  					return
    48  				}
    49  
    50  				high := byte(hash.Sum32() % 255)
    51  				low := net.ParseIP(localIP).To4()[3]
    52  				id = uint16(high)<<8 | uint16(low)
    53  				log.Printf("[Common] snowflake get machine id [%X]", id)
    54  				return
    55  			},
    56  			CheckMachineID: nil,
    57  		})
    58  		if flake == nil {
    59  			panic(ErrNewGenerator)
    60  		}
    61  		snowflakeInstance = &snowflake{instance: flake}
    62  	})
    63  
    64  	return snowflakeInstance
    65  }
    66  
    67  func (s *snowflake) Next(opts ...utils.OptionExtender) (id uint64, err error) {
    68  	return s.instance.NextID()
    69  }