#ifndef FACT_DimState #define FACT_DimState #include "State.h" class DimState { public: enum { kOffline = -256, kNotAvailable = -257, }; protected: typedef function callback; callback fCallback; void HandlerImp(const EventImp &evt) { const bool disconnected = evt.GetSize()==0; last = cur; cur = make_pair(evt.GetTime(), disconnected ? kOffline : evt.GetQoS()); msg = disconnected ? "" : evt.GetString(); } void Callback(const EventImp &evt) { if (fCallback) fCallback(evt); } virtual void Handler(const EventImp &evt) { HandlerImp(evt); Callback(evt); } public: DimState(const string &n, const string s="STATE") : server(n), service(n+"/"+s), last(make_pair(Time(), kOffline)), cur(make_pair(Time(), kOffline)) { } virtual ~DimState() { } const string server; const string service; pair last; pair cur; string msg; virtual void Subscribe(StateMachineImp &imp) { imp.Subscribe(service.c_str()) (imp.Wrap(bind(&DimState::Handler, this, placeholders::_1))); } void SetCallback(const callback &cb) { fCallback = cb; } const Time &time() const { return cur.first; } const int32_t &state() const { return cur.second; } bool online() const { return state()>kOffline; } virtual State description() const { return State(kNotAvailable, ""); } }; ostream &operator<<(ostream& out, const DimState &s) { const State rc = s.description(); out << s.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - "; out << kBold << s.server; if (s.state()==DimState::kOffline) return out << ": Offline"; if (rc.index==DimState::kNotAvailable) return out; out << ": "; // if (rc.index==-2) // out << s.state(); // else out << rc.name << "[" << rc.index << "]"; if (!rc.comment.empty()) out << " - " << kBlue << rc.comment; return out; } class DimDescribedState : public DimState { vector states; public: DimDescribedState(const string &n) : DimState(n) { } virtual void Subscribe(StateMachineImp &imp) { imp.Subscribe((server+"/STATE_LIST").c_str()) (imp.Wrap(bind(&DimDescribedState::HandleDesc, this, placeholders::_1))); DimState::Subscribe(imp); } void HandleDesc(const EventImp &evt) { if (evt.GetSize()>0) { states = State::SplitStates(evt.GetString()); states.push_back(State(kOffline, "Offline")); } } State description() const { for (auto it=states.begin(); it!=states.end(); it++) if (it->index==state()) return *it; return State(kNotAvailable, "n/a"); } }; class DimVersion : public DimState { void Handler(const EventImp &evt) { HandlerImp(evt); cur.second = evt.GetSize()==4 ? evt.GetInt() : kOffline; if (cur.second==0) cur.second=kOffline; Callback(evt); } public: DimVersion() : DimState("DIS_DNS", "VERSION_NUMBER") { } string version() const { if (!online()) return "Offline"; ostringstream out; out << "V" << state()/100 << 'r' << state()%100; return out.str(); } State description() const { return State(state(), version()); } }; class DimControl : public DimState { map fCallbacks; void Handler(const EventImp &evt) { HandlerImp(evt); shortmsg = msg; file = ""; scriptdepth = -1; // Evaluate msg const size_t p0 = msg.find_first_of(':'); if (p0==string::npos) return; // Evaluate scriptdepth const size_t ps = msg.find_first_of('-'); if (ps!=string::npos) scriptdepth = atoi(msg.c_str()+ps+1); // Find filename const size_t p1 = msg.find_last_of('['); if (p1==string::npos) return; const size_t p2 = msg.find_first_of(':', p0+1); const size_t p3 = p2==string::npos || p2>p1 ? p1-1 : p2; file = msg.substr(p0+2, p3-p0-2); shortmsg.erase(p0, p3-p0); Callback(evt); const auto func = fCallbacks.find(file); if (func==fCallbacks.end()) return; // Call callback func->second(evt); } public: DimControl() : DimState("DIM_CONTROL") { } string file; string shortmsg; int scriptdepth; void AddCallback(const string &script, const callback &cb) { fCallbacks[script] = cb; } State description() const { return State(state(), "Current label"); } }; #endif