Print the exmpp Packet to Raw XML string - erlang

How to print the Packet type to raw XML string ? In the example https://github.com/processone/exmpp/blob/master/examples/echo_client.erl the echo_packet(MySession, Packet) -> function takes the parameter Packet which is of xmlel record type. As mentioned in the post https://stackoverflow.com/a/31020654/579689 tried the function xml:element_to_binary/1 but it did not work.
When i tried to print using the following expression
io:format("Received Presence stanza:~n~p~n~n", [xml:element_to_binary({xmlel,<<"message">>,[{<<"xml:lang">>,<<"en">>},{<<"type">>,<<"chat">>},{<<"to">>,<<"x">>},{<<"id">>,<<"aaf6a">>}],[{xmlcdata,<<"\n">>},{xmlel,<<"body">>,[],[{xmlcdata,<<"wewe">>}]},{xmlcdata,<<"\n">>},{xmlel,<<"active">>,[{<<"xmlns">>,<<"http://jabber.org/protocol/chatstates">>}],[]},{xmlcdata,<<"\n">>},{xmlel,<<"time">>,[{<<"xmlns">>,<<"urn:server-time">>},{<<"stamp">>,"2015-06-23T22:48:24Z"}],[]}]})]).
received following error
=ERROR REPORT==== 12-Oct-2015::09:06:01 ===
Error in process <0.30.0> with exit value: {undef,[{xml,element_to_binary,[{xmlel,<<7 bytes>>,[{<<8 bytes>>,<<2 bytes>>},{<<4 bytes>>,<<4 bytes>>},{<<2 bytes>>,<<1 byte>>},{<<2 bytes>>,<<5 bytes>>}],[{xmlcdata,<<1 byte>>},{xmlel,<<4 bytes>>,[],[{xmlcdata,<<4 bytes>>}]},{xmlcdata,<<1 byte>>},{xmlel,<<6 bytes>>,[{<<5 bytes>>,<<37 bytes>>}],[]},{xmlcdata,<<1 byte>>},{xmlel,<<4 bytes>>,[{<<5 bytes>>,<<15 bytes>>},{<<5 bytes>>,"2015-06-23T22:48:24Z"}],[]}]}],[]},{echo_client,loop,1,[{file,"../examples/ech...

Error {undef,[{xml,element_to_binary,[list of N args]}]} tells you that function xml:element_to_binary/N is undefined.
Looking through xml module of the project you may try element_to_string instead of element_to_binary.
However from the point of efficiency exmpp_xml:document_to_iolist/1 will suit you better

Related

Erlang's dets doesn't create file with open_file

It's my first attempt to write anything in Erlang, so maybe the question is silly.
I'm writing a quite simple HTTP server using cowboy
db_name() -> "DB_test".
timestamp() ->
calendar:datetime_to_gregorian_seconds(calendar:universal_time()).
sha(Str) ->
<<X:256/big-unsigned-integer>> = crypto:hash(sha256, Str),
lists:flatten(io_lib:format("~64.16.0b", [X])).
handle_post(Req0, State) ->
Link = binary_to_list(cowboy_req:header(<<"link">>, Req0)),
dets:open_file(db_name(), []),
dets:insert(db_name(), {hashed_url(Link), Link, timestamp()}),
Req = cowboy_req:reply(200,
#{<<"content-type">> => <<"text/plain">>},
sha(Link),
Req0),
{ok, Req, State}.
The idea is that a POST HTTP request contains a 'link' header with some link. After recieving such request my server should store it's hash in dets table along with the link and its timestamp. The problem is that the "DB_test" file isn't created. Why?
Based on your example code, it's hard to say exactly why, since you're ignoring the return values from both dets:open_file/2 and dets:insert/2.
Both of them return different values for the success and failure cases; but do not throw exceptions.
See the official documentation for more details: http://erlang.org/doc/man/dets.html
The simplest solution to this is to crash the cowboy connection handling process in non-success cases. You can do that by doing something like the following:
{ok, Ref} = dets:open_file(db_name(), []),
ok = dets:insert(Ref, {hashed_url(Link), Link, timestamp()}),
This will crash with a badmatch exception in the failure cases, when the value returned cannot be pattern matched to the left-hand side of the statement, subsequently causing cowboy to return HTTP 500 to the client.
You'll then see details on what the actual error was in the stacktrace logged
A second solution would be to explicitly handle the failure cases, you can use the 'case' keyword for that.
An example would be something like:
case dets:open_file(db_name(), []) of
{ok, Ref} ->
do_success_things();
{error, Reason}=E ->
io:format("Unable to open database file: ~p~n", [E]),
do_failure_things();
end
For further reading, I'd highly recommend the Syntax in functions and Errors and exceptions chapters of Learn you some Erlang for great good: http://learnyousomeerlang.com/

How to check if a Pid is member of a list of Pids in Erlang?

I have a function that sets a value to a process Pid and I can have a process depend on another one. So if I set a value to a process then I have to also set the value to the processes that depend on it. However, if there is a circle between the processes
i.e. A depends on B and B depends on A
then I want to return an error message.
I try to do this by passing a list of Pids which have already changed values so that if I come across the same Pid twice (By checking if it is a member of the list of Pids) then the whole function stops. This is my code:
set_values(Pid, Value, PidSet, PidList) ->
case lists:member(Pid, PidList) of
false -> io:format("Setting Value~n"),
lists:map(fun(Pid) ->
Pid ! {self(), set_value, Value, [Pid | PidList]} end, PidSet);
true -> io:format("circle_detected~n"),
Pid ! {circle_detected}
end.
When I run it, I get this error:
=ERROR REPORT==== 2-Nov-2014::17:47:45 ===
Error in process <0.888.0> with exit value: {badarg,[{lists,member,
[<0.888.0>,empty_list],[]},{process,set_viewer_values,4,[{file,"process.erl"},{line,56}]},
{process,looper,2,[{file,"process.erl"},{line,116}]}]}
From what I understand I give bad arguments to lists:member function.
What should I do?
Thanks
If you read your error message, you have {lists,member,
[<0.888.0>,empty_list] ..., where lists is module, member is function name, and [<0.888.0>,empty_list] are aruguments (two) presented as list. So you are making call to lists:nenber/2 with PidList variable being atom empty_list. And this gives you an error.
So you need to look into how you funciton is being called (prefered), or create some pattern match on PidList like
set_values(Pid, Value, PidSet, _PidList = empty_list) ->
...

MailboxProcessor.PostAndReply design choice

Looking at:
member this.PostAndReply : (AsyncReplyChannel<'Reply> -> 'Msg) * ?int -> 'Reply
I can't figure out why the signature looks so counter-intuitive to me. What we want to do is posting a message to an agent, and wait for a reply.
Why do we have to give him a weird function as a 'message'?
See again this MSDN snippet:
let rec loop() =
printf "> "
let input = Console.ReadLine()
printThreadId("Console loop")
let reply = agent.PostAndReply(fun replyChannel -> input, replyChannel)
if (reply <> "Stopping.") then
printfn "Reply: %s" reply
loop()
else
()
loop()
I'd rather prefer something like this:
member this.PostAndReply : 'Msg * ?int -> 'Reply
Thanks
This type signature looks pretty confusing when you see it for the first time, but it does make sense.
The F# library design
The idea behind the is that when you call PostAndReply you need to give it a function that:
constructs a message of type 'Msg (to be sent to the agent)
after the F# runtime builds a channel for sending messages back to the caller (channels are represented as values of type AsyncReplyChannel<'Reply>).
The message that you construct needs to contain the reply channel, but the F# library does not know how you want to represent your messages (and so it does not know how you want to store the reply channel in the message). As a result, the library asks you to write a function that will construct the message for the agent after the system constructs the channel.
Your alternative suggestion
The problem with your suggestion is that if PostAndReply had a type 'Msg -> 'Reply, the message that the agent receives after it calls Receive would be of the following type:
'Msg * AsyncReplyChannel<'Reply>
... so every message received to the agent would also have to carry a channel for sending replies back. However, you probably don't want to send a reply back for every received message, so this wouldn't really work. Maybe you could use something like:
'Msg * option<AsyncReplyChannel<'Reply>>
... but that's just getting more complicated (and it still isn't quite right, because you can only reply to some messages from 'Msg, but not to all of them).

How to use bitcask as a stand alone

(edit: i miss some reputation to create the bitcask tag so ...)
(tl;dr => bitcask:get/2 doesn't work and raises badarg in bitcask_nifs:keydir_get_int)
I would like to know how to use bitcask without riak the right way.
First, i was trying this:
bitcask:put(Handle, 3, {this, is, data}).
bitcask:get(Handle, 3).
This two calls raise the same error : badarg with erlang:size/1
The problem is erlang:size/1 accepts only binaries or tuples.
So i was trying this :
bitcask:put(Handle, {thing, 3}, {this, is, data}).
bitcask:get(Handle, {thing, 3}).
A new badarg error then, with erlang:crc32 and the Value i want to store.
So now i use this code, bucket is the atom name of a registered gen_server
which keeps the handle in its state. cask_wrapper is the code for theese
gen_servers. The code below is the acces to theese gen servers.
-module(sr_db).
...
get(Type, Key) when not is_binary(Key) ->
?MODULE:get(Type, term_to_binary(Key));
get(Type, Key) ->
Bucket = type2bucket(Type),
cask_wrapper:get(Bucket, {get, Key}).
put(Type, Key, Data) when not is_binary(Key) ->
?MODULE:put(Type, term_to_binary(Key), Data);
put(Type, Key, Data) when not is_binary(Data) ->
?MODULE:put(Type, Key, term_to_binary(Data));
put(Type, Key, Data) ->
Bucket = type2bucket(Type),
cask_wrapper:put(Bucket, Key, Data),
ok.
%% syncput(Type, Key, Data) -> call au lieu de cast
type2bucket(user) -> users_cask.
I use this code like this:
sr_db:get(user, 3).
%% then a call is made to cask_wrapper:get(users_cask, {get, 3}).
there are the cask_wrapper functions
get(Bucket, Key) ->
gen_server:call(Bucket, {get, Key}).
handle_call({get, Key}, _From, State) ->
Fetch = bitcask:get(State#state.handle, Key),
{reply, Fetch, State}.
I use the same mechanism with the put function. (but with gen_server:cast)
My first question is : is doing term_to_binary conversion in every call
a good practice, or is it slow ? I will have to convert back to erlang
terms the values that i fetch.
At the moment, the put operation returns 'ok'. It works. But the get
operation doesn't work yet. This is the error:
=ERROR REPORT==== 29-Jan-2012::20:21:24 ===
** Generic server users_cask terminating
** Last message in was {get,{get,<<131,97,3>>}}
** When Server state == {state,#Ref<0.0.0.353>}
** Reason for termination ==
** {badarg,[{bitcask_nifs,keydir_get_int,[<<>>,{get,<<131,97,3>>}]},
{bitcask_nifs,keydir_get,2},
{bitcask,get,3},
{cask_wrapper,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}
Bitcask dir : "/home/niahoo/src/skyraiders/priv/bitcasks/users"
options : [read_write]** exception exit: {{badarg,
[{bitcask_nifs,keydir_get_int,
[<<>>,{get,<<131,97,3>>}]},
{bitcask_nifs,keydir_get,2},
{bitcask,get,3},
{cask_wrapper,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]},
{gen_server,call,[users_cask,{get,{get,<<131,97,3>>}}]}}
in function gen_server:call/2
I can't figure out why it does not work and would appreciate some help.
Thank you
Bitcask expects the key and the value both to be binaries (as you already noticed).
I don't really know how fast term_to_binary/binary_to_term is, but there is really no way around it if you want to store terms on disk. You could of course roll you own code to convert you keys and values to/from binaries, but I doubt that it will be significantly fast than the builtin functions and certainly less flexible.
But at the end of the day you have to measure the profile your application, and decide if term_to_binary/binary_to_term is a hotspot in your total system. I would be very surprised if that is the case in any real application where data has to be written to disk.
Now to the error when calling sr_db:get/2. You are wrapping the key twice inside a {get, Key} tuple, once inside sr_db:get/2 and another time in cask_wrapper:get/2, but you unwrap it only once, by matching in cask_wrapper:handle_call/3.
You can immediately spot this in the error report in those two lines:
** Last message in was {get,{get,<<131,97,3>>}}
and
{gen_server,call,[users_cask,{get,{get,<<131,97,3>>}}]}}

Thrift/Erlang string

I'm trying to write a simple Thrift server in Erlang that takes a string and returns a string.
Everything seems to be working up to the point of calling my function:
handle_function(Function, Args) when is_atom(Function), is_tuple(Args) ->
case apply(?MODULE, Function, tuple_to_list(Args)) of
ok -> ok;
Reply -> {reply, Reply}
end.
test([X]) ->
"You sent: " ++ X.
I'm getting a function_clause. The stack trace shows the following:
{function_clause, [{server, test,
[<<"w00t">>]},
{server,handle_function, 2}, ...
My handle_function is copied from the tutorial file so I won't be surprised if I need to tweak it. Any ideas?
That last argument of apply should be a list of arguments to 'test', e.g., if tuple_to_list(Args) resulted in:
[1]
...then:
test(1)
If tuple_to_list(Args) resulted in:
[1,2]
...then:
test(1,2)
So, if {<<"woot">>} is being passed to tuple_to_list, that's going to be:
[<<"woot">>]
...so:
test(<<"woot">>)
...but test's signature asks for a list as the argument, so there's a mismatch.

Resources