Skip to content
blak3r edited this page Dec 11, 2012 · 27 revisions

There are a lot of things that could be done to improve this project... Most of which don't really learning any of the domain specific Asterisk backend stuff. Would love to collaborate with people on this project and make it even better. So, any help would be greatly appreciated. Don't be shy about editing this page or any of the documentation for that matter. That's the part many of us like least!

I'll happily expand and give guidance on how to best implement features. Best way is to create an enhancement issue and i'll chime in with more details on it.

Table of Contents

Features

  • Have Button to create a new contact when inbound number isn't recognized... (Add to contact--> create new or add to existing) == basically done... probably should get an icon instead of using text.
  • Have ability to assign a call to a contact but not change add phone to the contact. For example, when you join a conference call... you need to be able to assign the call to the contact but can't do it automatically since conf. call number may be generic. -- I added code to make popup appear... but have no way of detecting the popup window was closed. You can't do an onchange on the form input fields it sets. onchange doesn't work when changed programatically...
  • Have ability to "Add to Existing Contact", allow user to click a button, select the contact and then select which phone to add it to. The UI for selecting the contact would be same as above. Prompting the user to select which phone field to add it to is less cookie cutter.
  • Add Icons for things like "Create Meeting"... etc. Internally at my company we use Sugar PRO which has quick select icons across the top so i'm not planning on adding these. But, it's been a highly requested feature.
  • Update language files for german and whatever the other language is.
  • Add Transfer Support (See Enhancements in Issues).

Minor Bugs

  • $sugar_config['asterisk_dialin_ext_match'] = 'Local\/(?:.*?)(\d\d\d?\d?\d?)@'; -- Make this take 3-11 digits. If longer then say 5 characters we need to implement a method to look at users's mobile phones.
  • See issues for bug on RingGroups

New Features Ideas

  • Add lead support (currently only contacts are matched).
  • Better handling for answering on mobile phone through a ring group. Call window appears, but when call is ended call popup will always say connected.
  • Would be cool if we displayed voicemail inside sugar. From what i've read this sounds doable given the options in AMI.
  • Make a "Call Controller" like window that would show the status of every current call in the system. It'd serve as a "presence" app as well. This would probably only be feasible for small implementations though.

