processone / xmpp

Erlang/Elixir XMPP parsing and serialization library on top of Fast XML

Home Page:http://process-one.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

how to add a tag

grizzly-monkey opened this issue · comments

commented

I have created below spec

-record(sync, {id = <<>> :: binary(),
               c = <<>> :: sync_type(),
               from :: undefined | jid:jid(),
               to :: undefined | jid:jid(),
               json :: <<>> :: binary(),
               sub_els = [] :: [xmpp_element() | fxml:xmlel()]
               }).


-xml(sync,
     #elem{name = <<"sync">>,
     xmlns =  [<<"jabber:client">>, <<"jabber:server">>,
               <<"jabber:component:accept">>],
     cdata = #cdata{label = '$json'},
     result = {sync, '$id','$c','$from', '$to', '$json', '$_els'},
     attrs = [ #attr{name = <<"id">>},
               #attr{name = <<"c">>,
                     default = <<"0">> },
               #attr{name = <<"from">>,
             	   		  dec = {dec_jid, []},
             		   	  enc = {enc_jid, []}},
               #attr{name = <<"to">>,
               			  dec = {dec_jid, []},
               			  enc = {enc_jid, []}}
             ]}).

Which parses below request

<<"<sync id='6383950948998274048-13' c='-902781519'>{\"t\":\"sync1\",\"id\":{\"t\":\"UserDets\",\"hash\":2102,\"user_id\":5533240}}</sync>">>

however my reponse to the result is with addtion of response tag as below

<<"<sync id='6383950948998274048-13' c='-902781519'> <response>JSON_RESPONSE </response> </sync>">>

when preparing response packet how do i add response tag ?
in old version i used to

Children = [#xmlel{name = <<"response">>,
        attrs = [],
        children = [{xmlcdata, ResponseData}]}],

Please help
Thanks

Add sync_response spec:

-xml(sync_response,
        #elem{name = <<"response">>,
                xmlns =  [<<"jabber:client">>, <<"jabber:server">>,
                          <<"jabber:component:accept">>],
                result = $cdata}).

