BlinkenArea - GitList
Repositories
Blog
Wiki
Blinker
Code
Commits
Branches
Tags
Search
Tree:
170612a
Branches
Tags
master
Blinker
src
noarch
OpSplitter.cpp
limit number of connections for OpPrinter
Stefan Schuermans
commited
170612a
at 2011-12-23 13:54:52
OpSplitter.cpp
Blame
History
Raw
/* Blinker Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #include <map> #include <string> #include "Directory.h" #include "File.h" #include "ListTracker.h" #include "ListTracker_impl.h" #include "Mgrs.h" #include "Module.h" #include "NameFile.h" #include "OpConn.h" #include "OpConnIf.h" #include "OpMgr.h" #include "OpSplitter.h" #include "OpSplitterExtension.h" #include "SettingFile.h" #include "Time.h" #include "TimeCallee.h" #include "UIntFile.h" namespace Blinker { /** * @brief constructor * @param[in] name module name * @param[in] mgrs managers * @param[in] dirBase base directory */ OpSplitter::OpSplitter(const std::string &name, Mgrs &mgrs, const Directory &dirBase): Module(name, mgrs, dirBase), m_fileSound(dirBase.getFile("sound")), m_fileMaxConn(dirBase.getFile("maxconn")), m_extListTracker(*this, dirBase.getSubdir("extensions")) { // load extensions m_extListTracker.init(); // open operator connection interface m_mgrs.m_opMgr.open(m_name, this); } /// virtual destructor OpSplitter::~OpSplitter() { // close operator connection interface m_mgrs.m_opMgr.close(m_name); // close all connections while (!m_mapLocal.empty()) { MapLocal::iterator it = m_mapLocal.begin(); it->first->close(); m_mapLocal.erase(it); } while (!m_mapInOut.empty()) { MapInOut::iterator it = m_mapInOut.begin(); it->first->close(); m_mapInOut.erase(it); } while (!m_mapOutIn.empty()) { MapOutIn::iterator it = m_mapOutIn.begin(); it->first->close(); m_mapOutIn.erase(it); } // unload extensions m_extListTracker.clear(); // cancel time callback m_mgrs.m_callMgr.cancelTimeCall(this); } /// check for update of configuration void OpSplitter::updateConfig() { // sound name file was modified -> re-read sound name if (m_fileSound.checkModified()) m_fileSound.update(); // max. number of conn. file was modified -> re-read max. number of conn. if (m_fileMaxConn.checkModified()) m_fileMaxConn.update(); // extensions update m_extListTracker.updateConfig(); } /// callback when requested time reached void OpSplitter::timeCall() { // send sound play request on marked local operator connection for (MapLocal::iterator it = m_mapLocal.begin(); it != m_mapLocal.end(); ++it) { if (it->second.m_sendPlay) { it->second.m_sendPlay = false; if (m_fileSound.m_valid) it->first->sendPlay(m_fileSound.m_obj.m_str); } } } /** * @brief check if accepting new operator connction is possible * @param[in] name operator interface name * @return if accepting new connection is possible */ bool OpSplitter::acceptNewOpConn(const std::string &name) { // if maximum number of connections if limited, check it if (m_fileMaxConn.m_valid && m_mapLocal.size() + m_mapInOut.size() >= m_fileMaxConn.m_obj.m_uint) return false; // too many connection return true; (void)name; // unused } /** * @brief new operator connection * @param[in] name operator interface name * @param[in] pConn operator connection object * * The new connection may not yet be used for sending inside this callback. */ void OpSplitter::newOpConn(const std::string &name, OpConn *pConn) { // this is a new incoming connection -> make it a local connection newLocal(pConn); (void)name; // unused } /** * @brief key command received on operator connection * @param[in] pConn operator connection object * @param[in] key key that was pressed */ void OpSplitter::opConnRecvKey(OpConn *pConn, char key) { // local connection -> process MapLocal::iterator itLocal = m_mapLocal.find(pConn); if (itLocal != m_mapLocal.end()) { localKey(itLocal, key); return; } // incoming to outgoing connection -> forward MapInOut::iterator itInOut = m_mapInOut.find(pConn); if (itInOut != m_mapInOut.end()) { itInOut->second->sendKey(key); return; } // outgoing to incoming connection -> forward MapOutIn::iterator itOutIn = m_mapOutIn.find(pConn); if (itOutIn != m_mapOutIn.end()) { itOutIn->second->sendKey(key); return; } } /** * @brief play command received on operator connection * @param[in] pConn operator connection object * @param[in] sound name of sound to play */ void OpSplitter::opConnRecvPlay(OpConn *pConn, const std::string &sound) { // play command does not make sense for local connections -> ignore // incoming to outgoing connection -> forward MapInOut::iterator itInOut = m_mapInOut.find(pConn); if (itInOut != m_mapInOut.end()) { itInOut->second->sendPlay(sound); return; } // outgoing to incoming connection -> forward MapOutIn::iterator itOutIn = m_mapOutIn.find(pConn); if (itOutIn != m_mapOutIn.end()) { itOutIn->second->sendPlay(sound); return; } } /** * @brief operator connection is closed * @param[in] pConn operator connection object * * The connection may not be used for sending any more in this callback. */ void OpSplitter::opConnClose(OpConn *pConn) { // local connection -> forget this connection MapLocal::iterator itLocal = m_mapLocal.find(pConn); if (itLocal != m_mapLocal.end()) { m_mapLocal.erase(itLocal); return; } // incoming to outgoing connection -> close outgoing connection as well MapInOut::iterator itInOut = m_mapInOut.find(pConn); if (itInOut != m_mapInOut.end()) { itInOut->second->close(); m_mapOutIn.erase(itInOut->second); m_mapInOut.erase(itInOut); return; } // outgoing to incoming connection -> make incoming connection local MapOutIn::iterator itOutIn = m_mapOutIn.find(pConn); if (itOutIn != m_mapOutIn.end()) { newLocal(itOutIn->second); m_mapInOut.erase(itOutIn->second); m_mapOutIn.erase(itOutIn); return; } } /** * @brief create new local connection * @param[in] pConn connection to make local */ void OpSplitter::newLocal(OpConn *pConn) { // add connection to local connection map Local &local = m_mapLocal[pConn]; local.m_number.clear(); // no extension dialed so far local.m_sendPlay = true; // send play command m_mgrs.m_callMgr.requestTimeCall(this, Time::now()); } /** * @brief a key has been pressed for a local connection * @param[in] itLocal local connection * @param[in] key the key pressed */ void OpSplitter::localKey(MapLocal::iterator itLocal, char key) { switch (key) { // begin new extension number case '*': itLocal->second.m_number.clear(); break; // add digit to extension number case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': itLocal->second.m_number += key; break; // close local connection / call extension case '#': if (itLocal->second.m_number.empty()) localClose(itLocal); else callExtension(itLocal); break; } } /** * @brief close local connection * @param[in] itLocal local connection */ void OpSplitter::localClose(MapLocal::iterator itLocal) { itLocal->first->close(); m_mapLocal.erase(itLocal); } /** * @brief call extension dialed over local connection * @param[in] itLocal local connection */ void OpSplitter::callExtension(MapLocal::iterator itLocal) { // lookup extension ExtMap::iterator itExt = m_extMap.find(itLocal->second.m_number); if (itExt == m_extMap.end()) { // unknown extension -> ignore itLocal->second.m_number.clear(); // begin new extension number return; } // try to open outgoiong operator connection to module OpConn *pOutConn = m_mgrs.m_opMgr.connect(itExt->second, this); if (!pOutConn) { // module is not ready for connection itLocal->second.m_number.clear(); // begin new extension number return; } // establish connection forwarding m_mapInOut[itLocal->first] = pOutConn; m_mapOutIn[pOutConn] = itLocal->first; // connection is no more a local one m_mapLocal.erase(itLocal); } } // namespace Blinker