Firebase push algorithm in Ruby (ref: https://www.firebase.com/blog/2015-02-11-firebase-unique-identifiers.html)
require 'date'
class FirebasePush
PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'
def initialize
@prev_ts = 0
@rand_chars = Array.new(12)
end
def assert(cond, msg = '')
raise "Firebase INTERNAL ASSERT FAILED:#{msg}" unless cond
end
def next_id(ts = seed)
is_dup = (ts == @prev_ts)
@prev_ts = ts
ts_chars = Array.new(8)
7.step(0, -1) { |i|
ts_chars[i] = PUSH_CHARS[ts % 64]
ts = (ts / 64).floor
}
assert(ts == 0)
id = ts_chars.join ''
unless is_dup
12.times { |i| @rand_chars[i] = (rand * 64).floor }
else
11.step(0, -1) { |i|
unless @rand_chars[i] == 63
@rand_chars[i] += 1
break
end
@rand_chars[i] = 0
}
end
12.times { |i| id << PUSH_CHARS[@rand_chars[i]] }
assert(id.length == 20, 'next_id: Length should be 20.')
id
end
def seed
DateTime.now.strftime('%Q').to_i
end
end
if __FILE__ == $0
fb = FirebasePush.new
ts = fb.seed
(ARGV[0] || 1).to_i.times { |_|
puts fb.next_id(ts)
}
end