-xml(sync,
        #elem{
           result = {sync, '$id','$c','$from', '$to', '$json', '$response', '$_els'},
           %% All your filelds go here
           refs = [#ref{name = sync_response, label = '$response', default = <<"">>}]}).

Then the reply in your code will look like:

Reply = #sync{id = ID, from = To, to = From, response = JSONBinary}

I would also like to add that using jabber:client namespace violates RFC6120, because there is no such element within this namespace defined in RFC6120 schema.

commented

Oh thanks for bringing it to my notice will change the namespace

Error on sync_response that you gave without xmlns

case fxml_gen:compile("specs/xmpp_codec.spec", [{add_type_specs, xmpp_element}, {erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.'
failed to compile "specs/xmpp_codec.spec": {'EXIT',
                                            {{bad_spec,
                                              {empty_xmlns,<<"response">>}},
                                             [{fxml_gen,bad_spec,1,

So later i added

-xml(sync_response,
     #elem{name = <<"response">>,
           xmlns = <<"testing:xmlnss">>,
           result = '$cdata',
           cdata = #cdata{label = '$cdata'}}).

and refs as

refs = [#ref{name = sync_result, label = '$response', default = <<"">>}]}).

But after this i get below error on encode

#sync{id = <<"6383980290226270208-21">>,c = <<"-902781519">>,
      from = {jid,<<>>,<<"dev.com">>,<<>>,<<>>,<<"dev.com">>,<<>>},
      to = {jid,<<"143622">>,<<"dev.com">>,<<"A-3.13">>,<<"143622">>,
                <<"dev.com">>,<<"A-3.13">>},
      json = <<>>,
      response = <<"{\"t\":\"user\",\"id\":143622,\"first_name\":\"Gsr\",\"last_name\":\"Goos\"}">>,
      sub_els = []}

13:04:00.267 [error] Hook c2s_handle_info crashed when running ejabberd_c2s:process_info/2:
** Reason = {error,function_clause, ** [{xmpp_codec,'encode_sync_$result',[{file,"src/xmpp_codec.erl"},{line,2282}],[<<"{"t":"user","id":143622,"first_name":"Gsr","last_name":"Goos"}">>,<<"testing:xmlnss">>,[]]},{xmpp_codec,encode_sync,[{file,"src/xmpp_codec.erl"},{line,2271}],2},{xmpp_stream_in,socket_send,[{file,"src/xmpp_stream_in.erl"},{line,1112}],2},{xmpp_stream_in,send_pkt,[{file,"src/xmpp_stream_in.erl"},{line,1066}],2},{ejabberd_hooks,safe_apply,[{file,"src/ejabberd_hooks.erl"},{line,380}],4},{ejabberd_hooks,run_fold1,[{file,"src/ejabberd_hooks.erl"},{line,364}],4},{xmpp_stream_in,handle_info,[{file,"src/xmpp_stream_in.erl"},{line,388}],2},{gen_server,handle_msg,[{file,"gen_server.erl"},{line,599}],5}]}
** Arguments = [#{access => c2s,auth_module => ejabberd_auth_sql,conn => c2s_compressed_tls,ip => {{219,91,211,1

PS : I added response field to my sync record as well

Please show the complete spec: sync, sync_response and the record.

Ah, the reference is incorrect: you should use sync_response instead of sync_result.

btw, you don't need to write your record by hand, it's only needed if you have "underscore" label ($_) in your spec.

commented

This is final complete spec that i have written and is giving me the same error

-record(sync, {id = <<>> :: binary(),
               c = <<>> :: sync_type(),
               from :: undefined | jid:jid(),
               to :: undefined | jid:jid(),
               json :: <<>> :: binary(),
               result :: <<>> :: binary(),
               sub_els = [] :: [xmpp_element() | fxml:xmlel()]
               }).



-xml(sync_result,
     #elem{name = <<"result">>,
           xmlns = <<"a:c">>,
           result = '$cdata',
           cdata = #cdata{label = '$cdata'}}).

-xml(sync,
     #elem{name = <<"sync">>,
     xmlns =  [<<"a:c">>, <<"jabber:server">>,
               <<"jabber:component:accept">>],
     cdata = #cdata{label = '$json'},
     result = {sync, '$id','$c','$from', '$to', '$json', '$result', '$_els'},
     attrs = [ #attr{name = <<"id">>},
               #attr{name = <<"c">>,
                     default = <<"0">> },
               #attr{name = <<"from">>,
             	   		  dec = {dec_jid, []},
             		   	  enc = {enc_jid, []}},
               #attr{name = <<"to">>,
               			  dec = {dec_jid, []},
               			  enc = {enc_jid, []}}
             ],
     refs = [#ref{name = sync_result, label = '$result', default = <<"">>}]}).

  1. Remove record definition (it's not needed in your case as I pointed above), because it will be generated automatically.
  2. Add min/max attributes to the #ref{}:
#ref{name = sync_result, label = '$result', default = <<"">>, min = 0, max = 1}

Also remove 'jabber:server' and 'jabber:component:accept', because they have the same problem as 'jabber:client', i.e. just leave xmlns = <<"a:c">>.

I just checked, this spec works flawlessly for me:

-xml(sync_result,
     #elem{name = <<"result">>,
           xmlns = <<"a:c">>,
           result = '$cdata',
           cdata = #cdata{label = '$cdata'}}).

-xml(sync,
     #elem{name = <<"sync">>,
     xmlns =  <<"a:c">>,
     cdata = #cdata{label = '$json'},
     result = {sync, '$id','$c','$from', '$to', '$json', '$result', '$_els'},
     attrs = [ #attr{name = <<"id">>},
               #attr{name = <<"c">>,
                     default = <<"0">> },
               #attr{name = <<"from">>,
             	   		  dec = {dec_jid, []},
             		   	  enc = {enc_jid, []}},
               #attr{name = <<"to">>,
               			  dec = {dec_jid, []},
               			  enc = {enc_jid, []}}
             ],
     refs = [#ref{name = sync_result, label = '$result',
		  min = 0, max = 1, default = <<"">>}]}).
> xmpp:encode(#sync{result = <<"some json">>}).
#xmlel{name = <<"sync">>,
       attrs = [{<<"xmlns">>,<<"a:c">>}],
       children = [#xmlel{name = <<"result">>,attrs = [],
                          children = [{xmlcdata,<<"some json">>}]}]}
commented

min = 0, max = 1 adding this made it work .. what is the purpose of it ?

Thanks for the help I am good now you are the man @zinid :) thanks a lot. i spent almost 6 hours i getting this corrected

min = 0, max = 1 adding this made it work .. what is the purpose of it ?

This means exactly what it says: it restricts the element to allow only 0 or 1 subelement of this kind, i.e. only zero or single <result/> element is allowed in <sync/>. The default is to allow any number of <result/> elements, which is not your case from what I understand.

i spent almost 6 hours i getting this corrected

Next time don't spend hours of your life on this, just ask a question :)

commented

you all do so much of work for the community i thought ill try something before i ask ... and was not sure if it was an idiotic question. definitely I owe you a beer / beers :)