Call Recording Support

  • Ability to record the call... I seems this is possible to do through AMI, so probably could hook it in to asteriskLogger and not need to create a custom dial command. http://www.voip-info.org/wiki/view/Asterisk+Manager+API+Action+Monitor.
  • Ideally I think we'd want to have a user setting for call recording preference... Ideally, we'd have AMI start the recording automatically when call starts and if by the end of the call the user presses the record button on the UI it'd retrieve it and add it to the call.
  • Where do we store the recordings? Do we leave them on the asterisk box or do we have to transfer them to sugar. (i'm guessing we'd have to transfer it to sugar or we'd have to expose files to the world.)

SugarCRM Architecture Improvements

Original plugin was developed in the sugar v4.5 days. A lot of effort has gone into modernizing it and making it upgrade safe but it's still has some rough edges. If you have any experience with developing for sugarcrm these would be a great way to help the project. These include:

Module Loader / Package

  • Fields are added to User, but user needs to go into studio to then add them to template. (This is fine in 6.4 since Users are now "Studioable". Users who are using older versions of Sugar have to manually merge the user fields. This is discussed in more detail in the installation steps. __ Update: this is very low priority it seems that 90% of the users of this module are using it in 6.5 and up, so no reason to support older versions of Sugar__

Performance Improvements

I suspect as larger companies start using this plugin... Performance issues may crop up.

Issue 1: Optimize callListener.php

The CallListener.php class is called by every active browser tab that each user has open about every 2-5 seconds (depending on the AJAX poll rate you configured). That means if you had 10 users logged into sugar, each with 3 browser tabs open, and a poll rate of 2000ms. That's 30 requests/2 minutes --> 15 requests per second. Each of those requests is going to require at least one DB query. Therefore, making callListener.php return as quickly as possible is important for scalability.

      1. Summary of methods to optimize...
Before we can really optimize callListener queries we need to have a better sense of where the bottleneck is for most organizations.

As it stands, the worst case performance happens when you have someone who calls in on a certain extension and the phone number doesn't match any contact/account. When this occurs, we do the "expensive" phone number lookup query which uses regex's to find search the entire contacts table for matching phone numbers. Once a particular contact is found we save the contact id so it's not continuously looked for. It's unclear whether or not mysql query cache effectively makes this a non issue or not. If our phone number search query is being cached (not really sure if it does or not)... then this shouldn't be that big of a performance hit. Sure, some people might not have mysql query cache enabled... but if they have a lot of users hitting their CRM without any query cache they kinda need to invest some resources in optimizing their CRM performance anyway.

Lets back up a step... in call listener there are two queries which happen.

1. QUERY #1 - Fetches all the calls for a given users extension that haven't been closed by user and have happened within the last 60 minutes. 2. QUERY #2 - For each call returned in #1 we then look to find any contacts in the CRM that match the phone number for the given call record.

Therefore, query 1 is happening a LOT more then query #2. Furthermore query 2 only happens once per call record if we are able to find a single matching contact in the CRM. (In my business... people that call us are generally already a contact... so this doesn't happen as much.)

        1. Methods for speeding up Query #1
As outlined above there are some pretty good solutions for speeding up query #1. Namely we just need to extract the user extension in asteriskLogger and put that into a column which is indexed. That'll speed up query number 1 signifigantly. Alternatively, we should just delete any entries in the asteriskLog that are older then say 2 hours... this would keep the table size pretty small so that a full table scan wouldn't matter.

EDIT: Some ideas for improving performance are discussed here. Only psuedocode is provided thus far: https://github.com/blak3r/yaai/commit/6e24e2df62ade78c2135ff8756952761faa0c452#commitcomment-1472245

EDIT2: More ideas for indexing asterisk_log and adding a new column for storing the extension in asterisk_log so that we don't have to use LIKE queries are here: https://github.com/blak3r/yaai/issues/47

        1. Methods for speeding up Query #2
1. Create a new database table which stores all the phone numbers in the CRM in a standard format. This would allow us to eliminate the LIKEs in the query. This would make the query fast.

2. Use memcache and start caching query reaults on a key based on extention+phone num. or something like for 10s. Or perhaps remove all cached entries whenever a new contact bean is created. This approach is fairly complicated and again we still don't know if memcached would be better then mysql query cache... and finally... not all users have memcached as an option.

3. Change UI so when user clicks the new contact button it somehow gets the ID of the new contact. Not sure how that could be done.... or perhaps upon clicking save memo we research for a related contact. This of course wouldn't work if they saved the memo before saving the new contact.

4. Option 4 stop polling and use we sockets and push updates to clients. Not really sure how that would work.

        1. Other Thoughts
You might ask... why not just do all the contact relation once in asteriskLogger instead of doing it in callListener? The reason we can't do that is for the case where a new person calls in... and a contact is created for that caller during the call. User will expect the callPopup to update and will expect that if they save the call notes it gets related to that new user. If we do it all in asteriskLogger, you could do the lookup at the start and end of call... but many times people don't actually save the contact record until after the call is over. Hence why we need to do it in callListener.

Issue 2: Looking for matching contact based on phone number requires a full table scan

The other area which could be a big problem for people with very large databases is the phone number lookup. The way this is implemented uses either REGEX (in asterisk logger) or Replace statements (callListener). As a result I'm told this requires a full table scan to find matching contacts for a phone number. In general this shouldn't happen too often (only once a call in most cases)... but if you have 100,000 contacts then this might be of greater concern.

The reason table scan is necessary is because phone numbers aren't stored in the database in a standard format. As a result when you write a query you need to remove punctuation from the values in the database before comparing. So, in order to fix this we either a) Need to enforce a particular database storage format of phone numbers. (I think i've seen a plugin for sugar that does this already) b) Need to create a custom field for each phone_work, phone_mobile, etc that stores a version of the phone number without anything punctuation in it and then rewrite the queries to go against it.

Other

