Muhammad Kholid B
Muhammad Kholid B

Reputation: 477

Elixir marshal ISO 8583 message error with Erlang library

I am new to elixir and I need to create ISO 8583 client with this language and Phoenix framework. I found an Erlang library for it from stackoverflow thread here, compiled successfully and followed the example in the repository here but got error when marshaling the message. Here is my Elixir code to marshal the message:

msg1 = :erl8583_message.new()
msg2 = :erl8583_message.set_mti("0800", msg1)
msg3 = :erl8583_message.set(3, "300000", msg2)
msg4 = :erl8583_message.set(24, "045", msg3)
msg5 = :erl8583_message.set(41, "11111111", msg4)
msg6 = :erl8583_message.set(42, "222222222222222", msg5)
msg7 = :erl8583_message.set(63, "This is a Test Message", msg6)
marshalled = :erl8583_marshaller_ascii.marshal(msg7)

That's just an elixir version from the example on the repo. This is the error I've got when running the app:

[error] #PID<0.438.0> running TestlangIsoClientWeb.Endpoint (cowboy_protocol) terminated
Server: 127.0.0.1:4001 (http)
Request: POST /api/process
** (exit) an exception was raised:
    ** (FunctionClauseError) no function clause matching in :erl8583_marshaller_ascii.marshal_data_element/2
        (erl8583) /home/muhammad/Workspace/testlang/testlang_iso_client/deps/erl8583/src/erl8583_marshaller_ascii.erl:168: :erl8583_marshaller_ascii.marshal_data_element({:n, :fixed, 4}, "0800")
        (erl8583) /home/muhammad/Workspace/testlang/testlang_iso_client/deps/erl8583/src/erl8583_marshaller.erl:108: :erl8583_marshaller.marshal/2
        (testlang_iso_client) lib/testlang_iso_client_web/controllers/my_controller.ex:61: TestlangIsoClientWeb.MyController.process/2
        (testlang_iso_client) lib/testlang_iso_client_web/controllers/my_controller.ex:1: TestlangIsoClientWeb.MyController.action/2
        (testlang_iso_client) lib/testlang_iso_client_web/controllers/my_controller.ex:1: TestlangIsoClientWeb.MyController.phoenix_controller_pipeline/2
        (testlang_iso_client) lib/testlang_iso_client_web/endpoint.ex:1: TestlangIsoClientWeb.Endpoint.instrument/4
        (phoenix) lib/phoenix/router.ex:278: Phoenix.Router.__call__/1
        (testlang_iso_client) lib/testlang_iso_client_web/endpoint.ex:1: TestlangIsoClientWeb.Endpoint.plug_builder_call/2
        (testlang_iso_client) lib/testlang_iso_client_web/endpoint.ex:1: TestlangIsoClientWeb.Endpoint.call/2
        (plug) lib/plug/adapters/cowboy/handler.ex:16: Plug.Adapters.Cowboy.Handler.upgrade/4
        (cowboy) /home/muhammad/Workspace/testlang/testlang_iso_client/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

Is there something I missed to make it work? Any help would be very appreciated.

Updated

I have tried to changed the string parameter to charlist, but still got the same error. Here is the code snippet:

def test(conn, _params) do
  IO.puts("Test")
  msg1 = :erl8583_message.new()
  msg2 = :erl8583_message.set_mti('0800', msg1)
  msg3 = :erl8583_message.set(3, '300000', msg2)
  msg4 = :erl8583_message.set(24, '045', msg3)
  msg5 = :erl8583_message.set(41, '11111111', msg4)
  msg6 = :erl8583_message.set(42, '222222222222222', msg5)
  msg7 = :erl8583_message.set(63, 'This is a Test Message', msg6)
  marshalled = :erl8583_marshaller_ascii.marshal(msg7)
  json(conn, %{status: "ok"})
end

Here is the function erl8583_marshaller.erl:108 mentioned in the stacktrace:

marshal(Message, MarshalHandlers) ->
    OptionsRecord = parse_options(MarshalHandlers, #marshal_options{}),
    {Marshalled1, Message1} = init_marshalling(OptionsRecord, Message),
    MarshalledMti = encode_mti(OptionsRecord, Message1),  % --- Line 108
    Marshalled2 = <<Marshalled1/binary, MarshalledMti/binary>>,
    {MarshalledBitmap, Message2} = encode_bitmap(OptionsRecord, Message1),
    Marshalled3 = <<Marshalled2/binary, MarshalledBitmap/binary>>,
    MarshalledFields = encode_fields(OptionsRecord, Message2),
    Marshalled4 = <<Marshalled3/binary, MarshalledFields/binary>>,
    end_marshalling(OptionsRecord, Message2, Marshalled4).

And here is the function erl8583_marshaller_ascii.erl:168 mentioned in the stacktrace:

%%
%% Local Functions
%%
marshal_data_element({n, llvar, Length}, FieldValue) when length(FieldValue) =< Length ->
    erl8583_convert:integer_to_string(length(FieldValue), 2) ++ FieldValue;

I don't understand why the call to that function was failed to match with parameters {:n, :fixed, 4}, "0800" that was sent from my function. I have tried to change the double quotes to single quotes with no success. Is there any other suggestions what am I supposed to do?

Upvotes: 1

Views: 274

Answers (2)

Nuku Ameyibor
Nuku Ameyibor

Reputation: 51

there may be a bug in the code. you can reference this issue here

there is one elixir library out which is relatively new.

its called ale8583.

documentation is still coming out on this one but looks very promising.

you can check it out.

Upvotes: 3

legoscia
legoscia

Reputation: 41598

Try passing charlists instead of strings:

msg1 = :erl8583_message.new()
msg2 = :erl8583_message.set_mti('0800', msg1)
msg3 = :erl8583_message.set(3, '300000', msg2)
msg4 = :erl8583_message.set(24, '045', msg3)
msg5 = :erl8583_message.set(41, '11111111', msg4)
msg6 = :erl8583_message.set(42, '222222222222222', msg5)
msg7 = :erl8583_message.set(63, 'This is a Test Message', msg6)
marshalled = :erl8583_marshaller_ascii.marshal(msg7)

There is potential for confusion here:

  • What Erlang calls "strings" and puts in double quotes ("foo"), Elixir calls "charlists" and puts in single quotes ('foo').
  • What Elixir calls "strings" and puts in double quotes ("foo"), Erlang calls "binaries" and puts in double quotes plus angle brackets (<<"foo">>).

It seems like the erl8583 library expects Erlang strings throughout.

Upvotes: 0

Related Questions