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?
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.
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.
Related
I have this concrete syntax:
syntax SomeMore = [...] SyncBlock? sync;
syntax SyncBlock = "sync" "{" SyncStatement* stats "}";
syntax SyncStatement = [...];
[SyncBlock]"sync { <syncStrings> }" seems to work, but when I try to use it as a SyncBlock? and assign it:
SyncBlock? sync = [SyncBlock?]"sync { <syncStrings> }"
it does not work: inline parsing not supported on SyncBlock?, what is the easiest way to build up a value of this X?-type?
Can I convert a SyncBlock to a SyncBlock? somehow?
Something like this also doesn’t work:
syncBlock = (SyncBlock?)`sync { <SyncStatement* syncs>}`;
P.S. SyncBlock? syncBlock = … results in Ambiguous code (internal error), SyncBlock? syncBlock = …. Probably due to a ternary operator ambiguity?
I found a workaround, not ideal, but it works.
It seems that the ? in the types introduces some difficulties, but can be circumvented using an "alias" for this type:
I changed the grammar to:
syntax SomeMore = [...] MaybeSyncBlock sync;
syntax MaybeSyncBlock = SyncBlock?;
syntax SyncBlock = "sync" "{" SyncStatement* stats "}";
syntax SyncStatement = [...];
Now this works:
MaybeSyncBlock syncBlock = [MaybeSyncBlock]"sync { <syncStrings> }";
Hello I am writing oauth 2 library to access google api's and my code is as follows
jwt_create() ->
{ok,PemBin} = file:read_file("your-key-file.pem"),
PemEntry = public_key:pem_decode(PemBin),
[A,B] = PemEntry,
io:format("A:: ~p ~n",[A]),
PrivateKey = public_key:pem_entry_decode(PemEntry),
JwtHeaderJson = encode_json(jwt_header()),
JwtClaimsetJson = encode_json(jwt_claimset()),
ComputeSignature = compute_signature(JwtHeaderJson, JwtClaimsetJson, PrivateKey),
Z=binary:replace(
binary:replace(<<JwtHeaderJson/binary, ".", JwtClaimsetJson/binary, ".", ComputeSignature/binary>>,
<<"+">>, <<"-">>, [global]),
<<"/">>, <<"_">>, [global]),
io:format("JWT:: ~p ~n",[Z]).
compute_signature(Header, ClaimSet,#'RSAPrivateKey'{publicExponent=Exponent
,modulus=Modulus
,privateExponent=PrivateExponent}) ->
base64:encode(crypto:sign(rsa, sha256, <<Header/binary, ".", ClaimSet/binary>>,
[Exponent, Modulus, PrivateExponent])).
encode_json(JWToken) ->
base64:encode(jsx:encode(JWToken)).
I am getting error as follows:
exception error: no function clause matching
public_key:pem_entry_decode([{'PrivateKeyInfo',<<48,130,4,191,2,1,0,48,13,6,9,42,134,
72,134,247,13,1,1,1,5,0,4,130,4,...>>,
not_encrypted},
{'Certificate',<<48,130,3,96,48,130,2,72,160,3,2,1,2,2,8,
79,59,244,35,60,15,3,155,48,...>>,
not_encrypted}]) (public_key.erl, line 123)
in function googleoauth:jwt_create/0 (src/googleoauth.erl, line 55)
Please help me in generating JWS and JWT for OAUTH 2 for accessing google apis
You are passing the wrong thing to public_key:pem_entry_decode/1:
This will resolve your problem:
PrivateKey = public_key:pem_entry_decode(A),
public_key:pem_entry_decode/1 takes a single pem_entry() but a PEM file can contain many entries, perhaps your code PemEntry = public_key:pem_decode(PemBin) should read PemEntries = public_key:pem_decode(PemBin) instead?
Also note the line before assumes 2 list entries, you might have meant this instead (not sure your intent here though)?
[A|B] = PemEntry,
I am playing with records and list. Please, I want to know how to use one variable twice. When I assign any values into variable _list and after that I try rewrite this variable then raising error:
** exception error: no match of right hand side value
-module(hello).
-author("anx00040").
-record(car, {evc, type, color}).
-record(person, {name, phone, addresa, rc}).
-record(driver, {rc, evc}).
-record(list, {cars = [], persons = [], drivers = []} ).
%% API
-export([helloIF/1, helloCase/1, helloResult/1, helloList/0, map/2, filter/2, helloListCaA/0, createCar/3, createPerson/4, createDriver/2, helloRecords/0, empty_list/0, any_data/0, del_Person/1, get_persons/1, do_it_hard/0, add_person/2]).
createCar(P_evc, P_type, P_color) -> _car = #car{evc = P_evc, type = P_type, color = P_color}, _car
.
createPerson(P_name, P_phone, P_addres, P_rc) -> _person= #person{name = P_name, phone = P_phone, addresa = P_addres, rc = P_rc}, _person
.
createDriver(P_evc, P_rc) -> _driver = #driver{rc = P_rc, evc = P_evc}, _driver
.
empty_list() ->
#list{}.
any_data() ->
_car1 = hello:createCar("BL 4", "Skoda octavia", "White"),
_person1 = hello:createPerson("Eduard B.","+421 917 111 711","Kr, 81107 Bratislava1", "8811235"),
_driver1 = hello:createDriver(_car1#car.evc, _person1#person.rc),
_car2 = hello:createCar("BL 111 HK", "BMW M1", "Red"),
_person2 = hello:createPerson("Lenka M","+421 917 111 111","Krizn0, 81107 Bratislava1", "8811167695"),
_driver2 = hello:createDriver(_car2#car.evc, _person2#person.rc),
_car3 = hello:createCar("BL 123 AB", "Audi A1 S", "Black"),
_person3 = hello:createPerson("Stela Ba.","+421 918 111 711","Azna 20, 81107 Bratislava1", "8811167695"),
_driver3 = hello:createDriver(_car3#car.evc, _person3#person.rc),
_list = #list{
cars = [_car1,_car2,_car3],
persons = [_person1, _person2, _person3],
drivers = [_driver1, _driver2, _driver3]},
_list.
add_person(List, Person) ->
List#list{persons = lists:append([Person], List#list.persons) }.
get_persons(#list{persons = P}) -> P.
do_it_hard()->
empty_list(),
_list = add_person(any_data(), #person{name = "Test",phone = "+421Test", addresa = "Testova 20 81101 Testovo", rc =88113545}),
io:fwrite("\n"),
get_persons(add_person(_list, #person{name = "Test2",phone = "+421Test2", addresa = "Testova 20 81101 Testovo2", rc =991135455}))
.
But it raising error when i use variable _list twice:
do_it_hard()->
empty_list(),
_list = add_person(any_data(), #person{name = "Test",phone = "+421Test", addresa = "Testova 20 81101 Testovo", rc =88113545}),
_list =add_person(_list, #person{name = "Test2",phone = "+421Test2", addresa = "Testova 20 81101 Testovo2", rc =991135455}),
get_persons(_list)
.
In the REPL, it can be convenient to experiment with things while re-using variable names. There, you can do f(A). to have Erlang "forget" the current assignment of A.
1> Result = connect("goooogle.com").
{error, "server not found"}
2> % oops! I misspelled the server name
2> f(Result).
ok
3> Result = connect("google.com").
{ok, <<"contents of the page">>}
Note that this is only a REPL convenience feature. You can't do this in actual code.
In actual code, variables can only be assigned once. In a procedural language (C, Java, Python, etc), the typical use-case for reassignment is loops:
for (int i = 0; i < max; i++) {
conn = connect(servers[i]);
reply = send_data(conn);
print(reply);
}
In the above, the variables i, conn, and reply are reassigned in each iteration of the loop.
Functional languages use recursion to perform their loops:
send_all(Max, Servers) ->
send_loop(1, Max, Servers).
send_loop(Current, Max, _Servers) when Current =:= Max->
ok;
send_loop(Current, Max, Servers) ->
Conn = connect(lists:nth(Current, Servers)),
Reply = send_data(Conn),
print(Reply).
This isn't very idiomatic Erlang; I'm trying to make it mirror the procedural code above.
As you can see, I'm getting the same effect, but my assignments within a function are fixed.
As a side note, you are using a lot of variable names beginning with underscore. In Erlang this is a way of hinting that you will not be using the value of these variables. (Like in the above example, when I've reached the end of my list, I don't care about the list of servers.) Using a leading underscore as in your code turns off some useful compiler warnings and will confuse any other developers who look at your code.
In some situations it is convenient to use use SeqBind:
SeqBind is a parse transformation that auto-numbers all occurrences of these bindings following the suffix # (creating L#0, L#1, Req#0, Req#1) and so on.
Simple example:
...
-compile({parse_transform,seqbind}).
...
List# = lists:seq(0, 100),
List# = lists:filter(fun (X) -> X rem 2 == 0 end, List#)
...
I used google...
Erlang is a single-assignment language. That is, once a variable has been given a value, it cannot be given a different value. In this sense it is like algebra rather than like most conventional programming languages.
http://www.cis.upenn.edu/~matuszek/General/ConciseGuides/concise-erlang.html
I'm trying to extract the second link under the description tag. I have written the following code, but it looks really messy with freads and substrings (just to get it to work). Is there any cleaner way to accomplish this?
magic(Url)->
Tag = ".xml",
inets:start(),
{ ok, {Status, Headers, Body }} = httpc:request(Url ++ Tag),
{ Xml, Rest } = xmerl_scan:string(Body),
{xmlObj , string , A } = xmerl_xpath:string("substring-after(substring-after(substring->before(//channel/item/description[1], '\">[link]') , 'br') , 'href=')", Xml),
{ok,_,B} = io_lib:fread("~6s" , A),
string:sub_string(B,1,string:len(B)-1).
Not a perfect solution, but you may use such xpaths
//channel/item/description[1]/text()[16] and //channel/item/description[1]/text()[24]
extracted strings contains urls + quotes at the beginning, so you may use list matching syntax to cut off quotation marks: [_|Url] = ...
So use this: [{_,_,_,_,[_|U1],_}] = xmerl_xpath:string("//channel/item/description[1]/text()[16]", Xml). to bind U1 with first url.
Test in shell:
11> [{_,_,_,_,[_|U1],_}] = xmerl_xpath:string("//channel/item/description[1]/text()[16]", Xml).
[{xmlText,[{description,5},{item,5},{channel,1},{rss,1}],
16,[],"\"http://www.reddit.com/user/escaped_reddit",text}]
12>
12> U1.
"http://www.reddit.com/user/escaped_reddit"
13>
13>
13> [{_,_,_,_,[_|U2],_}] = xmerl_xpath:string("//channel/item/description[1]/text()[24]", Xml).
[{xmlText,[{description,5},{item,5},{channel,1},{rss,1}],
24,[],
"\"http://www.reddit.com/r/erlang/comments/y62wf/how_to_use_ranch/",
text}]
14>
14> U2.
"http://www.reddit.com/r/erlang/comments/y62wf/how_to_use_ranch/"
Platform: (where Lua and LuaSocket are ported)
An embedded system using ARM 7 development board running 3rd party RTOS with TCP/IP stack.
What works:
Using Lua standard library such as "io" calls, print, assert, etc
sending UDP packets by using the udp = assert(socket.udp) method, assert(udp:send(something))
Problem:
When executing an example smtp lua script:
local smtp = require("socket.smtp")
from = "myEmail"
rcpt = {"<someOne's Email>"}
mesgt = { heasers = {someHeader}, body = "Hello World" }
r, e = smtp.send {
from = from,
rcpt = rcpt,
source = smtp.message(mesgt),
server = "someServer",
port = 25,
}
-- an error returns after execution:
-- lua\socket\smtp.lua:115: attempt to call field 'try' (a nil value)
-- Corresponding code in smtp.lua around line 115:
function open(server, port, create)
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
TIMEOUT, create))
local s = base.setmetatable({tp = tp}, metat)
-- make sure tp is closed if we get an exception
s.try = socket.newtry(function()
s:close()
end)
return s
end
// Where try = newtry() in socket.lua and the corresponding C code is the same
// from the one provided with the library for UNIX:
static int global_newtry(lua_State *L) {
lua_settop(L, 1);
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
lua_pushcclosure(L, finalize, 1);
return 1;
}
Well, since the error says that "try is nil", then my best guess is that the C lib is not correctly, or not completely, linked to your Lua. This could be the result of a faulty installation, a missing lib, or something of that sort.