-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
106 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,62 @@ | ||
defmodule Snowflake.Helper do | ||
@moduledoc """ | ||
The Helper module helps users work with snowflake IDs. | ||
Helper module can do the following: | ||
- Deriving timestamp based on ID | ||
- Creating buckets based on days since epoch... | ||
Utility functions intended for Snowflake application. | ||
epoch() and machine_id() are useful for inspecting in production. | ||
""" | ||
use Bitwise | ||
@default_config [ | ||
nodes: [], | ||
epoch: 0 | ||
] | ||
|
||
@doc """ | ||
Get timestamp in ms from your config epoch from any snowflake ID | ||
Grabs epoch from config value | ||
""" | ||
@spec timestamp_of_id(integer) :: integer | ||
def timestamp_of_id(id) do | ||
id >>> 22 | ||
@spec epoch() :: integer | ||
def epoch() do | ||
Application.get_env(:snowflake, :epoch) || @default_config[:epoch] | ||
end | ||
|
||
@doc """ | ||
Get timestamp from computer epoch - January 1, 1970, Midnight | ||
Grabs hostname, fqdn, and ip addresses, then compares that list to the nodes | ||
config to find the intersection. | ||
""" | ||
@spec real_timestamp_of_id(integer) :: integer | ||
def real_timestamp_of_id(id) do | ||
timestamp_of_id(id) + Snowflake.Utils.epoch() | ||
@spec machine_id() :: integer | ||
def machine_id() do | ||
nodes = Application.get_env(:snowflake, :nodes) || @default_config[:nodes] | ||
host_addrs = [hostname(), fqdn(), Node.self()] ++ ip_addrs() | ||
|
||
case MapSet.intersection(MapSet.new(host_addrs), MapSet.new(nodes)) |> Enum.take(1) do | ||
[matching_node] -> Enum.find_index(nodes, fn node -> node == matching_node end) | ||
_ -> 1023 | ||
end | ||
end | ||
|
||
@doc """ | ||
Get bucket value based on segments of N days | ||
""" | ||
@spec bucket(integer, atom, integer) :: integer | ||
def bucket(units, unit_type, id) do | ||
round(timestamp_of_id(id) / bucket_size(unit_type, units)) | ||
defp ip_addrs() do | ||
case :inet.getifaddrs do | ||
{:ok, ifaddrs} -> | ||
ifaddrs | ||
|> Enum.flat_map(fn {_, kwlist} -> | ||
kwlist |> Enum.filter(fn {type, _} -> type == :addr end) | ||
end) | ||
|> Enum.filter_map(fn {_, addr} -> tuple_size(addr) in [4, 6] end, fn {_, addr} -> | ||
case addr do | ||
{a, b, c, d} -> [a, b, c, d] |> Enum.join(".") # ipv4 | ||
{a, b, c, d, e, f} -> [a, b, c, d, e, f] |> Enum.join(":") # ipv6 | ||
end | ||
end) | ||
_ -> [] | ||
end | ||
end | ||
|
||
@doc """ | ||
When no id is provided, we generate a bucket for the current time | ||
""" | ||
@spec bucket(integer, atom) :: integer | ||
def bucket(units, unit_type) do | ||
timestamp = System.os_time(:milliseconds) - Snowflake.Utils.epoch() | ||
round(timestamp / bucket_size(unit_type, units)) | ||
defp hostname() do | ||
{:ok, name} = :inet.gethostname() | ||
to_string(name) | ||
end | ||
|
||
defp bucket_size(unit_type, units) do | ||
case unit_type do | ||
:hours -> 1000 * 60 * 60 * units | ||
_ -> 1000 * 60 * 60 * 24 * units # days is default | ||
defp fqdn() do | ||
case :inet.get_rc[:domain] do | ||
nil -> nil | ||
domain -> hostname() <> "." <> to_string(domain) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
defmodule Snowflake.Util do | ||
@moduledoc """ | ||
The Util module helps users work with snowflake IDs. | ||
Util module can do the following: | ||
- Deriving timestamp based on ID | ||
- Creating buckets based on days since epoch... | ||
- get real timestamp of any ID | ||
""" | ||
use Bitwise | ||
|
||
@doc """ | ||
Get timestamp in ms from your config epoch from any snowflake ID | ||
""" | ||
@spec timestamp_of_id(integer) :: integer | ||
def timestamp_of_id(id) do | ||
id >>> 22 | ||
end | ||
|
||
@doc """ | ||
Get timestamp from computer epoch - January 1, 1970, Midnight | ||
""" | ||
@spec real_timestamp_of_id(integer) :: integer | ||
def real_timestamp_of_id(id) do | ||
timestamp_of_id(id) + Snowflake.Helper.epoch() | ||
end | ||
|
||
@doc """ | ||
Get bucket value based on segments of N days | ||
""" | ||
@spec bucket(integer, atom, integer) :: integer | ||
def bucket(units, unit_type, id) do | ||
round(timestamp_of_id(id) / bucket_size(unit_type, units)) | ||
end | ||
|
||
@doc """ | ||
When no id is provided, we generate a bucket for the current time | ||
""" | ||
@spec bucket(integer, atom) :: integer | ||
def bucket(units, unit_type) do | ||
timestamp = System.os_time(:milliseconds) - Snowflake.Helper.epoch() | ||
round(timestamp / bucket_size(unit_type, units)) | ||
end | ||
|
||
defp bucket_size(unit_type, units) do | ||
case unit_type do | ||
:hours -> 1000 * 60 * 60 * units | ||
_ -> 1000 * 60 * 60 * 24 * units # days is default | ||
end | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters