ruby_xid 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/ruby_xid.rb +145 -0
- data/lib/xid/base32.rb +141 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '08ba94c6fc740af7f91b899eb0459764ff1dcd7512eac6a575f33bdc6ee8c255'
|
4
|
+
data.tar.gz: 7b5eac75b7a82f8b2e67b4df57f5d85d3b451ad62ee4235e97df5f1c1a87675c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '072618ecba2040867b4a04c95d844ddf8e0e50bdbc744455aa096de2e16ae931b0dbdeb6f35ebce103d061d3e52dc49fed82a109300ca342cf17182c5aa58c25'
|
7
|
+
data.tar.gz: 3f7061a4a6893c6f77cfb738b39f135ba0b1c66c7ce97014d30e7be9fc1e7e0c95ffe5bc02b10bbc6938ffaa7719b9e623059682bffb91bbf6a7c792e629124e
|
data/lib/ruby_xid.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
# Xid implementatin in Ruby
|
2
|
+
class Xid
|
3
|
+
require 'socket'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
RAW_LEN = 12
|
8
|
+
TRIM_LEN = 20
|
9
|
+
|
10
|
+
def initialize(id = nil)
|
11
|
+
@mutex = Mutex.new
|
12
|
+
init_rand_int
|
13
|
+
@pid = Process.pid
|
14
|
+
unless id.nil?
|
15
|
+
# Decoded array
|
16
|
+
@value = id
|
17
|
+
else
|
18
|
+
@value = generate_xid
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def next_xid
|
23
|
+
@value = generate_xid
|
24
|
+
string
|
25
|
+
end
|
26
|
+
|
27
|
+
def pid
|
28
|
+
# type: () -> int
|
29
|
+
(@value[7] << 8 | @value[8])
|
30
|
+
end
|
31
|
+
|
32
|
+
def counter
|
33
|
+
# type: () -> int
|
34
|
+
@value[9] << 16 | @value[10] << 8 | @value[11]
|
35
|
+
end
|
36
|
+
|
37
|
+
def machine
|
38
|
+
# type: () -> str
|
39
|
+
@value[4..7].map(&:chr)
|
40
|
+
end
|
41
|
+
|
42
|
+
def datetime
|
43
|
+
Time.at(time).to_datetime
|
44
|
+
end
|
45
|
+
|
46
|
+
def time
|
47
|
+
# type: () -> int
|
48
|
+
@value[0] << 24 | @value[1] << 16 | @value[2] << 8 | @value[3]
|
49
|
+
end
|
50
|
+
|
51
|
+
def machine_id
|
52
|
+
@machine_id ||= real_machine_id
|
53
|
+
end
|
54
|
+
|
55
|
+
def string
|
56
|
+
# type: () -> str
|
57
|
+
byte_value = bytes
|
58
|
+
Base32.b32encode(byte_value).downcase[0..TRIM_LEN - 1]
|
59
|
+
end
|
60
|
+
|
61
|
+
def bytes
|
62
|
+
# type: () -> str
|
63
|
+
@value.map(&:chr).join('')
|
64
|
+
end
|
65
|
+
|
66
|
+
def init_rand_int
|
67
|
+
# type: () -> int
|
68
|
+
@rand_int = begin
|
69
|
+
buford = SecureRandom.hex(3).scan(/.{2}/m).map(&:hex)
|
70
|
+
buford[0] << 16 | buford[1] << 8 | buford[2]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def ==(other_xid)
|
75
|
+
# type: (Xid) -> bool
|
76
|
+
string < other_xid.string
|
77
|
+
end
|
78
|
+
|
79
|
+
def <(other_xid)
|
80
|
+
# type: (Xid) -> bool
|
81
|
+
string < other_xid.string
|
82
|
+
end
|
83
|
+
|
84
|
+
def >(other_xid)
|
85
|
+
# type: (Xid) -> bool
|
86
|
+
string > other_xid.string
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.from_string(str)
|
90
|
+
val = Base32.b32decode(str)
|
91
|
+
value_check = val.select { |x| x >= 0 && x < 255 }
|
92
|
+
|
93
|
+
(value_check.length..RAW_LEN - 1).each do |i|
|
94
|
+
value_check[i] = false
|
95
|
+
end
|
96
|
+
|
97
|
+
raise 'Invalid Xid' unless value_check.all?
|
98
|
+
|
99
|
+
Object.const_get(name).new(val)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def real_machine_id
|
105
|
+
# type: () -> List[int]
|
106
|
+
hostname = Socket.gethostname.encode('utf-8')
|
107
|
+
md5 = Digest::MD5.new
|
108
|
+
md5 << hostname
|
109
|
+
val = md5.digest[0..3]
|
110
|
+
val.scan(/.{1}/m).map(&:ord)
|
111
|
+
rescue
|
112
|
+
SecureRandom.hex(3).scan(/.{2}/m).map(&:hex)
|
113
|
+
end
|
114
|
+
|
115
|
+
def generate_xid
|
116
|
+
# type: () -> List[int]
|
117
|
+
now = Time.now.to_i
|
118
|
+
id = [0] * RAW_LEN
|
119
|
+
|
120
|
+
id[0] = (now >> 24) & 0xff
|
121
|
+
id[1] = (now >> 16) & 0xff
|
122
|
+
id[2] = (now >> 8) & 0xff
|
123
|
+
id[3] = now & 0xff
|
124
|
+
|
125
|
+
id[4] = machine_id[0]
|
126
|
+
id[5] = machine_id[1]
|
127
|
+
id[6] = machine_id[2]
|
128
|
+
|
129
|
+
id[7] = (@pid >> 8) & 0xff
|
130
|
+
id[8] = @pid & 0xff
|
131
|
+
|
132
|
+
@mutex.synchronize do
|
133
|
+
@rand_int += 1
|
134
|
+
end
|
135
|
+
i = @rand_int
|
136
|
+
|
137
|
+
id[9] = (i >> 16) & 0xff
|
138
|
+
id[10] = (i >> 8) & 0xff
|
139
|
+
id[11] = i & 0xff
|
140
|
+
|
141
|
+
id
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
require_relative 'xid/base32'
|
data/lib/xid/base32.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
|
2
|
+
class Xid::Base32
|
3
|
+
|
4
|
+
ENCODE_HEX = '0123456789abcdefghijklmnopqrstuv'.freeze
|
5
|
+
PAD_CHAR = '='.freeze
|
6
|
+
|
7
|
+
# Start class methods
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def decode_hex_map
|
11
|
+
Hash[ENCODE_HEX.chars.each_with_index.map { |x, i| [x, i] }]
|
12
|
+
end
|
13
|
+
|
14
|
+
def b32encode(src)
|
15
|
+
src = src.scan(/.{1}/m).map(&:ord)
|
16
|
+
encode(src, ENCODE_HEX)
|
17
|
+
end
|
18
|
+
|
19
|
+
def b32decode(src)
|
20
|
+
decode(src, ENCODE_HEX)
|
21
|
+
end
|
22
|
+
|
23
|
+
def encode(src_str, str_map)
|
24
|
+
return '' if src_str.empty?
|
25
|
+
|
26
|
+
dst = []
|
27
|
+
src_len = 0
|
28
|
+
while src_str && !src_str.empty?
|
29
|
+
src_len = src_str.length
|
30
|
+
next_byte = [0] * 8
|
31
|
+
|
32
|
+
if src_len > 4
|
33
|
+
next_byte[7] = src_str[4] & 0x1f
|
34
|
+
next_byte[6] = src_str[4] >> 5
|
35
|
+
end
|
36
|
+
if src_len > 3
|
37
|
+
next_byte[6] = next_byte[6] | (src_str[3] << 3) & 0x1f
|
38
|
+
next_byte[5] = (src_str[3] >> 2) & 0x1f
|
39
|
+
next_byte[4] = src_str[3] >> 7
|
40
|
+
end
|
41
|
+
if src_len > 2
|
42
|
+
next_byte[4] = next_byte[4] | (src_str[2] << 1) & 0x1f
|
43
|
+
next_byte[3] = (src_str[2] >> 4) & 0x1f
|
44
|
+
end
|
45
|
+
if src_len > 1
|
46
|
+
next_byte[3] = next_byte[3] | (src_str[1] << 4) & 0x1f
|
47
|
+
next_byte[2] = (src_str[1] >> 1) & 0x1f
|
48
|
+
next_byte[1] = (src_str[1] >> 6) & 0x1f
|
49
|
+
end
|
50
|
+
if src_len > 0
|
51
|
+
next_byte[1] = next_byte[1] | (src_str[0] << 2) & 0x1f
|
52
|
+
next_byte[0] = src_str[0] >> 3
|
53
|
+
end
|
54
|
+
|
55
|
+
next_byte.each do |nb|
|
56
|
+
dst << str_map[nb]
|
57
|
+
end
|
58
|
+
src_str = src_str[5..src_str.length]
|
59
|
+
end
|
60
|
+
|
61
|
+
dst[-1] = '=' if src_len < 5
|
62
|
+
if src_len < 4
|
63
|
+
dst[-2] = '='
|
64
|
+
dst[-3] = '='
|
65
|
+
end
|
66
|
+
if src_len < 3
|
67
|
+
dst[-4] = '='
|
68
|
+
end
|
69
|
+
if src_len < 2
|
70
|
+
dst[-5] = '='
|
71
|
+
dst[-6] = '='
|
72
|
+
end
|
73
|
+
|
74
|
+
dst.join('')
|
75
|
+
end
|
76
|
+
|
77
|
+
def decode(src, str_map)
|
78
|
+
src.downcase!
|
79
|
+
|
80
|
+
end_loop = false
|
81
|
+
result = []
|
82
|
+
while src && !src.empty? && !end_loop
|
83
|
+
dst = [0] * 5
|
84
|
+
dbuf = [0] * 8
|
85
|
+
src_len = 8
|
86
|
+
|
87
|
+
(0..8).each do |i|
|
88
|
+
if i >= src.length
|
89
|
+
src_len = i
|
90
|
+
end_loop = true
|
91
|
+
break
|
92
|
+
end
|
93
|
+
char = src[i]
|
94
|
+
if char == PAD_CHAR
|
95
|
+
end_loop = true
|
96
|
+
src_len = i
|
97
|
+
break
|
98
|
+
else
|
99
|
+
dbuf[i] = decode_hex_map[char]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
if src_len >= 8
|
104
|
+
dst[4] = (dbuf[6] << 5) | (dbuf[7])
|
105
|
+
end
|
106
|
+
if src_len >= 7
|
107
|
+
dst[3] = (dbuf[4] << 7) | (dbuf[5] << 2) | (dbuf[6] >> 3)
|
108
|
+
end
|
109
|
+
if src_len >= 5
|
110
|
+
dst[2] = (dbuf[3] << 4) | (dbuf[4] >> 1)
|
111
|
+
end
|
112
|
+
if src_len >= 4
|
113
|
+
dst[1] = (dbuf[1] << 6) | (dbuf[2] << 1) | (dbuf[3] >> 4)
|
114
|
+
end
|
115
|
+
if src_len >= 2
|
116
|
+
dst[0] = (dbuf[0] << 3) | (dbuf[1] >> 2)
|
117
|
+
end
|
118
|
+
|
119
|
+
dst = dst.map { |x| x & 0xff }
|
120
|
+
|
121
|
+
if src_len == 2
|
122
|
+
dst = dst[0]
|
123
|
+
elsif src_len == 4
|
124
|
+
dst = dst[0..1]
|
125
|
+
elsif src_len == 5
|
126
|
+
dst = dst[0..2]
|
127
|
+
elsif src_len == 7
|
128
|
+
dst = dst[0..3]
|
129
|
+
elsif src_len == 8
|
130
|
+
dst = dst[0..4]
|
131
|
+
end
|
132
|
+
|
133
|
+
result += dst
|
134
|
+
src = src[8..src.length]
|
135
|
+
end
|
136
|
+
|
137
|
+
result
|
138
|
+
end
|
139
|
+
end
|
140
|
+
# END - Class methods
|
141
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_xid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Valarpiraichandran
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-12-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: a.valarpirai@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/ruby_xid.rb
|
20
|
+
- lib/xid/base32.rb
|
21
|
+
homepage: http://github.com/valarpirai/ruby_xid
|
22
|
+
licenses:
|
23
|
+
- MIT
|
24
|
+
metadata: {}
|
25
|
+
post_install_message:
|
26
|
+
rdoc_options: []
|
27
|
+
require_paths:
|
28
|
+
- lib
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
requirements: []
|
40
|
+
rubygems_version: 3.0.6
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Ruby xid implementation
|
44
|
+
test_files: []
|