123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- using System;
- using System.Linq;
- using System.Net.NetworkInformation;
- using Masuit.Tools.DateTimeExt;
- using Masuit.Tools.Hardware;
- using Masuit.Tools.Strings;
- namespace Masuit.Tools.Systems;
- /// <summary>
- /// 改良版雪花id
- /// </summary>
- public class SnowFlakeNew
- {
- private static long _workerId; //机器ID
- private const long Twepoch = 1692079923000L; //唯一时间随机量
- private static long _offset = 7783685984256L; //起始偏移量
- private static long _sequence;
- private const int SequenceBits = 12; //计数器字节数,10个字节用来保存计数码
- private const long SequenceMask = -1L ^ -1L << SequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
- private static long _lastTimestamp = -1L;
- private static readonly object LockObj = new();
- private static NumberFormater _numberFormater = new(36);
- private static SnowFlakeNew _snowFlake;
- /// <summary>
- /// 获取一个新的id
- /// </summary>
- public static string NewId => GetInstance().GetUniqueId();
- /// <summary>
- /// 获取一个新的id
- /// </summary>
- public static long LongId => GetInstance().GetLongId();
- /// <summary>
- /// 创建一个实例
- /// </summary>
- /// <returns></returns>
- public static SnowFlakeNew GetInstance()
- {
- return _snowFlake ??= new SnowFlakeNew();
- }
- /// <summary>
- /// 默认构造函数
- /// </summary>
- public SnowFlakeNew()
- { }
- /// <summary>
- /// 默认构造函数
- /// </summary>
- static SnowFlakeNew()
- {
- try
- {
- var mac = SystemInfo.GetMacAddress().FirstOrDefault(a => a.GetAddressBytes().Length > 0);
- if (mac != null)
- {
- var bytes = mac.GetAddressBytes();
- _workerId = bytes[4] << 2 | bytes[5];
- }
- else
- {
- var ip = SystemInfo.GetLocalUsedIP();
- if (ip != null)
- {
- var bytes = ip.GetAddressBytes();
- _workerId = bytes[3];
- }
- }
- }
- catch
- {
- _workerId = 0;
- }
- }
- /// <summary>
- /// 构造函数
- /// </summary>
- /// <param name="machineId">机器码</param>
- public SnowFlakeNew(int machineId)
- {
- SetMachienId(machineId);
- }
- public static void SetMachienId(long machineId)
- {
- if (machineId >= 0)
- {
- if (machineId > 1024)
- {
- throw new Exception("机器码ID非法");
- }
- _workerId = machineId;
- }
- }
- /// <summary>
- /// 设置起始偏移量
- /// </summary>
- /// <param name="offset"></param>
- public static void SetInitialOffset(long offset)
- {
- _offset = offset;
- }
- /// <summary>
- /// 设置数制格式化器
- /// </summary>
- /// <param name="nf"></param>
- public static void SetNumberFormater(NumberFormater nf)
- {
- _numberFormater = nf;
- }
- public long GetLongId()
- {
- lock (LockObj)
- {
- long timestamp = DateTime.Now.GetTotalMilliseconds();
- if (_lastTimestamp == timestamp)
- { //同一微妙中生成ID
- _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
- if (_sequence == 0)
- {
- //一微妙内产生的ID计数已达上限,等待下一微妙
- timestamp = DateTime.Now.GetTotalMilliseconds();
- while (timestamp <= _lastTimestamp)
- {
- timestamp = DateTime.Now.GetTotalMilliseconds();
- }
- return timestamp;
- }
- }
- else
- { //不同微秒生成ID
- _sequence = 0; //计数清0
- }
- if (timestamp < _lastTimestamp)
- { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
- throw new Exception($"Clock moved backwards. Refusing to generate id for {_lastTimestamp - timestamp} milliseconds");
- }
- _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
- return (_workerId << 52 | (timestamp - Twepoch << 12) | _sequence) - _offset;
- }
- }
- /// <summary>
- /// 获取一个字符串表示形式的id
- /// </summary>
- /// <returns></returns>
- public string GetUniqueId()
- {
- return _numberFormater.ToString(GetLongId());
- }
- /// <summary>
- /// 获取一个字符串表示形式的id
- /// </summary>
- /// <param name="maxLength">最大长度,至少6位</param>
- /// <returns></returns>
- public string GetUniqueShortId(int maxLength = 8)
- {
- if (maxLength < 6)
- {
- throw new ArgumentException("最大长度至少需要6位");
- }
- string id = GetUniqueId();
- int index = id.Length - maxLength;
- if (index < 0)
- {
- index = 0;
- }
- return id.Substring(index);
- }
- }
|