UUID - ifconfig
Posted on March 27, 2008
De vez em quando nos deparamos com o cenário onde precisamos gerar um ID único não-sequencial (auto increment do banco de dados não serve). Pode ser para várias coisas, por exemplo, um link que você quer enviar por e-mail ao seu usuário que, quando ele clickar, vai levar diretamente a uma página customizada para mudar de senha sem que ele precise logar antes. Ou algo assim.
Uma das diversas maneiras é usar um gerador de UUIDs ou “Universally Unique Identifier”, um número de 128-bits representado como uma string de 36 caracteres. Existem algumas bibliotecas para isso em Ruby, uma delas é o uuidtools, que você instala simplesmente assim:
sudo gem install uuidtools
Ele funciona muito bem, mas há alguns ‘poréns’, principalmente se estiver usando Windows. Veja aqui por que.
Antes de mais nada, vamos entender como ele funciona. Na sua aplicação Rails, não se esqueça de dar require ‘uuidtools’ em algum lugar do config/environment.rb ou num arquivo de requirements dentro de config/initializers, no caso do Rails 2.0.
Para usar na sua aplicação, basta chamar o seguinte:
1 2 |
>> UUID.timestamp_create.to_s => "76b69f2e-fbc1-11dc-882f-001ec20704ce" |
Cada vez que chamar o mesmo comando, ele irá gerar um novo número, quase totalmente garantido de nunca se repetir. Eu digo ‘quase’ porque na realidade existe sim chance de colisão, mas é muito pequeno. E se for armazenar isso num campo de um model ActiveRecord, não esqueça de usar ‘validates_uniqueness_of’
Enfim, dentre as várias maneiras de se gerar UUIDs, um dos componentes normalmente usados para formar esse número é o MAC address da sua placa de rede. Por si só ela também é um número mais ou menos único. Portanto, o gerador precisa saber consultar esse número.
Inúmeras bibliotecas fazem o mais simples: uma chamada de sistema ao comando ‘ifconfig’ do Unix ou ‘ipconfig’ no Windows. Daí analisa-se o retorno e consegue-se extrair o MAC address do texto.
Agora começa o problema: ifconfig não é um padrão. Diferentes Unix/Linux podem chamá-lo com parâmetros diferentes. Pode existir configurações de sistema operacional que não devolvem o MAC address ou devolvem em saídas ligeiramente diferentes e, nesse caso, a regular expression que as bibliotecas usam podem falhar.
No caso do Windows, como ele faz uma chamada a um programa externo, ipconfig, ele fica abrindo e fechando uma janela de command prompt. Isso pode ser bastante irritante.
Por isso, eu pensei em outra solução: pular completamente a chamada ao comando externo. Para tanto, criei um arquivo lib/uuid_extension.rb com o seguinte conteúdo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class UUID class << self # rename the old method alias :old_mac_address :mac_address end def self.get_mac_address UUID.mac_address end # replace the old method for a static version def self.mac_address begin SERVER_CONFIG['mac_address'] rescue old_mac_address end end end |
O método UUID.mac_address é o que originalmente faz todas as chamadas externas. Via monkey-patching estou saltando completamente essa implementação e, em vez disso, lendo um valor estático no hash SERVER_CONFIG. E de onde vem esse hash? Isso é um arquivo de configuração chamado config/server.yml com o seguinte conteúdo:
1 2 3 4 5 6 7 8 9 10 11 |
development: server: http://localhost:3000 mac_address: 00:1e:c2:07:04:xx test: server: http://localhost:3000 mac_address: 00:1e:c2:07:04:xx production: server: http://www.servidor.com mac_address: 00:1e:c2:07:04:xx |
Para ler esse arquivo toda vez que o Rails inicia, criei um arquivo chamado config/initializers/server.rb com o seguinte:
1 2 3 |
# Load custom server configuration raw_config = File.read(RAILS_ROOT + "/config/server.yml") SERVER_CONFIG = YAML.load(raw_config)[RAILS_ENV] |
Pronto, isso fecha as pontas. Agora, em vez do uuidtools chamar o ifconfig o tempo todo, ele vai ler de um Hash em memória com a configuração acima. Isso garante que ele sempre vai achar o Mac address que precisa independente de alguma peculiaridade no seu sistema operacional.
O único cuidado é ter certeza de estar usando o Mac address correto da sua máquina. Isso é particularmente importante se você utilizar Capistrano para fazer deployment em mais de uma máquina. Nesse caso o ideal é que cada máquina tenha um server.yml local com o Mac address correto dela e a receita do Capistrano copie esse arquivo para dentro do projeto Rails que acabou de fazer deployment. O Mac address não deve ser repetido entre diferentes máquinas pois isso aumentaria o risco de colisões.
Portanto, se alguém estiver tendo problemas com o UUIDtools, esse pequeno hack deve ajudar.
blog comments powered by Disqus
Archives
- February 12(2)
- December 11(1)
- November 11(4)
- October 11(6)
- September 11(5)
- August 11(1)
- July 11(5)
- May 11(4)
- April 11(11)
- March 11(4)
- February 11(3)
- January 11(4)
- December 10(9)
- November 10(2)
- October 10(10)
- September 10(4)
- August 10(6)
- July 10(14)
- June 10(16)
- May 10(8)
- April 10(14)
- March 10(9)
- February 10(6)
- January 10(14)
- December 09(10)
- November 09(10)
- October 09(7)
- September 09(19)
- August 09(4)
- July 09(12)
- June 09(7)
- May 09(12)
- April 09(11)
- March 09(9)
- February 09(9)
- January 09(12)
- December 08(14)
- November 08(20)
- October 08(15)
- September 08(18)
- August 08(25)
- July 08(13)
- June 08(21)
- May 08(29)
- April 08(27)
- March 08(12)
- February 08(32)
- January 08(31)
- December 07(27)
- November 07(30)
- October 07(25)
- September 07(28)
- August 07(16)
- July 07(15)
- June 07(16)
- May 07(7)
- April 07(13)
- March 07(8)
- February 07(9)
- January 07(24)
- December 06(17)
- November 06(17)
- October 06(15)
- September 06(38)




