-module(ids@cuid). -compile(no_auto_import). -export([start/0, gen/1, is_cuid/1, slug/1, is_slug/1]). start() -> gleam@otp@actor:start({state, 0, get_fingerprint()}, fun handle_msg/2). gen(Channel) -> gleam@otp@actor:call(Channel, fun(A) -> {generate, A} end, 1000). is_cuid(Id) -> gleam@string:starts_with(Id, <<"c"/utf8>>). slug(Channel) -> gleam@otp@actor:call(Channel, fun(A) -> {generate_slug, A} end, 1000). is_slug(Slug) -> SlugLength = gleam@string:length(Slug), (SlugLength >= 7) andalso (SlugLength =< 10). handle_msg(Msg, State) -> case Msg of {generate, Reply} -> Id = format_id( [<<"c"/utf8>>, timestamp(), format_count(erlang:element(2, State)), erlang:element(3, State), random_block(), random_block()] ), gleam@otp@actor:send(Reply, Id), {continue, erlang:setelement(2, State, new_count(erlang:element(2, State)))}; {generate_slug, Reply@1} -> Slug = format_id( [gleam@string:slice(timestamp(), -2, 2), gleam@string:slice( format_count(erlang:element(2, State)), -4, 4 ), gleam@string:concat( [gleam@string:slice(erlang:element(3, State), 0, 1), gleam@string:slice(erlang:element(3, State), -1, 1)] ), gleam@string:slice(random_block(), -2, 2)] ), gleam@otp@actor:send(Reply@1, Slug), {continue, erlang:setelement(2, State, new_count(erlang:element(2, State)))} end. format_id(IdData) -> gleam@string:lowercase(gleam@string:concat(IdData)). new_count(Count) -> case Count < 1679616 of true -> Count + 1; false -> 0 end. timestamp() -> Secs = gleam@os:system_time(millisecond), gleam@int:to_base_string(Secs, 36). format_count(Num) -> gleam@string:pad_left(gleam@int:to_base_string(Num, 36), 4, <<"0"/utf8>>). get_fingerprint() -> Operator = 36 * 36, {ok, Pid} = gleam@int:parse(erlang:list_to_binary(os:getpid())), Id = (Pid rem Operator) * Operator, Localhost = net_adm:localhost(), Sum = gleam@list:fold(Localhost, 0, fun(Char, Acc) -> Char + Acc end), Hostid = ((Sum + gleam@list:length(Localhost)) + 36) rem Operator, gleam@int:to_base_string(Id + Hostid, 36). random_block() -> gleam@string:pad_left( gleam@int:to_base_string(rand:uniform(1679616 - 1), 36), 4, <<"0"/utf8>> ).