uniflake 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/uniflake/generator_ids/number.rb +18 -0
- data/lib/uniflake/generators/discord.rb +8 -0
- data/lib/uniflake/generators/snowflake.rb +8 -0
- data/lib/uniflake/generators/uniflake.rb +65 -0
- data/lib/uniflake/sequence_resolvers/memory.rb +18 -0
- data/lib/uniflake/sequence_resolvers/random.rb +15 -0
- data/lib/uniflake/sequence_resolvers/redis.rb +37 -0
- data/lib/uniflake.rb +11 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f80b6d4ffd25a72a9a88dcec412a922514d9c6e631ac4244c9dfb3d2e590018f
|
4
|
+
data.tar.gz: 5405b316f49e42ce17876f062302d44d447d165152138cc2286ce04d7e176070
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 39ae675c29e7de6674043d050d0ce7b133316b481a5be6b4026dd013312afd2b49cc75717760db94b14095ea680db4d960a0576270408b8588e7306861d80c59
|
7
|
+
data.tar.gz: 7c9270a843f01f0600fd0212dfbdfad0d4d1a1e26b7c60c6b3f143194a9d3a34248001ce5bdf9aae22a403fe061ad1089a48756d12c9699ce178e2537ebb7023
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Uniflake
|
2
|
+
|
3
|
+
class Number
|
4
|
+
BIT_LENGTH = 10
|
5
|
+
MAX_ID = (1 << BIT_LENGTH) - 1
|
6
|
+
|
7
|
+
attr_reader :id
|
8
|
+
|
9
|
+
def initialize(id = 0)
|
10
|
+
raise OverflowError, "invalid generator id (#{id} > #{MAX_ID})" if id > MAX_ID
|
11
|
+
@id = id
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_i
|
15
|
+
@id
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Uniflake::Generators
|
2
|
+
|
3
|
+
class Uniflake
|
4
|
+
STRUCTURE = {
|
5
|
+
timestamp: 41,
|
6
|
+
generator_id: 10,
|
7
|
+
sequence: 12
|
8
|
+
}
|
9
|
+
|
10
|
+
DEFAULT_EPOCH_START_AT = Time.new(2022, 01, 01)
|
11
|
+
|
12
|
+
MAX_TIMESTAMP = (1 << STRUCTURE[:timestamp]) - 1
|
13
|
+
MAX_GENERATOR_ID = (1 << STRUCTURE[:generator_id]) - 1
|
14
|
+
MAX_SEQUENCE = (1 << STRUCTURE[:sequence]) - 1
|
15
|
+
|
16
|
+
def initialize(sequence_resolver, epoch_start_at = self::class::DEFAULT_EPOCH_START_AT, generator_id = 0)
|
17
|
+
@generator_id = generator_id.to_i
|
18
|
+
raise Error, "invalid generator_id (#{@generator_id} > #{self::class::MAX_GENERATOR_ID})" if @generator_id > self::class::MAX_GENERATOR_ID
|
19
|
+
|
20
|
+
@epoch_start_at = epoch_start_at.strftime('%s%L').to_i
|
21
|
+
now = Time.now.strftime('%s%L').to_i
|
22
|
+
raise Error, "invalid epoch (#{@epoch_start_at} > #{now})" if @epoch_start_at > now
|
23
|
+
|
24
|
+
@sequence_resolver = sequence_resolver
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate
|
28
|
+
now = Time.now.strftime('%s%L').to_i
|
29
|
+
|
30
|
+
sequence = @sequence_resolver.resolve(@generator_id, now, self::class::MAX_SEQUENCE)
|
31
|
+
raise Error, "invalid sequence (#{sequence} > #{self::class::MAX_SEQUENCE})" if sequence > self::class::MAX_SEQUENCE
|
32
|
+
|
33
|
+
timestamp = now - @epoch_start_at
|
34
|
+
raise Error, "invalid timestamp (#{timestamp} > #{self::class::MAX_TIMESTAMP})" if timestamp > self::class::MAX_TIMESTAMP
|
35
|
+
|
36
|
+
self.class.compose(timestamp, @generator_id, sequence)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.compose(timestamp, generator_id, sequence)
|
40
|
+
shift = 0
|
41
|
+
id = 0
|
42
|
+
self::STRUCTURE.keys.reverse.each do |field|
|
43
|
+
id += binding.local_variable_get(field) << shift
|
44
|
+
shift += self::STRUCTURE[field]
|
45
|
+
end
|
46
|
+
id
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse(id)
|
50
|
+
fields = self.class.parse(id)
|
51
|
+
fields[:timestamp] += @epoch_start_at if fields.has_key? :timestamp
|
52
|
+
fields
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.parse(id)
|
56
|
+
id = id.to_s(2).rjust(self::STRUCTURE.values.sum, "0")
|
57
|
+
fields = {}
|
58
|
+
self::STRUCTURE.each do |field, length|
|
59
|
+
fields[field] = id[0..length - 1].to_i(2)
|
60
|
+
id[0..length - 1] = id[length..-1]
|
61
|
+
end
|
62
|
+
fields
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Uniflake::SequenceResolvers
|
2
|
+
|
3
|
+
class Memory
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@sequences = {}
|
7
|
+
@last_time = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def resolve(int_generator_id, time, max_value = 0)
|
11
|
+
raise "invalid time" if time < @last_time[int_generator_id].to_i
|
12
|
+
|
13
|
+
@sequences[int_generator_id] = time == @last_time[int_generator_id].to_i ? @sequences[int_generator_id].to_i + 1 : 0
|
14
|
+
@last_time[int_generator_id] = time
|
15
|
+
@sequences[int_generator_id]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Uniflake::SequenceResolvers
|
2
|
+
|
3
|
+
class Random
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@prng = Random.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def resolve(int_generator_id, time, max_value = 0)
|
10
|
+
raise "invalid time" if time < @last_time.to_i
|
11
|
+
@last_time = time
|
12
|
+
@prng.rand max_value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Uniflake::SequenceResolvers
|
2
|
+
|
3
|
+
class Redis
|
4
|
+
|
5
|
+
def initialize(client, key_prefix = '')
|
6
|
+
@client = client
|
7
|
+
@prefix = key_prefix
|
8
|
+
end
|
9
|
+
|
10
|
+
def resolve(int_generator_id, time, max_value = 0)
|
11
|
+
last_time = connection.get(@prefix + int_generator_id.to_s + "_last_time").to_i
|
12
|
+
raise "invalid time" if time < last_time
|
13
|
+
|
14
|
+
connection.set @prefix + int_generator_id.to_s + "_last_time", time
|
15
|
+
|
16
|
+
connection.eval lua, [@prefix + int_generator_id.to_s + time.to_s], ['0', '10']
|
17
|
+
end
|
18
|
+
|
19
|
+
def connection
|
20
|
+
if @client.class.method_defined? 'with'
|
21
|
+
@client.with { |connection| return connection }
|
22
|
+
end
|
23
|
+
|
24
|
+
@client
|
25
|
+
end
|
26
|
+
|
27
|
+
def lua
|
28
|
+
<<~LUA
|
29
|
+
if redis.call('set', KEYS[1], ARGV[1], "EX", ARGV[2], "NX") then
|
30
|
+
return 0
|
31
|
+
else
|
32
|
+
return redis.call('incr', KEYS[1])
|
33
|
+
end
|
34
|
+
LUA
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/uniflake.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module Uniflake
|
2
|
+
require_relative 'uniflake/generators/uniflake.rb'
|
3
|
+
require_relative 'uniflake/generators/snowflake.rb'
|
4
|
+
require_relative 'uniflake/generators/discord.rb'
|
5
|
+
|
6
|
+
require_relative 'uniflake/sequence_resolvers/memory.rb'
|
7
|
+
require_relative 'uniflake/sequence_resolvers/random.rb'
|
8
|
+
require_relative 'uniflake/sequence_resolvers/redis.rb'
|
9
|
+
|
10
|
+
require_relative 'uniflake/generator_ids/number.rb'
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: uniflake
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- nebo7
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: ''
|
14
|
+
email: ''
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/uniflake.rb
|
20
|
+
- lib/uniflake/generator_ids/number.rb
|
21
|
+
- lib/uniflake/generators/discord.rb
|
22
|
+
- lib/uniflake/generators/snowflake.rb
|
23
|
+
- lib/uniflake/generators/uniflake.rb
|
24
|
+
- lib/uniflake/sequence_resolvers/memory.rb
|
25
|
+
- lib/uniflake/sequence_resolvers/random.rb
|
26
|
+
- lib/uniflake/sequence_resolvers/redis.rb
|
27
|
+
homepage: https://github.com/nebo7/uniflake
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements: []
|
46
|
+
rubygems_version: 3.2.22
|
47
|
+
signing_key:
|
48
|
+
specification_version: 4
|
49
|
+
summary: ''
|
50
|
+
test_files: []
|