twitter_snowflake 0.0.2
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/.gitignore +16 -0
- data/Gemfile +5 -0
- data/README.md +105 -0
- data/lib/twitter_snowflake.rb +92 -0
- data/lib/twitter_snowflake/snowflake.rb +72 -0
- data/lib/twitter_snowflake/version.rb +5 -0
- data/twitter_snowflake.gemspec +22 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b6823234421cda30700685779281840c03182376a020a90d15cac4f3a110bf10
|
4
|
+
data.tar.gz: e68055bf4fa8c33b23e2816bf15b80c8dc5ffa9e39642ffcd2b8baea0674762c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c43dc596687839df000374a8137fcd5cf4c9f0e9ef9480589aaed853fb83ffb82697113ca312ca3aa2b4511d4c8735b3a94a932ed66d54c0c8f263677f12e01c
|
7
|
+
data.tar.gz: 300004e8f1a00eeb413961c596fe23c1b40d6058f3283d3bfeb0f967b77cf1eff85ddb8b4479147ce6126cb1f0d8152bd651d06762ec3defa469904eeb23921c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# TwitterSnowflake.rb
|
2
|
+
|
3
|
+
A Ruby library to handle Twitter snowflake IDs.
|
4
|
+
|
5
|
+
## âŦī¸ Installation
|
6
|
+
|
7
|
+
There are two ways to install this library:
|
8
|
+
|
9
|
+
**1. Bundler**
|
10
|
+
|
11
|
+
Run `bundle init` to generate a Gemfile, append the following line to it and run `bundle install`.
|
12
|
+
|
13
|
+
```
|
14
|
+
gem 'twitter_snowflake', '~> 0.0.1'
|
15
|
+
```
|
16
|
+
|
17
|
+
**2. Gem**
|
18
|
+
|
19
|
+
Or you can use Ruby's package manager: gem. Open your terminal and run the following command:
|
20
|
+
|
21
|
+
```
|
22
|
+
gem install twitter_snowflake
|
23
|
+
```
|
24
|
+
|
25
|
+
## đĻ Dependencies
|
26
|
+
|
27
|
+
### Runtime
|
28
|
+
|
29
|
+
TwitterSnowflake.rb does not rely on any third-party library.
|
30
|
+
|
31
|
+
### Development
|
32
|
+
|
33
|
+
- [YARD](https://rubygems.org/gems/yard/versions/0.9.20) â to generate documentation.
|
34
|
+
- [Rubocop](https://rubygems.org/gems/rubocop/versions/0.76.0) â to spot bad code smells.
|
35
|
+
|
36
|
+
## đ Documentation
|
37
|
+
|
38
|
+
You can find the documentation in [Rubydoc](https://www.rubydoc.info/github/asyncnoodle/TwitterSnowflake.rb).
|
39
|
+
|
40
|
+
## đšī¸ Usage
|
41
|
+
|
42
|
+
To parse a snowflake ID, use `TwitterSnowflake.parse`:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
require 'twitter_snowflake'
|
46
|
+
|
47
|
+
snowflake = TwitterSnowflake.parse 948_350_713_171_619_840
|
48
|
+
# => #<TwitterSnowflake::Snowflake:0x00005584b970d878
|
49
|
+
# @epoch=1288834974657,
|
50
|
+
# @id=948350713171619840,
|
51
|
+
# @increment=0,
|
52
|
+
# @process_id=19,
|
53
|
+
# @time=2018-01-02 22:30:04 -0200,
|
54
|
+
# @timestamp=1514939404181,
|
55
|
+
# @worker_id=0>
|
56
|
+
```
|
57
|
+
|
58
|
+
If you don't need a whole `Snowflake` instance, you can use `TwitterSnowflake`'s utility class methods:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
TwitterSnowflake.timestamp 948_350_713_171_619_840 # => 1514939404181
|
62
|
+
```
|
63
|
+
|
64
|
+
Calculations are made with Twitter's epoch by default (`1_288_834_974_657`). You can change the epoch value by passing a keyword argument to `TwitterSnowflake.parse` or `TwitterSnowflake.timestamp`:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
discord_epoch = 1_420_070_400_000
|
68
|
+
id = 649_027_890_029_133_824
|
69
|
+
|
70
|
+
TwitterSnowflake.timestamp id, epoch: discord_epoch # => 1574810707338
|
71
|
+
|
72
|
+
TwitterSnowflake.parse id, epoch: discord_epoch
|
73
|
+
# => <TwitterSnowflake::Snowflake:0x000056544c9e9818
|
74
|
+
# @epoch=1420070400000,
|
75
|
+
# @id=649027890029133824,
|
76
|
+
# @increment=0,
|
77
|
+
# @process_id=0,
|
78
|
+
# @time=2019-11-26 20:25:07 -0300,
|
79
|
+
# @timestamp=1574810707338,
|
80
|
+
# @worker_id=1>
|
81
|
+
```
|
82
|
+
|
83
|
+
It is also possible to generate a snowflake yourself with `TwitterSnowflake.synthesize`:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
snowflake = TwitterSnowflake.synthesize(
|
87
|
+
epoch: 1_420_070_400_000, # defaults to Twitter's epoch if no value is provided
|
88
|
+
timestamp: 1_574_810_707_338,
|
89
|
+
worker_id: 1,
|
90
|
+
process_id: 0,
|
91
|
+
increment: 0,
|
92
|
+
)
|
93
|
+
|
94
|
+
p snowflake.id # => 649027890029133824
|
95
|
+
```
|
96
|
+
|
97
|
+
## đ License
|
98
|
+
|
99
|
+
TwitterSnowflake.rb is licensed under [MIT](LICENSE).
|
100
|
+
|
101
|
+
## âī¸ Contributors
|
102
|
+
|
103
|
+
- [asyncnoodle](https://github.com/asyncnoodle) â author & maintainer.
|
104
|
+
|
105
|
+
I'm looking to improve TwitterSnowflake.rb, so feel free to contribute!
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'twitter_snowflake/version'
|
4
|
+
require 'twitter_snowflake/snowflake'
|
5
|
+
|
6
|
+
# TwitterSnowflake is a library to parse snowflake IDs.
|
7
|
+
module TwitterSnowflake
|
8
|
+
# Twitter's epoch in milliseconds. Used as default epoch to parse IDs.
|
9
|
+
TWITTER_EPOCH = 1_288_834_974_657
|
10
|
+
|
11
|
+
# Timestamp offset (low-order bit of the timestamp collection)
|
12
|
+
TIMESTAMP_BINARY_OFFSET = 22
|
13
|
+
|
14
|
+
# Worker ID offset (low-order bit of the worker ID collection)
|
15
|
+
WORKER_ID_BINARY_OFFSET = 17
|
16
|
+
|
17
|
+
# Mask to extract worker ID.
|
18
|
+
WORKER_ID_MASK = 0x3E000
|
19
|
+
|
20
|
+
# Process ID offset (low-order bit of the process ID collection)
|
21
|
+
PROCESS_ID_BINARY_OFFSET = 12
|
22
|
+
|
23
|
+
# Mask to extract process ID.
|
24
|
+
PROCESS_ID_MASK = 0x1F000
|
25
|
+
|
26
|
+
# Mask to extract increment.
|
27
|
+
INCREMENT_MASK = 0xFFF
|
28
|
+
|
29
|
+
class << self
|
30
|
+
# Creates a snowflake object for any given timestamp, worker ID, process ID and increment.
|
31
|
+
#
|
32
|
+
# @param epoch [Integer] base epoch in milliseconds to perform calculations.
|
33
|
+
# @param timestamp [Integer] the timestamp in milliseconds.
|
34
|
+
#
|
35
|
+
# @return [Snowflake] the generated snowflake.
|
36
|
+
def synthesize(timestamp:, worker_id: 0, process_id: 0, increment: 0, epoch: TWITTER_EPOCH)
|
37
|
+
id = (timestamp - epoch) << TIMESTAMP_BINARY_OFFSET
|
38
|
+
id += (worker_id << WORKER_ID_BINARY_OFFSET)
|
39
|
+
id += (process_id << PROCESS_ID_BINARY_OFFSET)
|
40
|
+
id += increment
|
41
|
+
|
42
|
+
Snowflake.new(id: id, epoch: epoch)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Parses a snowflake ID.
|
46
|
+
#
|
47
|
+
# @param id [Integer] the snowflake ID.
|
48
|
+
# @param epoch [Integer] base epoch in milliseconds to perform calculations.
|
49
|
+
#
|
50
|
+
# @return [Snowflake] a snowflake object.
|
51
|
+
def parse(id, epoch: TWITTER_EPOCH)
|
52
|
+
Snowflake.new(id: id, epoch: epoch)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Extracts the timestamp from a snowflake ID.
|
56
|
+
#
|
57
|
+
# @param id [Integer] the snowflake ID.
|
58
|
+
# @param epoch [Integer] base epoch in milliseconds to perform calculations.
|
59
|
+
#
|
60
|
+
# @return [Integer] the timestamp in milliseconds.
|
61
|
+
def timestamp(id, epoch: TWITTER_EPOCH)
|
62
|
+
(id >> TIMESTAMP_BINARY_OFFSET) + epoch
|
63
|
+
end
|
64
|
+
|
65
|
+
# Extracts the worker ID from a snowflake ID.
|
66
|
+
#
|
67
|
+
# @param id [Integer] the snowflake ID.
|
68
|
+
#
|
69
|
+
# @return [Integer] the worker ID.
|
70
|
+
def worker_id(id)
|
71
|
+
(id & WORKER_ID_MASK) >> WORKER_ID_BINARY_OFFSET
|
72
|
+
end
|
73
|
+
|
74
|
+
# Extracts the process ID from a snowflake ID.
|
75
|
+
#
|
76
|
+
# @param id [Integer] the snowflake ID.
|
77
|
+
#
|
78
|
+
# @return [Integer] the process ID.
|
79
|
+
def process_id(id)
|
80
|
+
(id & PROCESS_ID_MASK) >> PROCESS_ID_BINARY_OFFSET
|
81
|
+
end
|
82
|
+
|
83
|
+
# Extracts the increment from a snowflake ID.
|
84
|
+
#
|
85
|
+
# @param id [Integer] the snowflake ID.
|
86
|
+
#
|
87
|
+
# @return [Integer] the increment.
|
88
|
+
def increment(id)
|
89
|
+
id & INCREMENT_MASK
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TwitterSnowflake
|
4
|
+
# A snowflake ID as a Ruby object.
|
5
|
+
class Snowflake
|
6
|
+
# @return [Integer] the snowflake ID in its original form.
|
7
|
+
attr_reader :id
|
8
|
+
|
9
|
+
# @return [Integer] the base epoch in milliseconds to perform calculations.
|
10
|
+
attr_reader :epoch
|
11
|
+
|
12
|
+
# @return [Integer] the timestamp extracted from the ID in milliseconds.
|
13
|
+
attr_reader :timestamp
|
14
|
+
|
15
|
+
# @return [Integer] the worker ID extracted form the ID.
|
16
|
+
attr_reader :worker_id
|
17
|
+
|
18
|
+
# @return [Integer] the proccess ID extracted from the ID.
|
19
|
+
attr_reader :process_id
|
20
|
+
|
21
|
+
# @return [Integer] the increment extracted from the ID.
|
22
|
+
attr_reader :increment
|
23
|
+
|
24
|
+
# @return [Time] the timestamp as a Time object
|
25
|
+
attr_reader :time
|
26
|
+
|
27
|
+
# @param id [Integer] the ID itself.
|
28
|
+
# @param epoch [Intger] base epoch in milliseconds to perform calculations.
|
29
|
+
def initialize(id:, epoch:)
|
30
|
+
# Data used during extraction process
|
31
|
+
@id = id
|
32
|
+
@epoch = epoch
|
33
|
+
|
34
|
+
# Extracting data
|
35
|
+
@timestamp = TwitterSnowflake.timestamp(@id, epoch: @epoch)
|
36
|
+
@worker_id = TwitterSnowflake.worker_id(@id)
|
37
|
+
@process_id = TwitterSnowflake.process_id(@id)
|
38
|
+
@increment = TwitterSnowflake.increment(@id)
|
39
|
+
|
40
|
+
# Useful information
|
41
|
+
@time = Time.at(@timestamp / 1000.0)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Checks if two snowflakes are equal. Two snowflakes are considered equal
|
45
|
+
# if both have the same ID and are based on the same epoch.
|
46
|
+
#
|
47
|
+
# @param other [Snowflake] the other snowflake.
|
48
|
+
#
|
49
|
+
# @return [Boolean] whether the snowflakes are equal or not.
|
50
|
+
def ==(other)
|
51
|
+
(@id == other.id) && (@epoch == other.epoch)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Checks if this snowflake has been generated before another snowflake.
|
55
|
+
#
|
56
|
+
# @param other [Snowflake] the other snowflake.
|
57
|
+
#
|
58
|
+
# @return [Boolean] whether this snowflake has been generated before another snowflake or not.
|
59
|
+
def before?(other)
|
60
|
+
@timestamp < other.timestamp
|
61
|
+
end
|
62
|
+
|
63
|
+
# Checks if this snowflake has been generated after another snowflake.
|
64
|
+
#
|
65
|
+
# @param other [Snowflake] the other snowflake.
|
66
|
+
#
|
67
|
+
# @return [Boolean] whether this snowflake has been generated after another snowflake or not.
|
68
|
+
def after?(other)
|
69
|
+
@timestamp > other.timestamp
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'twitter_snowflake/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'twitter_snowflake'
|
9
|
+
spec.version = TwitterSnowflake::VERSION
|
10
|
+
spec.authors = %w[asyncnoodle]
|
11
|
+
|
12
|
+
spec.summary = 'Ruby library to handle Twitter snowflake IDs.'
|
13
|
+
spec.homepage = 'https://github.com/asyncnoodle/TwitterSnowflake.rb'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|examples|lib/discordrb/webhooks)/}) }
|
17
|
+
spec.require_paths = %w[lib]
|
18
|
+
|
19
|
+
spec.add_development_dependency 'rspec', '~> 3.8.0'
|
20
|
+
spec.add_development_dependency 'rubocop', '~> 0.74.0'
|
21
|
+
spec.add_development_dependency 'yard', '~> 0.9.9'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twitter_snowflake
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- asyncnoodle
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-11-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.8.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.8.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.74.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.74.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.9.9
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.9
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- ".gitignore"
|
62
|
+
- Gemfile
|
63
|
+
- README.md
|
64
|
+
- lib/twitter_snowflake.rb
|
65
|
+
- lib/twitter_snowflake/snowflake.rb
|
66
|
+
- lib/twitter_snowflake/version.rb
|
67
|
+
- twitter_snowflake.gemspec
|
68
|
+
homepage: https://github.com/asyncnoodle/TwitterSnowflake.rb
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubygems_version: 3.0.3
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: Ruby library to handle Twitter snowflake IDs.
|
91
|
+
test_files: []
|