#include "../shared/CommandDispatcher.h" #include "../shared/ReplyToClient.h" #include "../shared/SimpleLogFile.h" #include "../shared/GlobalConfigFile.h" #include "../shared/ContainerThread.h" #include "RecordDispatcher.h" #include "Strategy.h" #include "AutoSecondaryData.h" #include "AlertsDailyData.h" #include "SimpleAlertTest.h" // This is a sample showing how to use the alerts. And this is a simple // test harness. // // The real alerts would need more: // o Seperate the code that requires the database from the code that doesn't. // o Probably N threads to listen for alerts. // o Listen for multiple strategies at once. // o Probably group all strategies for one user, and respond with the next // id number, like the server does now, like the client expects. // o Probably store the recent alerts, so you have more control over when // a strategy is compare to the alerts. // o Listen for network disconnects. // o Respond over the network, not the log file. // o Print debug only on request. // Maybe more. That's just off the top of my head. class SimpleAlertTest : public ForeverThreadUser { private: enum { mtExternalRequest, mtAlert, mtAlertsDaily, mtAlertsDailyDone }; Parse::AlertStrategy _strategy; DatabaseWithRetry _readOnlyDatabase; int _skipCount; bool _showEntireRecord; bool _alertsDailyInitialized; AlertsDailyData _alertsDailyData; public: virtual void handleRequestInThread(Request *original) { switch (original->callbackId) { case mtExternalRequest: { ExternalRequest *request = dynamic_cast< ExternalRequest * >(original); std::string response; UserId userId = strtolDefault(request->getProperty("user_id"), 0); response = "user_id=" + ntoa(userId) + "\r\n"; _showEntireRecord = request->getProperty("show_entire_record") == "1"; response += "_showEntireRecord=" + ntoa((int)_showEntireRecord) + "\r\n"; std::string collaborate = request->getProperty("collaborate"); response += "collaborate="; response += collaborate; response += "\r\n"; if (collaborate.empty()) _strategy.clear(); else { _strategy.load(collaborate, userId, _readOnlyDatabase); } addToOutputQueue(request->getSocketInfo(), response, request->getResponseMessageId()); break; } case mtAlertsDaily: { ExternalRequest *request = dynamic_cast< ExternalRequest * >(original); std::string response; const std::string date = request->getProperty("date"); response += "date="; response += date; response += "\r\nRequest sent to thread."; AutoSecondaryData::instance().addAlertsDaily(date); AutoSecondaryData::instance().notifyWhenReady(this, mtAlertsDailyDone); addToOutputQueue(request->getSocketInfo(), response, request->getResponseMessageId()); break; } case mtAlertsDailyDone: { // Ideally we'd send this to the user over the network, but that would // be a minor pain to manage. sendToLogFile(TclList()<(original); Execution::RecordInfo recordInfo; recordInfo.setRecord(request->record); _strategy.init(recordInfo); if (_strategy.evaluateWhere(recordInfo)) { _skipCount = 0; TclList msg; msg<first<second.shortDebug(); msg<record->debugDump(); sendToLogFile(msg); } else { _skipCount++; if (_skipCount >= 10000) { TclList msg; msg<record->lookUpValue(MainFields::id); bool valid; int64_t value; field.getInt(valid, value); if (valid) msg<<"id"<record->lookUpValue(MainFields::timestamp); field.getInt(valid, value); if (valid) msg<<"timestamp"< listenForCommand("simple_alert_test", this, mtExternalRequest); CommandDispatcher::getInstance()-> listenForCommand("simple_alert_test_ad", this, mtAlertsDaily); IRecordDispatcher::getAlerts()->listenForRecords(this, mtAlert); start(); } }; void initSimpleAlertTest() { // We might or might not remove this from the executable when we're done. // This switch allows us to ignore the test most of the time, but run it // quickly and easily if we want to. if (getConfigItem("simple_alert_test") == "1") new SimpleAlertTest(); }