Pro Tip - Using Shell & Curl in Dial plans

I see a lot of people solving curl requests via additional scripts.

Typical use case goes something like:

“I need a call context to go get some information, set the result as a variable, and use the variable or argument in my next step.” Knee-jerk reaction is “hey, I can make a script for that and I know how to call a script via dial plan, problem solved!”

Yes, problem solved but not efficiently. Multiple steps makes for more points of failure, in my opinion. Especially if you’re not the only “hands in the pot”.

I’ll use an example of something gaining popularity at the moment, Jitsi meet. For those creating a PBX back-end solution, Asterisk needs to CURL an API in order to retrieve a conference room name. Part of the result is then added as a SIP Header.

API URL: https://jitsi-api.jitsi.net/conferenceMapper?id=YOUR-PIN-HERE

Sending a CURL request with a valid pin (1234567890):

curl --silent https://jitsi-api.jitsi.net/conferenceMapper?id=1234567890

Returns:

{"message":"Successfully retrieved conference mapping","id":1234567890,"conference":"[email protected]"}

It would be nice if we needed the entire string, but the SIP Header should only contain the room name. In this case, “teammeeting”.

This is where folks try to solution with a script to cut down to the desired info, but it can be done easier all in one Dial plan line.

The terminal version of extracting “teammeeting” would be:

curl --silent https://jitsi-api.jitsi.net/conferenceMapper?id=${confid} | sed -e 's/.*"conference":"\(.*\)@.*/\1/'

Key operator being that we added a stream editor command to read the curl result string and trim out what we want.

The SED example below looks for "conference":" , removes it and everything before it. Then, looks for @ removing @ and everything after it

sed -e 's/.*"conference":"\(.*\)@.*/\1/'

Wrapping this up in an Asterisk Dial plan looks something like this:

exten => s,n,Set(CURL_RESULT=${SHELL(curl --silent https://jitsi-api.jitsi.net/conferenceMapper?id=${confid} | sed -e 's/.*"conference":"\(.*\)@.*/\1/')})
exten => s,n,Verbose(0, ${CURL_RESULT});

In the Dial plan line , we’ve obtained the PIN in a previous step, being injected as ${confid}.

Reading an asterisk log would print out the desired ${CURL_RESULT} as “teammeeting”, which is what we needed. No scripts, all one line.

3 Likes

A few things I would do differently. Instead of ‘sed’ I would just use ‘jq’. jq is a json parser for shell scripts. Although it’s not on most systems by default. To get the value of conference, you would just do something like the following:

jq -r '.conference'

Also, If I remember correctly, I think Asterisk natively supports curl and json.

I found this article explaining you can do this purely in dial-plan and the parse the json with an actual json parser! https://marcelog.github.io/articles/asterisk_json_curl_dialplan.html

2 Likes

Thanks for the tip!

I agree jq is useful for returning a key value. I think people need to be aware there’s a little more work involved in that though.

invoking jq as per the recommendation below:

jq -r '.conference'

Would return the entire “Conference” key value:

[email protected]

However, we only want part of the value:

teammeeting

Little more work needed there, but the tip is very much appreciated. Thanks!

Try

jq -r '.conference'| split("@")[0])

Regaurding jq, I had the same thought, but returns:

syntax error near unexpected token `('

If you want a live example to play with, try the line below. It will return “[email protected]” , but for this exercise we only want “wonderingpumpkinsrunfast”.

https://jitsi-api.jitsi.net/conferenceMapper?id=3049235710

Move the single tick quote:
jq -r '.conference | split("@")[0])'

The output could be piped into the dialplan function CUT to get the part before the @:

> core show function CUT

  -= Info about function 'CUT' =- 

[Synopsis]
Slices and dices strings, based upon a named delimiter. 

[Description]
Cut out information from a string (<varname>), based upon a named delimiter.

[Syntax]
CUT(varname,char-delim,range-spec)

[Arguments]
varname
    Variable you want cut
char-delim
    Delimiter, defaults to '-'
range-spec
    Number of the field you want (1-based offset), may also be specified as a
    range (with '-') or group of ranges and fields (with '&')

leading to something even more unsightly (but that’s what you get with dialplan)

exten => s,n,Set(CURL_RESULT=${CUT(SHELL(curl... ),@,1)})

equivalent of the shell command cut -f 1 -d '@' receiving piped input from jq

curl -s   https://jitsi-api.jitsi.net/conferenceMapper\?id\=3049235710 |jq -r  '.conference|split("@")|.[0]'

@dicko & @jerrm

Nicely done! Thanks for contributing a full jq solution :slight_smile:

curl -s   https://jitsi-api.jitsi.net/conferenceMapper\?id\=3049235710 |jq -r  '.conference|split("@")|.[0]'

@jerrm - you came to a similar method, just needed to remove the last parenthesis resulting in:

curl --silent https://jitsi-api.jitsi.net/conferenceMapper?id=3049235710 | jq -r '.conference | split("@")[0]'

Great tip!
Now that we have shell curl with sed and jq, I’d love to see a full Asterisk Curl() solution without a shell call :slight_smile:

You will find results if you google, but there is no native Asterisk function(s) for parsing json. I think the above is probably is as neat as its going to get.

Thanks for the feedback on the json parsing

My post was not meant to be passive aggressive, my intent was to point out that if one googles for ‘Asterisk JSON’ you will find hits that reference non-native diaplan functions provided by a third party library. I’m not aware of ‘stock’ dialplan functions that can parse json easily.

Thanks for clarifying :slight_smile:

1 Like

Challenge accepted:

exten => s,n,Set(CURL_RESULT=$["${REPLACE(CURL(https://jitsi-api.jitsi.net/conferenceMapper?id=${confid}),\",')}"=~"'conference':'(.*)@"])
2 Likes

That is truly awesome! I was trying to see If I could beat someone to it, but you were too quick. Thanks :wink:

This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.