Skip to content

Commit

Permalink
Move unique_id functionality to base62 module
Browse files Browse the repository at this point in the history
  • Loading branch information
mustafaturan committed Jun 25, 2018
1 parent 8d87cd2 commit 956ffd9
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ config :event_bus,
topics: [], # list of atoms
ttl: 30_000_000, # integer
time_unit: :micro_seconds, # atom
id_generator: EventBus.Util.String # module: must implement 'unique_id/0' function
id_generator: EventBus.Util.Base62 # module: must implement 'unique_id/0' function
```

After having such config like above, you can generate events without providing optional attributes like below:
Expand Down
53 changes: 53 additions & 0 deletions lib/event_bus/utils/base62.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
defmodule EventBus.Util.Base62 do
@moduledoc false

@mapping '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'

@doc """
Generates partially sequential, base62 unique identifier
"""
@spec unique_id() :: String.t()
def unique_id do
now() <> node_id() <> random(4, 14_776_336)
end

@doc """
Converts given integer to base62
"""
@spec encode(integer()) :: String.t()
def encode(num) when num < 62 do
<< Enum.at(@mapping, num) >>
end

def encode(num) do
encode(div(num, 62)) <> encode(rem(num, 62))
end

# Generates random base62 string with crypto:strong_rand_bytes
defp random(size, max) do
size
|> :crypto.strong_rand_bytes()
|> :crypto.bytes_to_integer()
|> rem(max)
|> encode()
|> String.pad_leading(size, "0")
end

# Current time (microseconds) encoded in base62
defp now do
encode(System.os_time(:microseconds))
end

# Assigns a random node_id on first call
defp node_id do
case Application.get_env(:event_bus, :node_id) do
nil -> save_node_id(random(3, 238_328))
nid -> nid
end
end

defp save_node_id(node_id) do
Application.put_env(:event_bus, :node_id, node_id, persistent: true)
node_id
end
end
37 changes: 3 additions & 34 deletions lib/event_bus/utils/string.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,9 @@ defmodule EventBus.Util.String do
@moduledoc false
# String util for event bus

@base62_map '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
@max_str_reminder 238_327 # 'zzz'
alias EventBus.Util.Base62

@doc """
Generates partially sequential random id
"""
@spec unique_id() :: String.t()
def unique_id do
base62_encode(now()) <> random()
end

def base62_encode(num) do
new_num = div(num, 62)
unless new_num == 0, do: merge(new_num, num), else: to_str(num)
end

defp merge(new_num, num) do
base62_encode(new_num) <> to_str(num)
end

defp to_str(num) do
<< Enum.at(@base62_map, rem(num, 62)) >>
end

# Random string based on system's monotonic time
defp random do
System.monotonic_time(:nano_seconds)
|> rem(1_000_000) # Take last 6 digits
|> rem(@max_str_reminder) # Set max to 'zzz'
|> base62_encode()
|> String.pad_leading(3, "0")
end

defp now do
System.os_time(:micro_seconds)
end
defdelegate unique_id,
to: Base62
end
19 changes: 19 additions & 0 deletions test/event_bus/utils/base62_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
defmodule EventBus.Util.Base62Test do
use ExUnit.Case
alias EventBus.Util.Base62

test ".encode" do
assert "0" == Base62.encode(0)
assert "z" == Base62.encode(61)
assert "10" == Base62.encode(62)
assert "1p0uwg6tOzJ" == Base62.encode(1529891323138833953)
end

test ".unique_id" do
refute Base62.unique_id() == Base62.unique_id()
end

test ".unique_id length" do
assert 16 == String.length(Base62.unique_id())
end
end
5 changes: 0 additions & 5 deletions test/event_bus/utils/string_test.exs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
defmodule EventBus.Util.StringTest do
use ExUnit.Case
alias EventBus.Util.String, as: StringUtil

test "generates unique_id" do
refute StringUtil.unique_id() == StringUtil.unique_id()
end
end

0 comments on commit 956ffd9

Please sign in to comment.