Rick Guyton Posted December 18, 2019 Report Posted December 18, 2019 I'm developing a reporting app and as part of it, I have two "agent" servers connecting to my Kazoo API using websockets and listening to events. They each listen for 30 minutes before closing and relaunching. "agent 1" starts on every 0 and 30 minute and "agent 2" starts on every 15 and 45 minute of the hour. This way, I have some redundancy. This obviously leaves me with duplicate messages though and I need a way to de-dup them. I have been using the routing key and this worked really well until I tried to do reporting on call hold time when the calls were held/unheld multiple times in a session. I've looked further into it and it seems like the key I should have been pulling is msg_id. But, before I invest the time to re-write my code to use this key to de-dup my messages, I want to be sure this would work as expected. Where you at @mc_? 😀
FASTDEVICE Posted December 18, 2019 Report Posted December 18, 2019 @Rick Guyton tangential question. Does websockets report the hold status from Konami, the device (SIP re-invite), or both?
Rick Guyton Posted December 18, 2019 Author Report Posted December 18, 2019 (edited) @FASTDEVICE Neither? AFAIK connecting to WS is equivalent to listening to the AQMP. So effectively you are seeing ecallmgr internally reporting to kazoo apps that a hold event has occurred after freeswitch told it so. I'm not 100% sure about that TBH. But, here's an example of a hold straight off the wire if it helps (censored like crazy obviously) {"action": "event", "subscribed_key": "call.*.*", "subscription_key": "call.MY_ACCOUNT_ID_HERE.CHANNEL_HOLD.*", "name": "CHANNEL_HOLD", "routing_key": "call.MY_ACCOUNT_ID_HERE.CHANNEL_HOLD.CALL_ID_HERE", "data": {"to_tag": "NOT_SURE_IF_THIS_IS_SENSITIVE", "timestamp": 63743922729, "switch_url": "sip:mod_sofia@SOME_IP:11000", "switch_uri": "sip:SOME_IP:11000", "switch_nodename": "freeswitch@fs003.ord.p.zswitch.net", "switch_hostname": "fs003.ord.p.zswitch.net", "presence_id": "MY_EXT@MY_REALM", "other_leg_direction": "inbound", "other_leg_destination_number": "+MY_PHONE_NUM", "other_leg_caller_id_number": "+MY_CELL_PHONE_NUM", "other_leg_caller_id_name": "Rich Guyton Iii", "other_leg_call_id": "OTHER_CALL_LED_ID", "media_server": "fs003.ord.p.zswitch.net", "from_tag": "NOT_SURE_IF_THIS_IS_SENSITIVE", "disposition": "ANSWER", "custom_sip_headers": {"x_kazoo_invite_format": "contact", "x_kazoo_aor": "sip:MY_USER_NAME@MY_REALM"}, "custom_channel_vars": {"account_id": "MY_ACCOUNT_ID_HERE", "authorizing_id": "NOT_SURE_IF_THIS_IS_SENSITIVE", "authorizing_type": "device", "bridge_id": "OTHER_CALL_LED_ID", "call_interaction_id": "INTERACTION_ID", "channel_authorized": "true", "ecallmgr_node": "ecallmgr@apps002.ord.p.zswitch.net", "global_resource": "false", "inception": "+MY_PHONE_NUM@SOME_IP", "owner_id": "MY_OWNER_ID", "realm": "MY_REALM", "username": "MY_USER_NAME"}, "custom_application_vars": {}, "channel_state": "EXCHANGE_MEDIA", "channel_name": "sofia/sipinterface_1/MY_USER_NAME@MY_REALM", "channel_created_time": 1576703524752278, "channel_call_state": "HELD", "caller_id_number": "+MY_CELL_PHONE_NUM", "caller_id_name": "CleaRing - Rich Guyton Iii", "callee_id_number": "+MY_PHONE_NUM", "callee_id_name": "CleaRing", "call_direction": "outbound", "call_id": "CALL_ID_HERE", "msg_id": "NOT_SURE_IF_THIS_IS_SENSITIVE", "event_name": "CHANNEL_HOLD", "event_category": "call_event", "app_version": "4.0.0", "app_name": "ecallmgr"}} Edited December 18, 2019 by Rick Guyton (see edit history)
Administrators mc_ Posted December 18, 2019 Administrators Report Posted December 18, 2019 I believe msg_id for call events is the timestamp from FreeSWITCH, at least in 4.3. So presumably msg_id + event_name should be "unique"?
Rick Guyton Posted December 18, 2019 Author Report Posted December 18, 2019 Just now, mc_ said: I believe msg_id for call events is the timestamp from FreeSWITCH, at least in 4.3. So presumably msg_id + event_name should be "unique"? I'll concat msg_id and the routing key just to be safe. That'll do it I think. Thanks a bunch @mc_!
FASTDEVICE Posted December 19, 2019 Report Posted December 19, 2019 @Rick Guyton was that event initiated by pressing the hold button on a device i.e. Yealink/ Polycom IP phone, or programmatically from the Operator Console Pro UI? I'm trying to detect when a user places a caller on hold from the IP phone directly.
Rick Guyton Posted December 19, 2019 Author Report Posted December 19, 2019 (edited) 11 minutes ago, FASTDEVICE said: @Rick Guyton was that event initiated by pressing the hold button on a device i.e. Yealink/ Polycom IP phone, or programmatically from the Operator Console Pro UI? I'm trying to detect when a user places a caller on hold from the IP phone directly. So, you are listening on the AQMP. So regardless of the origin, it should come up. Are you looking to verify that this is the case? Or are you trying to differentiate between hold on Op Console vs physical phone holds? EDIT: my example was done on a physical phone Edited December 19, 2019 by Rick Guyton (see edit history)
FASTDEVICE Posted December 19, 2019 Report Posted December 19, 2019 I'm trying to confirm that physical phone holds are creating hold events in websockets. There is no equivalent in Webhooks so I need to move to Websockets. I was planning to test it out over the weekend and your question seemed very timely. Thanks for confirming!
Rick Guyton Posted December 19, 2019 Author Report Posted December 19, 2019 2 minutes ago, FASTDEVICE said: I'm trying to confirm that physical phone holds are creating hold events in websockets. There is no equivalent in Webhooks so I need to move to Websockets. I was planning to test it out over the weekend and your question seemed very timely. Thanks for confirming! NP, if you haven't started on the websocket code code yet and python is acceptable to you, you might want to wait a bit before diving in. 😉
FASTDEVICE Posted December 19, 2019 Report Posted December 19, 2019 Are you building a WS client in python? If so, is it standalone? We use Laravel/ PHP for our app development and Lumen for microservices.
Rick Guyton Posted December 19, 2019 Author Report Posted December 19, 2019 5 minutes ago, FASTDEVICE said: Are you building a WS client in python? If so, is it standalone? We use Laravel/ PHP for our app development and Lumen for microservices. I've got an agent in python that connects, subscribes to one or more accounts (and sub-accounts), records events and dumps them out to a file. It then uploads to backblaze storage for processing by another agent. I'll be open sourcing that part for sure most likely before the end of the year. If you could use that, I'd hate for you to duplicate your efforts.
Rick Guyton Posted December 19, 2019 Author Report Posted December 19, 2019 (edited) Hey @mc_, do you know what "from_tag" is? This also seems to be unique across different hold events. Also, seems like you are right, the msg_id does appear to be a timestamp Edited December 19, 2019 by Rick Guyton (see edit history)
Administrators mc_ Posted December 19, 2019 Administrators Report Posted December 19, 2019 This guy's blog is great in general for SIP stuff but specifically https://andrewjprokop.wordpress.com/2013/09/23/lets-play-sip-tag/
Rick Guyton Posted December 19, 2019 Author Report Posted December 19, 2019 13 minutes ago, mc_ said: This guy's blog is great in general for SIP stuff but specifically https://andrewjprokop.wordpress.com/2013/09/23/lets-play-sip-tag/ Awesome as always @mc_ thanks! I'm going to concat all the things!!!
Rick Guyton Posted December 19, 2019 Author Report Posted December 19, 2019 21 minutes ago, Rick Guyton said: Awesome as always @mc_ thanks! I'm going to concat all the things!!! Ugh, just in case anyone is following along... from_tag and to_tag eventually stay the same. It differs between hold/unhold #1 and hold/unhold #2. But, not thereafter. I'll be using both msg_id and timestamp to de-dup with. This leaves open the possibility that if someone managed to hold/unhold/hold again within 1 second that it'd throw off my stats. But, I feel like that'd be getting pretty edge case. I think AQMP had internal IDs it'd be nice to get at least a hash of AQMP's internal ID to de-dup with. But, this is the best there is for the moment as far as I can see.
Rick Guyton Posted December 19, 2019 Author Report Posted December 19, 2019 5 hours ago, Rick Guyton said: Ugh, just in case anyone is following along... from_tag and to_tag eventually stay the same. It differs between hold/unhold #1 and hold/unhold #2. But, not thereafter. I'll be using both msg_id and timestamp to de-dup with. This leaves open the possibility that if someone managed to hold/unhold/hold again within 1 second that it'd throw off my stats. But, I feel like that'd be getting pretty edge case. I think AQMP had internal IDs it'd be nice to get at least a hash of AQMP's internal ID to de-dup with. But, this is the best there is for the moment as far as I can see. Ok, last update and I'm leaving this be. The timestamp in the msg_id is down to the microsecond. So, I really don't need the seperate timestamp field on top of it. Messages can be de-duped with routing key + msg_id
Recommended Posts