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);
}
}