Originally, this plugin continued to make AJAX calls even after the user session died (like when you login on a different computer)... I changed the code to only schedule subsequent ajax calls when the previous call returns successful. This will work from a performance standpoint but if there is ever a case where a single request fails for a legit reason... the call popup will not appear until user refreshes their page. I think this is an acceptable tradeoff. I'm just documenting it here in case the call popups seem to be sporatically failing.

Configuration Changes Needed

We need a better way to manage system configuration settings. It's such a chore to do so I put it off. See architecture section.

  • Add gravatar one
  • Add opencnam enabled / apikey
  • Add option for what to do with very short inbound calls (ie inbound calls that weren't answered). Set status to "Missed" (which shows up in activities as open task) or Held (shows up in history).
  • Need configurable Channel detection in order to assign calls to users when they answer on cell phones.
  • Add a configurable option for how long to display call popups before they hide automatically. (Default is 1 hour)
  • Add a config option to disable including jquery (workaround to jquery issue).
  • (DONE) Need to add dialin prefix (its in sugarListener)
  • (DONE) Need to make config option for the dialout. Currently hardcoded to /SIP (in my case i need to do the Local/##@sugarsip/n... see CreateCall... for some reason I don't need it in callListener (presumably b/c it's already SIP at that point).
  • (DONE) Parametize the channel --> assigned user id detection, search for Local/LC-52@from-internal-4bbbb in asteriskLogger.
  • (DONE) Add max subject length to controller.php (also variables for IBC, OBC);

MISC

  • Verify Asterisk Logger fix to relogin to AMI works if asterisk goes down.
  • (DONE) Currently language is hardcoded in sugarListener.php
  • (DONE) AsteriskLogger -> findUser method --> add to query something to detect that user is "Active" so you don't get past employees matchin.
  • Process the AMI response in CallCreate / controller and display errors when they fail in javascript.
  • If the database cannot be accessed, this is the error message you get
! FATAL: Cannot find login credentials for user admin which is a bit misleading... as it makes you think soap is the problem

Asterisk Logger Issues

Stability

Don't know what conditions occur which cause it to lock up... But, occassionally asterisk logger will lock up. So, for production systems it's good to restart the script daily. In my commit around 4/12 I added some code which makes it relogin to AMI after 30 consecutive timeouts or errors. I'm hoping this will keep it from locking up indefinitely. There seems to be no easy way to check the status of a socket.
UPDATE 5/7/2012: Still hasn't locked up on me.
UPDATE 7/30/2012: Service has now been running for 3 months straight... so I'd say this issue is resolved now.

Run as a Service

Also, I did some cursory research on how to make it run as a windows service. Couple good solutions here: Please post back if you find one. http://stackoverflow.com/questions/5952500/setting-a-php-script-as-a-windows-service. Please post back with what works.

On linux this much easier. See the utils folder included in the module for a sample script.

JQUERY Include or Not To Include on Page Problem Notes =

In my production system, I have 6.4.1. I have an extension which uses JQUERY already (1.4 something)...

In AsteriskJS.php if I force include: echo '<script type="text/javascript" src="custom/include/javascript/jquery/jquery.pack.js"></script>'; Asterisk Plugin works fine... But, my Dispage plugins fail. If I remove it so that the asterisk plugin doesn't include jquery, everything is fine.

This then of course will not work for people who don't already have jquery loaded.

On my demo 6.4 instance (I don't have any other extensions so jquery isn't loaded).

My conditional include solution I found on stackoverflow adds the script tag to the end of head. But, the code that is adding the code is in the body. (Where the after_ui_frame javascript is loaded)

As a result, I get Uncaught ReferenceError: $ is not defined

Experimented with surrounding my jquery wth some YUI code... but didn't have too much luck. I tried: YAHOO.util.Event.onDomReady --> nothing happened YAHOO.util.Event.onContentReady --> Uncaught ReferenceError: jQuery is not defined

```So, for now the workaround is... by default we include jquery and the user can go in and comment it out if they run into problems.```

UPDATE: At sugarcon it was recommended that we replace the jquery ready method with Sugar.Util.doWhen("jquery != undefined", I haven't tried it yet to see if that works.

http://forums.sugarcrm.com/f6/conditionally-include-jquery-if-other-plugins-already-havent-79391/#post277003