The BACKEND -=-=-=-=-=- Structure ========= The backend consists of very few python files: * backend.py * configlets.py * cfg_*.py * language.py * cdrutils.py * manager.py backend.py ---------- This is the wizard-of-all. It's tasks are: * read in all Configlets that are in ./cfg_*.py. Configlets are things that you can configure and that can create Asterisk configuration. * read in the current configuration, first from /etc/asterisk/destar_cfg.py and, if this file does not exist, from ./destar_cfg.py * provide query interfaces to the frontend where the Frontend can ask for "Give me all configlets that define external line" or "Give me all currently defined SIP phones". configlets.py ------------- This files contains base classes for all configlets to inherit from. It also contains the AsteriskConfigFile class, a class that is very handy to store an in-memory representation of a an Asterisk config file. Configlets can get a handle to an individual config file via the AstConf() function and append or prepend data. Once that is done, we can call the write() method and write out a newly created Asterisk config file. And this config file might then contain entries that 20 or more configlets placed into it. Configlets can't 'import backend' because the backend import them, so we have to have some backend functions in this file ... cfg_*.py -------- Each one of this files contain one configlets. Any file that has the form cfg_*.py will be imported. So you can put your own files into this directory. A configlet has these properties: * It can store data - this data ends up in destar_cfg.py and can be used in the createAsteriskConfiglet() method * and is a descendand from the Cfg class * the data that it can store is described in variables[] - this variable description is used by the frontend to auto-generate form * it has a 'shortName' and a 'group', it can also have a 'description' - this info is used by the frontend to generate menus and to decorate the form * it can have head() and repr() methods - those methods are used by the frontend when it has to generate tables. Many configlets doesn't have those methods but inherit them from their base class. * it has a createAsteriskConfiglet() method that modifies the in-memory representation of an Asterisk config file cdrutils.py =========== This backend module contains code to access the cdr_sqlite3_custom.so made call data record database. manager.py ========== This contains the interface to the Asterisk Manager. Example ======= Grey is all theory. Let's get dirty. Look at destar_cfg.py and search for 'Rtp'. You see something like this: CfgOptRtp( rtpstart = 16000, rtpend = 17000, ) Now look at cfg_opt_rtp.py. You'll see: # -*- coding: iso-latin-1 -*- from configlets import * from language import _ This the usual boilerplate of all configlets. They import everything from configlets.py. And they import a silly translation function _() from language.py. class CfgOptRtp(CfgOptSingle): Our configlet for the RTP Options inherit from CfgOptSingle. That has some code to make sure that only one single CfgOptRtp object can be instantiated. All other base classes (CfgApp, CfgLine, CfgPhone, CfgPerm, CfgOpt) allow more than one object instantiation. shortName = _("RTP options") This is the name of this configlet that will be displayed by the frontend. It is a translatable string, as can be seen by the _() idiom. variables = [VarType("rtpstart", type="int", title=_("Start of RTP port area") default=15000), VarType("rtpend", type="int", title=_("End of RTP port area"), default=17000)] This is an array with VarType() object instantiations. Each VarType stands for one object attribute. It defines * name * type (defaults to 'string') * len (defaults to '60') * title * hint * optional (default to False) * default (a default value) * hide These fields will later generate an menu in the frontend that has this format: title: _value-or-default_______ hint In our case, it will be: Start of RTP port area: _15000____ End of RTP port area: _17000____ Now, assume we filled out this form and submit it. When we have self.rtpstart and self.rtpend. Now, what do we do with those values? We write them into the asterisk config file: def createAsteriskConfiglet(self): c = AstConf("rtp.conf") c.appendValue(self, "rtpstart") c.appendValue(self, "rtpend") Handling Asterisk config files ============================== class AsteriskConfigFile and AstConf() The class contains an in-memory representation of an asterisk configuration file. The function is factory method for the class. It also returns the same class instance for a given config file name. This allows one to call, say, c = AstConf("extensions.conf") from several places and always get a reference to the same file. There are various methods in the class to add new lines to the config files, see the docstrings in the class. When you call the backend.createAsteriskConfig() method something will get written. Data files ========== destar_cfg.py ------------- This file is both a data file and source code. It is a data file because it is generated by a program and contains data about all configured items. It is source source because I use the python interpreter to read the file. It is imported into the name space of backend.py via "execfile()", not via "import" backend.createPythonConfig() writes this file.