Skip to content

Instantly share code, notes, and snippets.

@felixbuenemann
Last active August 29, 2015 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felixbuenemann/10618216 to your computer and use it in GitHub Desktop.
Save felixbuenemann/10618216 to your computer and use it in GitHub Desktop.
# encoding: utf-8
# Simple UUID Generator for UUID v0 (zero padded), v1, v2, v3, v4, v5
# Author: Felix Buenemann https://github.com/felixbuenemann/
# License: Public Domain
# Note: v1 code partially based on these ruby uuid implementations:
# https://github.com/assaf/uuid/
# https://github.com/cassandra-rb/simple_uuid
require 'digest/md5'
require 'digest/sha1'
require 'securerandom'
module UUIDGenerator
GREGORIAN_EPOCH_OFFSET = 0x01B2_1DD2_1381_4000.freeze # Oct 15, 1582
UUID_NIL = '00000000-0000-0000-0000-000000000000'.freeze
UUID_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'.freeze
UUID_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'.freeze
UUID_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8'.freeze
UUID_X500= '6ba7b814-9dad-11d1-80b4-00c04fd430c8'.freeze
@@mutex = Mutex.new
class << self
# if value is given, generates zero padded pseudo-uuid
def generate_v0(value = nil)
format_uuid 0, value.to_s
end
# naive implementation of uuid v1
# doesn't synchronize sequence between processes
# and doesn't correct for clock skew
def generate_v1(mac = nil, time = Time.new, sequence = next_sequence)
clock = (time.to_i * 1_000_000 + time.usec) * 10 + GREGORIAN_EPOCH_OFFSET
mac = (mac ? mac.gsub(/:|-/, '').hex : 0) & 0x7FFF_FFFF_FFFF
format_uuid 1, '%08x%04x%04x%04x%012x' % [
clock & 0xFFFF_FFFF,
(clock >> 32) & 0xFFFF,
(clock >> 48) & 0xFFFF,
sequence & 0xFFFF,
mac & 0xFFFF_FFFF_FFFF
]
end
def generate_v3(value, namespace = UUID_NIL)
namespace_bytes = uuid_str_to_bytes(namespace)
format_uuid 3, Digest::MD5.hexdigest("#{namespace_bytes}#{value}")
end
def generate_v4
SecureRandom.uuid
end
def generate_v5(value, namespace = UUID_NIL)
namespace_bytes = uuid_str_to_bytes(namespace)
format_uuid 5, Digest::SHA1.hexdigest("#{namespace_bytes}#{value}")
end
private
def next_sequence
@@mutex.synchronize { @sequence = @sequence.to_i.next }
end
def format_uuid(version, value)
s = value.rjust(32, '0')
if version > 0
s[12] = version.to_s
s[16] = byte_to_variant(s[16])
end
"#{s[0..7]}-#{s[8..11]}-#{s[12..15]}-#{s[16..19]}-#{s[20..31]}"
end
def byte_to_variant(byte)
[0x8,0x9,0xa,0xb][byte.hex/4].to_s(16)
end
def uuid_str_to_bytes(string)
[string.gsub(/-/,'')].pack('H*')
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment