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; /// /// 改良版雪花id /// 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; /// /// 获取一个新的id /// public static string NewId => GetInstance().GetUniqueId(); /// /// 获取一个新的id /// public static long LongId => GetInstance().GetLongId(); /// /// 创建一个实例 /// /// public static SnowFlakeNew GetInstance() { return _snowFlake ??= new SnowFlakeNew(); } /// /// 默认构造函数 /// public SnowFlakeNew() { } /// /// 默认构造函数 /// 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; } } /// /// 构造函数 /// /// 机器码 public SnowFlakeNew(int machineId) { SetMachienId(machineId); } public static void SetMachienId(long machineId) { if (machineId >= 0) { if (machineId > 1024) { throw new Exception("机器码ID非法"); } _workerId = machineId; } } /// /// 设置起始偏移量 /// /// public static void SetInitialOffset(long offset) { _offset = offset; } /// /// 设置数制格式化器 /// /// 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; } } /// /// 获取一个字符串表示形式的id /// /// public string GetUniqueId() { return _numberFormater.ToString(GetLongId()); } /// /// 获取一个字符串表示形式的id /// /// 最大长度,至少6位 /// 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); } }