Receiving multipart SMS
dowusu opened this issue · 2 comments
dowusu commented
This is not an issue, more of a feature request. I've been received multipart sms from the SMSC, currently I store the various parts in a ets
table using using a combination of source_addr, destination_addr and part of the multipart as a key with the actual message and sequence stored in a MapSet, I was wondering if there's an existing feature for handling/assembling incoming multipart message. Below is my current implementation for handling multipart using ets
.
def handle_cast(
{:pdu, %{mandatory: %{destination_addr: short_code, source_addr: msisdn, esm_class: 64}} = pdu, pid},
state
) do
{:ok, {ref, count, seq}, msg} = SMPPEX.Pdu.Multipart.extract_from_pdu(pdu)
key = "#{msisdn}_#{short_code}_#{ref}_#{count}" # Can use erlang:phash2 for a short key
case lookup(key) do
{:error, :not_found} ->
:ets.insert(__MODULE__, {key, MapSet.new([{seq, msg}])})
{:ok, [{_, result}]} ->
process_message(result, key, count, seq, msg)
end
end
{:noreply, state}
end
defp process_message(result, key, count, seq, msg) do
unless MapSet.member?(result, {seq, msg}) do
result = MapSet.put(result, {seq, msg})
if Enum.count(result) == count do
merge_message(result)
else
update_element(key, {2, result})
end
else
:ignore
end
end
defp merge_message(result) do
msg =
result
|> Enum.sort()
|> Enum.map(fn {_, ms} -> ms end)
|> Enum.join()
{:sms, msg}
end
defp update_element(key, value) do
:ets.update_element(__MODULE__, key, value)
end
defp lookup(key) do
case :ets.lookup(@table_name, key) do
[_ | _] = result -> {:ok, result}
_ -> {:error, :not_found}
end
end
savonarola commented
Hello!
Thank you for the proposal. In the projects I worked on we used hashes in Redis to keep message parts, and quite similar key structure.
I will consider adding some aggregation functionality since it appears to be a common need.
dowusu commented
Thanks 👍.