Class: UPnP::UUID
- Inherits:
-
Object
- Object
- UPnP::UUID
- Defined in:
- lib/UPnP/UUID.rb
Overview
Constant Summary collapse
- NIC_FILE =
File holding the NIC MAC address
'~/.UPnP/uuid_mac_address'
- CLOCK_MULTIPLIER =
Clock multiplier. Converts Time (resolution: seconds) to UUID clock (resolution: 10ns)
10000000
- CLOCK_GAPS =
Clock gap is the number of ticks (resolution: 10ns) between two Ruby Time ticks.
100000
- VERSION_CLOCK =
Version number stamped into the UUID to identify it as time-based.
0x0100
- FORMATS =
Formats supported by the UUID generator.
:default
-
Produces 36 characters, including hyphens separating the UUID value parts
:compact
-
Produces a 32 digits (hexadecimal) value with no hyphens
:urn
-
Adds the prefix
urn:uuid:
to the:default
format
{ :compact => '%08x%04x%04x%04x%012x', :default => '%08x-%04x-%04x-%04x-%012x', :urn => 'urn:uuid:%08x-%04x-%04x-%04x-%012x', }
Class Method Summary collapse
-
.generate(nic_file = NIC_FILE) ⇒ Object
Sets up the UUID class generates a UUID in the default format.
-
.setup(nic_file = NIC_FILE) ⇒ Object
Discovers the NIC MAC address and saves it to
nic_file
.
Instance Method Summary collapse
-
#generate(format = :default) ⇒ Object
Generates a new UUID string using
format
. -
#initialize(nic_file = NIC_FILE) ⇒ UUID
constructor
Creates a new UUID generator using the NIC stored in NIC_FILE.
Constructor Details
#initialize(nic_file = NIC_FILE) ⇒ UUID
Creates a new UUID generator using the NIC stored in NIC_FILE.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/UPnP/UUID.rb', line 119 def initialize(nic_file = NIC_FILE) if File.exist? nic_file then address = File.read nic_file raise Error, "invalid MAC address #{address}" unless address =~ /([\da-f]{2}[:\-]){5}[\da-f]{2}/i @address = address.scan(/[0-9a-fA-F]{2}/).join.hex & 0x7FFFFFFFFFFF else @address = rand(0x800000000000) | 0xF00000000000 end @drift = 0 @last_clock = (Time.new.to_f * CLOCK_MULTIPLIER).to_i @mutex = Mutex.new @sequence = rand 0x10000 end |
Class Method Details
.generate(nic_file = NIC_FILE) ⇒ Object
Sets up the UUID class generates a UUID in the default format.
82 83 84 85 86 87 |
# File 'lib/UPnP/UUID.rb', line 82 def self.generate(nic_file = NIC_FILE) return @uuid.generate if @uuid setup nic_file @uuid = new @uuid.generate end |
.setup(nic_file = NIC_FILE) ⇒ Object
Discovers the NIC MAC address and saves it to nic_file
. Works for UNIX (ifconfig) and Windows (ipconfig).
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/UPnP/UUID.rb', line 93 def self.setup(nic_file = NIC_FILE) nic_file = File. nic_file return if File.exist? nic_file FileUtils.mkdir_p File.dirname(nic_file) # Run ifconfig for UNIX, or ipconfig for Windows. config = '' Dir.chdir Dir.tmpdir do config << `ifconfig 2>/dev/null` config << `ipconfig /all 2>NUL` end addresses = config.scan(/[^:\-](?:[\da-z][\da-z][:\-]){5}[\da-z][\da-z][^:\-]/i) addresses = addresses.map { |addr| addr[1..-2] } raise Error, 'MAC address not found via ifconfig or ipconfig' if addresses.empty? open nic_file, 'w' do |io| io.write addresses.first end end |
Instance Method Details
#generate(format = :default) ⇒ Object
Generates a new UUID string using format
. See FORMATS for a list of supported formats.
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/UPnP/UUID.rb', line 140 def generate(format = :default) template = FORMATS[format] raise ArgumentError, "unknown UUID format #{format.inspect}" if template.nil? # The clock must be monotonically increasing. The clock resolution is at # best 100 ns (UUID spec), but practically may be lower (on my setup, # around 1ms). If this method is called too fast, we don't have a # monotonically increasing clock, so the solution is to just wait. # # It is possible for the clock to be adjusted backwards, in which case we # would end up blocking for a long time. When backward clock is detected, # we prevent duplicates by asking for a new sequence number and continue # with the new clock. clock = @mutex.synchronize do clock = (Time.new.to_f * CLOCK_MULTIPLIER).to_i & 0xFFFFFFFFFFFFFFF0 if clock > @last_clock then @drift = 0 @last_clock = clock elsif clock == @last_clock then drift = @drift += 1 if drift < 10000 @last_clock += 1 else Thread.pass nil end else @sequence = rand 0x10000 @last_clock = clock end end while not clock template % [ clock & 0xFFFFFFFF, (clock >> 32) & 0xFFFF, ((clock >> 48) & 0xFFFF | VERSION_CLOCK), @sequence & 0xFFFF, @address & 0xFFFFFFFFFFFF ] end |