englercj / node-esl

FreeSWITCH ESL implementation for Node.js; implements the full Event Socket Library specified in: http://wiki.freeswitch.org/wiki/Esl

Home Page:http://englercj.github.com/node-esl/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

All event data is treated as headers

OscarF opened this issue · comments

When receiving an event it seems like all data, both headers and body is treated as body .

When listening to events (as json) it would make sense to receive them as an object with key: value. As of now you instead get all fields as headers.

{headers: {name: "field_name", value: "value"}}

The _body key is a special one the parser creates for non-json types; see here and here. I am pretty sure the json stream used _body which is why I chose that key for the other formats. Can you give me an example of a JSON event with body data? That will be the most help in ensuring it is parsing correctly, and I can add a test case to ensure it works going forward.

I don't want the esl.Event object to be different depending on the format of the stream; the library should normalize them all to exactly the same format in the object. That being said I am following the Freeswitch ESL spec which says to have getHeader and getBody methods.

I have no problem making the headers field of events being an object you can directly access instead of an array you need to use getters into (that would likely be faster anyway). I could probably do some smart parsing on body data as well to try and have actual javascript types for the value there. If I do those two items does it get you want you are asking for, or am I missing the point?

Sorry if I was unclear.
Here's an example

  conn.on("esl::event::CHANNEL_ANSWER::**", function (event, headers, body) {
    console.log(event);

gives (with some fields removed)

{ headers:
   [ { name: 'Event-Name', value: 'CHANNEL_ANSWER' },
     { name: 'Core-UUID', value: '2834376e-09bd-4581-abc6-6c84fd07aefd' },
     { name: 'Channel-State', value: 'CS_CONSUME_MEDIA' },
     { name: 'Channel-Call-State', value: 'RINGING' },
     { name: 'Unique-ID', value: '3ac38b16-c830-4e65-8723-68589a28264a' },
     { name: 'Channel-Call-UUID', value: '3ac38b16-c830-4e65-8723-68589a28264a' },
     { name: 'Answer-State', value: 'answered' },
     { name: 'Caller-Unique-ID', value: '3ac38b16-c830-4e65-8723-68589a28264a' },
  hPtr: null,
  type: 'CHANNEL_ANSWER',
  subclass: undefined,
  body: '' }

when the actual body is all the body fields in json and headers are

{ 'Content-Length': 5807, 'Content-Type': 'text/event-json' }

I agree it might make more sense to have the headers be in { headerName: 'headerValue' } format, I am confused on why the current format is a problem for you. You should be using getHeader(name) to get the value of a header anyway.

Is you issue that it looks strange when you log it? Or that a message is being parsed incorrectly? Are you trying to use the headers object in a way that the current array doesn't allow?

I just want to make sure I solve the right problem and not have to come back and revisit this again later :). Thanks for your patience!

All "fields" (like Caller-Unique-ID) are "body fields" and not "header fields". event.getBody() returns event.body which you can see is an empty string in the above paste.

Are the fields supposed to be parsed as a header and accessed with getHeader() even though they are formally sent as body by Freeswitch? Is it meant to be that all "fields" are accessed by key (using getHeader) and getBody gives raw text?

I think the only "real" headers are { 'Content-Length': 5807, 'Content-Type': 'text/event-json' }

@OscarF In that case I would need to see Freeswitch's raw output to see if the parser is parsing incorrectly. But those all are valid freeswitch headers. The two you mentioned are the only 2 that are HTTP headers, but the protocol that freeswitch is talking is not HTTP.

For example, here is a sample packet from FSW:

Via: SIP/2.0/UDP 99.157.44.194;rport;branch=z9hG4bKpH2DtBDcDtg0N
Max-Forwards: 70
From: <sip:1005@99.157.44.194>;tag=Dy3c6Q1y15v5S
To: <sip:1005@99.157.44.194>
Call-ID: 129d1446-0063-122c-15aa-001a923f6a0f
CSeq: 104766492 NOTIFY
Contact: <sip:mod_sofia@99.157.44.194:5060>
User-Agent: FreeSWITCH-mod_sofia/1.0.trunk-9578:9586
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, PRACK, MESSAGE, SUBSCRIBE, NOTIFY, REFER, UPDATE, REGISTER, INFO, PUBLISH
Supported: 100rel, timer, precondition, path, replaces
Event: check-sync
Allow-Events: talk, presence, dialog, call-info, sla, include-session-description, presence.winfo, message-summary
Subscription-State: terminated;timeout
Content-Type: application/simple-message-summary
Content-Length: 2

OK

The only thing that is "body" in that message is OK; every other line is a header. I can see your confusion if you are treating this protocol as HTTP, but it isn't; it is only "HTTP-like" in the format that it sends data.

Here is another example:

Content-Type: command/reply
Reply-Text: +OK Job-UUID: d8c7f660-37a6-4e73-9170-1a731c442148
Job-UUID: d8c7f660-37a6-4e73-9170-1a731c442148

In this case there is no body, only 3 headers.

This is only regarding events coming from the server.
https://github.com/englercj/node-esl/blob/master/lib/esl/parser.js#L154
Into that function comes the headers argument with content-type and content-length. And the body argument contains json with many different fields (Like event-name).

What the code does now is
https://github.com/englercj/node-esl/blob/master/lib/esl/parser.js#L161
where it sets data and then
https://github.com/englercj/node-esl/blob/master/lib/esl/parser.js#L179 where it doesn't pass a body to the event constructor effectively treating all fields as header fields.

Maybe it's just me thinking the wrong way. And maybe it's a better solution to have all fields with a key to be header fields. I just don't think that is very clear as FSW sends them as body.

Here's some example data
headers: { 'Content-Length': 5806, 'Content-Type': 'text/event-json' }
body {"Event-Name":"CHANNEL_ANSWER","Core-UUID":"55530fa2-171d-4fd6-bd83-5ca5e5c26f4b", ...}

When listening to events as json the data shown here (http://wiki.freeswitch.org/wiki/Event_List#CHANNEL_ANSWER) as key: value are received as a json string in the body

You are confusing "Packet Headers" and "Event Headers". For the example event you linked there are two packet headers (Content-Type and Content-Length) that describe the event packet. This is the tcp protocol that is HTTP-like. We read those headers that describe how we should parse the packet's body that follows (which is the entirety of the event).

The body of the packet has the event (which can have an event body). In the CHANNEL_ANSWER event there is a large list of event headers with no event body. It is clearer if you look at the event minimum information and look at the subheader example. Notice there is the two packet headers, and a list of event headers.

To further illustrate, here is an example of a full packet from FSW:

Content-Length: 625
Content-Type: text/event-plain

Job-UUID: 7f4db78a-17d7-11dd-b7a0-db4edd065621
Job-Command: originate
Job-Command-Arg: sofia/default/1005%20'%26park'
Event-Name: BACKGROUND_JOB
Core-UUID: 42bdf272-16e6-11dd-b7a0-db4edd065621
FreeSWITCH-Hostname: ser
FreeSWITCH-IPv4: 192.168.1.104
FreeSWITCH-IPv6: 127.0.0.1
Event-Date-Local: 2008-05-02%2007%3A37%3A03
Event-Date-GMT: Thu,%2001%20May%202008%2023%3A37%3A03%20GMT
Event-Date-timestamp: 1209685023894968
Event-Calling-File: mod_event_socket.c
Event-Calling-Function: api_exec
Event-Calling-Line-Number: 609
Content-Length: 41

+OK 7f4de4bc-17d7-11dd-b7a0-db4edd065621

You can see the packet headers above describe the size of the event data, followed by the event headers that describe the event (including another Content-Length event header to describe the event's body size), followed by the body content.

What you get when accessing the headers in an esl.Event object is the event headers. Hope this clears up any confusion!

EDIT The reason the parser may look like it is doing more work than is necesarry if the above is true, it is because it is! I wrote the parser to support the case of blank and strangely formed packets (since I got those on certain old versions of FSW). But I try to normalize both cases to have all event headers and event body properly parsed int he esl.Event object.

Now I understand. Thanks for explaining and sorry for any confusion caused.

No problem, just wanted to make sure we explored the issue and that the library is handling all cases.

I also remembered why I used an array of header objects instead of an object with key-values for headers. The spec defines an interface to iterate headers, and putting them in an array was the best way to accomplish that.