From 765b6319bb849fd03307950e4b8b7ecc7363e7c1 Mon Sep 17 00:00:00 2001 From: Guilherme Werner Date: Thu, 11 Dec 2025 10:14:38 -0300 Subject: [PATCH] Add snowflake generator --- Directory.Packages.props | 1 + src/Tribufu.Database/FlakeGenerator.cs | 45 ++++++++++++++++++++ src/Tribufu.Database/Tribufu.Database.csproj | 1 + 3 files changed, 47 insertions(+) create mode 100644 src/Tribufu.Database/FlakeGenerator.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 94e2d6a..e71f9dc 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,6 +4,7 @@ + diff --git a/src/Tribufu.Database/FlakeGenerator.cs b/src/Tribufu.Database/FlakeGenerator.cs new file mode 100644 index 0000000..c48765e --- /dev/null +++ b/src/Tribufu.Database/FlakeGenerator.cs @@ -0,0 +1,45 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: UNLICENSED + +using IdGen; +using System; + +namespace Tribufu.Database +{ + public static class FlakeGenerator + { + public static readonly DateTime EPOCH = new(2016, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + private static readonly IdStructure _structure = new(41, 10, 12); + + private static readonly IdGeneratorOptions _options = new(_structure, new DefaultTimeSource(EPOCH)); + + private static readonly IdGenerator _generator = new(0, _options); + + public static ulong New() + { + //Console.WriteLine("Max. generators : {0}", _structure.MaxGenerators); + //Console.WriteLine("Id's/ms per generator : {0}", _structure.MaxSequenceIds); + //Console.WriteLine("Id's/ms total : {0}", _structure.MaxGenerators * _structure.MaxSequenceIds); + //Console.WriteLine("Wraparound interval : {0}", _structure.WraparoundInterval(_generator.Options.TimeSource)); + //Console.WriteLine("Wraparound date : {0}", _structure.WraparoundDate(_generator.Options.TimeSource.Epoch, _generator.Options.TimeSource).ToString("O")); + + return (ulong)_generator.CreateId(); + } + + public static ulong FromTimestamp(DateTime timestamp, ushort sequence = 0) + { + var diff = (long)(timestamp - EPOCH).TotalMilliseconds; + if (diff < 0 || diff > (1L << 41) - 1) + { + throw new ArgumentOutOfRangeException(nameof(timestamp), "Timestamp out of range for flake."); + } + + ulong timestampPart = (ulong)diff << 22; // 41 bits << (10+12) + ulong generatorPart = 0ul << 12; // Always 0 + ulong sequencePart = (ulong)(sequence & 0xFFF); // 12 bits + + return timestampPart | generatorPart | sequencePart; + } + } +} diff --git a/src/Tribufu.Database/Tribufu.Database.csproj b/src/Tribufu.Database/Tribufu.Database.csproj index 03a7813..3f0e397 100644 --- a/src/Tribufu.Database/Tribufu.Database.csproj +++ b/src/Tribufu.Database/Tribufu.Database.csproj @@ -16,6 +16,7 @@ +