Files
HTCloud/HT.Cloud.Code/DistributedIDGenerator/Generators/SequentialGuidIDGenerator.cs
2023-03-03 16:07:50 +08:00

86 lines
2.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// -----------------------------------------------------------------------------
// 让 .NET 开发更简单,更通用,更流行。
// Copyright © 2020-2021 Furion, 百小僧, Baiqian Co.,Ltd.
//
// 框架名称Furion
// 框架作者:百小僧
// 框架版本2.7.9
// 源码地址Gitee https://gitee.com/dotnetchina/Furion
// Githubhttps://github.com/monksoul/Furion
// 开源协议Apache-2.0https://gitee.com/dotnetchina/Furion/blob/master/LICENSE
// -----------------------------------------------------------------------------
using System;
using System.Security.Cryptography;
namespace HT.Cloud.Code
{
/// <summary>
/// 连续 GUID ID 生成器
/// <para>代码参考自https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/blob/ebe011a6f1b2a2a9709fe558cfc7ed3215b55c37/src/EFCore.MySql/ValueGeneration/Internal/MySqlSequentialGuidValueGenerator.cs </para>
/// </summary>
public class SequentialGuidIDGenerator : IDistributedIDGenerator
{
/// <summary>
/// 随机数生成器
/// </summary>
private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create();
/// <summary>
/// 生成逻辑
/// </summary>
/// <param name="idGeneratorOptions"></param>
/// <returns></returns>
public object Create(object idGeneratorOptions = null)
{
// According to RFC 4122:
// dddddddd-dddd-Mddd-Ndrr-rrrrrrrrrrrr
// - M = RFC version, in this case '4' for random UUID
// - N = RFC variant (plus other bits), in this case 0b1000 for variant 1
// - d = nibbles based on UTC date/time in ticks
// - r = nibbles based on random bytes
var options = (idGeneratorOptions ?? new SequentialGuidSettings()) as SequentialGuidSettings;
var randomBytes = new byte[7];
_rng.GetBytes(randomBytes);
var ticks = (ulong)options.TimeNow.Ticks;
var uuidVersion = (ushort)4;
var uuidVariant = (ushort)0b1000;
var ticksAndVersion = (ushort)((ticks << 48 >> 52) | (ushort)(uuidVersion << 12));
var ticksAndVariant = (byte)((ticks << 60 >> 60) | (byte)(uuidVariant << 4));
if (options.LittleEndianBinary16Format)
{
var guidBytes = new byte[16];
var tickBytes = BitConverter.GetBytes(ticks);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(tickBytes);
}
Buffer.BlockCopy(tickBytes, 0, guidBytes, 0, 6);
guidBytes[6] = (byte)(ticksAndVersion << 8 >> 8);
guidBytes[7] = (byte)(ticksAndVersion >> 8);
guidBytes[8] = ticksAndVariant;
Buffer.BlockCopy(randomBytes, 0, guidBytes, 9, 7);
return new Guid(guidBytes);
}
var guid = new Guid((uint)(ticks >> 32), (ushort)(ticks << 32 >> 48), ticksAndVersion,
ticksAndVariant,
randomBytes[0],
randomBytes[1],
randomBytes[2],
randomBytes[3],
randomBytes[4],
randomBytes[5],
randomBytes[6]);
return guid;
}
}
}