BlinkenArea - GitList
Repositories
Blog
Wiki
Blinker
Code
Commits
Branches
Tags
Search
Tree:
fd4d523
Branches
Tags
master
Blinker
src
noarch
Sender.h
now repeating frames after 1 s idle prepared sender to support multiple protocols
Stefan Schuermans
commited
fd4d523
at 2011-11-14 21:07:06
Sender.h
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 */ #ifndef SENDER_H #define SENDER_H #include <list> #include <string> #include <BlinkenLib/BlinkenFrame.h> #include "CallMgr.h" #include "Directory.h" #include "File.h" #include "Module.h" #include "SettingFile.h" #include "StreamMgr.h" #include "StreamRecv.h" #include "TimeCallee.h" namespace Blinker { /// stream sender template<typename ADDR, typename SOCK> class Sender: public Module, public StreamRecv, public TimeCallee { protected: /// static destination struct Dest { std::string m_name; ///< name of static destination SettingFile m_file; ///< setting file object ADDR m_addr; ///< parsed address Dest(const std::string &name, const File &file); ///< constructor bool parse(); ///< parse address from current file }; /// static destinations typedef std::list<Dest> Dests; public: /** * @brief constructor * @param[in] callMgr callback manager * @param[in] streamMgr stream manager * @param[in] dirBase base directory */ Sender(CallMgr &callMgr, StreamMgr &streamMgr, const Directory &dirBase); /// virtual destructor virtual ~Sender(); private: /// copy constructor disabled Sender(const Sender &that); /// assignment operator disabled const Sender & operator=(const Sender &that); public: /// check for update of configuration virtual void updateConfig(); /** * @brief set current frame * @param[in] pFrame current frame */ virtual void setFrame(stBlinkenFrame *pFrame); /// set current frame to none virtual void setNoFrame(); /// callback when requsted time reached virtual void timeCall(); protected: /// get input stream and attach to it void getInStream(); /// detach from input stream and release it void releaseInStream(); /// create socket and bind it void createSock(); /// destroy socket void destroySock(); /** * @brief light update of static destinations, * i.e. stat all files in current static destination directory * @param[in] dests static destinations for protocol * @param[in] proto Blinken protocol identifier */ void updateDestsLight(Dests &dests, etBlinkenProto proto); /** * @brief full update of static destinations, * i.e. scan files in playlist directory * @param[in] dirDests static destinations directory for protocol * @param[in] dests static destinations for protocol * @param[in] proto Blinken protocol identifier */ void updateDestsFull(Directory &dirDests, Dests &dests, etBlinkenProto proto); /** * @brief send current frame to address * @param[in] addr address to send to * @param[in] proto Blinken protocol identifier */ void sendCurFrame(const ADDR &addr, etBlinkenProto proto); /** * @brief send "no frame" to address * @param[in] addr address to send to * @param[in] proto Blinken protocol identifier */ void sendNoFrame(const ADDR &addr, etBlinkenProto proto); /** * @brief send frame to address * @param[in] data protcol data of frame * @param[in] addr address to send to */ void sendFrame(const std::string &data, const ADDR &addr); /** * @brief convert frame to protocol data * @param[in] pFrame frame * @param[in] proto Blinken protocol identifier * @param[out] data protcol data */ void frame2data(stBlinkenFrame *pFrame, etBlinkenProto proto, std::string &data); /** * @brief get "no frame" protocol data * @param[in] proto Blinken protocol identifier * @param[out] data protcol data */ void noFrame2data(etBlinkenProto proto, std::string &data); protected: SettingFile m_fileInStream; ///< input stream name file SettingFile m_fileBind; ///< bind address file Directory m_dirDestsMcuf; ///< static MCUF destinations directory std::string m_nameInStream; ///< name of input stream Stream *m_pInStream; ///< input stream SOCK *m_pSock; ///< socket to use for sending streams Dests m_destsMcuf; ///< current static MCUF destinations }; // class Sender /* ########## # Sender # ########## */ /** * @brief constructor * @param[in] callMgr callback manager * @param[in] streamMgr stream manager * @param[in] dirBase base directory */ template<typename ADDR, typename SOCK> Sender<ADDR, SOCK>::Sender(CallMgr &callMgr, StreamMgr &streamMgr, const Directory &dirBase): Module(callMgr, streamMgr, dirBase), m_fileInStream(dirBase.getFile("instream")), m_fileBind(dirBase.getFile("bind")), m_dirDestsMcuf(dirBase.getSubdir("mcuf")), m_pInStream(NULL), m_pSock(NULL) { // get input stream and attach to it getInStream(); // create and bind socket createSock(); // load static destinations updateDestsFull(m_dirDestsMcuf, m_destsMcuf, BlinkenProtoMcuf); } /// virtual destructor template<typename ADDR, typename SOCK> Sender<ADDR, SOCK>::~Sender() { // send no frame to all destinations setNoFrame(); // destroy socket destroySock(); // detach from input stream and release it releaseInStream(); // cancel time callback m_callMgr.cancelTimeCall(this); } /// check for update of configuration template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::updateConfig() { // input stream name file was modified -> re-get input stream if (m_fileInStream.checkModified()) { releaseInStream(); getInStream(); } // bind address file was modified -> re-create socket if (m_fileBind.checkModified()) { destroySock(); createSock(); } // static destinations update // (directory modified -> full, otherwise -> light) if (m_dirDestsMcuf.checkModified()) updateDestsFull(m_dirDestsMcuf, m_destsMcuf, BlinkenProtoMcuf); else updateDestsLight(m_destsMcuf, BlinkenProtoMcuf); } /** * @brief set current frame * @param[in] pFrame current frame */ template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::setFrame(stBlinkenFrame *pFrame) { std::string mcuf; // convert frame to protocol data if (!m_destsMcuf.empty()) frame2data(pFrame, BlinkenProtoMcuf, mcuf); // send frame to all static MCUF destinations typename Dests::const_iterator itDest; for (itDest = m_destsMcuf.begin(); itDest != m_destsMcuf.end(); ++itDest) sendFrame(mcuf, itDest->m_addr); // request time callback in one second m_callMgr.requestTimeCall(this, Time::now() + Time(1)); } /// set current frame to none template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::setNoFrame() { std::string mcuf; // get "no frame" protocol data if (!m_destsMcuf.empty()) noFrame2data(BlinkenProtoMcuf, mcuf); // send "no frame" to all static MCUF destinations typename Dests::const_iterator itDest; for (itDest = m_destsMcuf.begin(); itDest != m_destsMcuf.end(); ++itDest) sendFrame(mcuf, itDest->m_addr); // request time callback in one second m_callMgr.requestTimeCall(this, Time::now() + Time(1)); } /// callback when requsted time reached template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::timeCall() { stBlinkenFrame *pFrame; std::string data; // get current frame from stream if (m_pInStream && m_pInStream->getCurFrame(pFrame)) // repeat frame - behave exactly like this frame had been set setFrame(pFrame); // no stream of no current frame else // repeat "no frame" - behave exactly like "no frame" had been set setNoFrame(); } /// get input stream and attach to it template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::getInStream() { // get input stream m_fileInStream.getStr(m_nameInStream); m_pInStream = &m_streamMgr.refStream(m_nameInStream); // attach to input stream if (m_pInStream) m_pInStream->attach(this); } /// detach from input stream and release it template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::releaseInStream() { // detach from input stream if (m_pInStream) m_pInStream->detach(this); // unreference stream m_pInStream = NULL; m_streamMgr.unrefStream(m_nameInStream); } /// create socket and bind it template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::createSock() { std::string strAddr; ADDR addr; // create socket if (!m_pSock) { m_pSock = new SOCK(); if (!m_pSock) return; } // get bind address from bind address setting file if (!m_fileBind.getStr(strAddr) || !addr.fromStr(strAddr)) { delete m_pSock; m_pSock = NULL; return; } // bind socket if (!m_pSock->bind(addr)) { delete m_pSock; m_pSock = NULL; return; } } /// destroy socket template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::destroySock() { // destroy socket if (m_pSock) { delete m_pSock; m_pSock = NULL; } } /** * @brief light update of static destinations, * i.e. stat all files in current static destination directory * @param[in] dests static destinations for one protocol * @param[in] proto Blinken protocol identifier */ template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::updateDestsLight(Dests &dests, etBlinkenProto proto) { // walk through all files in static dest dir and check for modification typename Dests::iterator itDest = dests.begin(); while (itDest != dests.end()) { // address changed if (itDest->m_file.checkModified()) { // send "no frame" to old address sendNoFrame(itDest->m_addr, proto); // re-load address if (!itDest->parse()) { // parsing address failed -> remove destination itDest = dests.erase(itDest); // do not advance to next destination continue; } // send current frame to new address sendCurFrame(itDest->m_addr, proto); } // advance to next destination ++itDest; } // while itDest } /** * @brief full update of static destinations, * i.e. scan files in playlist directory * @param[in] dirDests static destinations directory for protocol * @param[in] dests static destinations for protocol * @param[in] proto Blinken protocol identifier */ template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::updateDestsFull(Directory &dirDests, Dests &dests, etBlinkenProto proto) { // get list of files in static destinations directory typedef std::list<std::string> Filelist; Filelist curFiles; dirDests.getEntries(Directory::TypeFile, curFiles); // walk through current static destinations and file list simultaneously Filelist::const_iterator itFile = curFiles.begin(); typename Dests::iterator itDest = dests.begin(); while (itFile != curFiles.end() || itDest != dests.end()) { // new static destination inserted if (itDest == dests.end() || (itFile != curFiles.end() && *itFile < itDest->m_name)) { // parse new address Dest dest(*itFile, dirDests.getFile(*itFile)); if (dest.parse()) { // insert new static destination dests.insert(itDest, dest); // send current frame to new static destination sendCurFrame(itDest->m_addr, proto); } // advance to next file ++itFile; } // static destination removed // static destination changed (=> remove and re-insert in next iteration) else if (itFile == curFiles.end() || *itFile > itDest->m_name || itDest->m_file.checkModified()) { // send "no frame" to old static destination sendNoFrame(itDest->m_addr, proto); // remove static destination itDest = dests.erase(itDest); // do not advance to next file } // static destination stayed in playlist and did not change else { // advance to next file and next static destination ++itFile; ++itDest; } } // while itFile itDest } /** * @brief send current frame to address * @param[in] addr address to send to * @param[in] proto Blinken protocol identifier */ template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::sendCurFrame(const ADDR &addr, etBlinkenProto proto) { stBlinkenFrame *pFrame; std::string data; // get current frame from stream if (m_pInStream && m_pInStream->getCurFrame(pFrame)) { // convert frame to protocal data frame2data(pFrame, proto, data); // send frame to address sendFrame(data, addr); } // no stream of no current frame else { // get "no frame" ad protocal data noFrame2data(proto, data); // send "no frame" to address sendFrame(data, addr); } } /** * @brief send "no frame" to address * @param[in] addr address to send to * @param[in] proto Blinken protocol identifier */ template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::sendNoFrame(const ADDR &addr, etBlinkenProto proto) { std::string data; // get "no frame" ad protocal data noFrame2data(proto, data); // send "no frame" to address sendFrame(data, addr); } /** * @brief send frame to address * @param[in] data protocol data of frame * @param[in] addr address to send to */ template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::sendFrame(const std::string &data, const ADDR &addr) { if (m_pSock) { m_pSock->send(data, addr); } } /** * @brief convert frame to protocol data * @param[in] pFrame frame * @param[in] proto Blinken protocol identifier * @param[out] data protocol data */ template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::frame2data(stBlinkenFrame *pFrame, etBlinkenProto proto, std::string &data) { char buf[65536]; int len; // convert frame to protcol data len = BlinkenFrameToNetwork(pFrame, proto, buf, sizeof(buf)); data.assign(buf, len); } /** * @brief get "no frame" protocol data * @param[in] proto Blinken protocol identifier * @param[out] data protcol data */ template<typename ADDR, typename SOCK> void Sender<ADDR, SOCK>::noFrame2data(etBlinkenProto proto, std::string &data) { // obtain "no frame" protcol data (void)proto; // FIXME data.clear(); // FIXME } /* ################ # Sender::Dest # ################ */ /// constructor template<typename ADDR, typename SOCK> Sender<ADDR, SOCK>::Dest::Dest(const std::string &name, const File &file): m_name(name), m_file(file) { } /// parse address from current file template<typename ADDR, typename SOCK> bool Sender<ADDR, SOCK>::Dest::parse() { std::string strAddr; return m_file.getStr(strAddr) && m_addr.fromStr(strAddr); } } // namespace Blinker #endif // #ifndef SENDER_H