// // Copyright (C) 2012 Telldus Technologies AB. All rights reserved. // // Copyright: See COPYING file that comes with this distribution // // #include "service/EventUpdateManager.h" #ifdef _LINUX #include #include #include #include #include #include #include #endif // _LINUX #include #include #include #ifdef _LINUX #include #include #endif // _LINUX #include "common/common.h" //debug #include "common/EventHandler.h" #include "common/Message.h" #include "common/Socket.h" #include "common/Strings.h" #include "service/config.h" #include "service/ConnectionListener.h" #include "service/Log.h" typedef std::list SocketList; typedef std::list StringList; class EventUpdateManager::PrivateData { public: TelldusCore::EventHandler eventHandler; TelldusCore::EventRef stopEvent, updateEvent, clientConnectEvent; SocketList clients; ConnectionListener *eventUpdateClientListener; #ifdef _LINUX std::map fileList; #endif // _LINUX }; EventUpdateManager::EventUpdateManager() :Thread() { d = new PrivateData; d->stopEvent = d->eventHandler.addEvent(); d->updateEvent = d->eventHandler.addEvent(); d->clientConnectEvent = d->eventHandler.addEvent(); d->eventUpdateClientListener = new ConnectionListener(L"TelldusEvents", d->clientConnectEvent); #ifdef _LINUX loadScripts("deviceevent"); loadScripts("devicechangeevent"); loadScripts("rawdeviceevent"); loadScripts("sensorevent"); loadScripts("controllerevent"); #endif // _LINUX } EventUpdateManager::~EventUpdateManager(void) { d->stopEvent->signal(); wait(); delete d->eventUpdateClientListener; for (SocketList::iterator it = d->clients.begin(); it != d->clients.end(); ++it) { delete(*it); } delete d; } TelldusCore::EventRef EventUpdateManager::retrieveUpdateEvent() { return d->updateEvent; } void EventUpdateManager::run() { while(!d->stopEvent->isSignaled()) { if (!d->eventHandler.waitForAny()) { continue; } if(d->clientConnectEvent->isSignaled()) { // new client added TelldusCore::EventDataRef eventData = d->clientConnectEvent->takeSignal(); ConnectionListenerEventData *data = dynamic_cast(eventData.get()); if(data) { d->clients.push_back(data->socket); } } else if(d->updateEvent->isSignaled()) { // device event, signal all clients TelldusCore::EventDataRef eventData = d->updateEvent->takeSignal(); EventUpdateData *data = reinterpret_cast(eventData.get()); if(data) { sendMessageToClients(data); executeScripts(data); } } } } void EventUpdateManager::loadScripts(const std::string &folder) { #ifdef _LINUX std::string path = TelldusCore::formatf("%s/%s", SCRIPT_PATH, folder.c_str()); struct dirent **namelist; int count = scandir(path.c_str(), &namelist, NULL, alphasort); if (count < 0) { return; } for(int i = 0; i < count; ++i) { if (strcmp(namelist[i]->d_name, ".") != 0 && strcmp(namelist[i]->d_name, "..") != 0) { d->fileList[folder].push_back(namelist[i]->d_name); } free(namelist[i]); } free(namelist); #endif // _LINUX } void EventUpdateManager::sendMessageToClients(EventUpdateData *data) { int connected = 0; for(SocketList::iterator it = d->clients.begin(); it != d->clients.end();) { if((*it)->isConnected()) { connected++; TelldusCore::Message msg; if(data->messageType == L"TDDeviceEvent") { msg.addArgument("TDDeviceEvent"); msg.addArgument(data->deviceId); msg.addArgument(data->eventState); msg.addArgument(data->eventValue); // string } else if(data->messageType == L"TDDeviceChangeEvent") { msg.addArgument("TDDeviceChangeEvent"); msg.addArgument(data->deviceId); msg.addArgument(data->eventDeviceChanges); msg.addArgument(data->eventChangeType); } else if(data->messageType == L"TDRawDeviceEvent") { msg.addArgument("TDRawDeviceEvent"); msg.addArgument(data->eventValue); // string msg.addArgument(data->controllerId); } else if(data->messageType == L"TDSensorEvent") { msg.addArgument("TDSensorEvent"); msg.addArgument(data->protocol); msg.addArgument(data->model); msg.addArgument(data->sensorId); msg.addArgument(data->dataType); msg.addArgument(data->value); msg.addArgument(data->timestamp); } else if(data->messageType == L"TDControllerEvent") { msg.addArgument("TDControllerEvent"); msg.addArgument(data->controllerId); msg.addArgument(data->eventState); msg.addArgument(data->eventChangeType); msg.addArgument(data->eventValue); } (*it)->write(msg); it++; } else { //connection is dead, remove it debuglogservice(0, "Lost connection, removing it"); delete *it; it = d->clients.erase(it); } } } void EventUpdateManager::executeScripts(EventUpdateData *data) { #ifdef _LINUX std::string dir; std::vector env; // Create a copy of the environment unsigned int size = 0; for(; ; ++size) { if (environ[size] == 0) { break; } } env.reserve(size + 6); // 6 is the most used extra environmental variables any event uses for(unsigned int i = 0; i < size; ++i) { env.push_back(environ[i]); } if(data->messageType == L"TDDeviceEvent") { dir = "deviceevent"; env.push_back(TelldusCore::formatf("DEVICEID=%i", data->deviceId)); env.push_back(TelldusCore::formatf("METHOD=%i", data->eventState)); env.push_back(TelldusCore::formatf("METHODDATA=%s", TelldusCore::wideToString(data->eventValue).c_str())); } else if(data->messageType == L"TDDeviceChangeEvent") { dir = "devicechangeevent"; env.push_back(TelldusCore::formatf("DEVICEID=%i", data->deviceId)); env.push_back(TelldusCore::formatf("CHANGEEVENT=%i", data->eventDeviceChanges)); env.push_back(TelldusCore::formatf("CHANGETYPE=%i", data->eventChangeType)); } else if(data->messageType == L"TDRawDeviceEvent") { dir = "rawdeviceevent"; env.push_back(TelldusCore::formatf("RAWDATA=%s", TelldusCore::wideToString(data->eventValue).c_str())); // string env.push_back(TelldusCore::formatf("CONTROLLERID=%i", data->controllerId)); } else if (data->messageType == L"TDSensorEvent") { dir = "sensorevent"; env.push_back(TelldusCore::formatf("PROTOCOL=%s", TelldusCore::wideToString(data->protocol).c_str())); env.push_back(TelldusCore::formatf("MODEL=%s", TelldusCore::wideToString(data->model).c_str())); env.push_back(TelldusCore::formatf("SENSORID=%i", data->sensorId)); env.push_back(TelldusCore::formatf("DATATYPE=%i", data->dataType)); env.push_back(TelldusCore::formatf("VALUE=%s", TelldusCore::wideToString(data->value).c_str())); env.push_back(TelldusCore::formatf("TIMESTAMP=%i", data->timestamp)); } else if(data->messageType == L"TDControllerEvent") { dir = "controllerevent"; env.push_back(TelldusCore::formatf("CONTROLLERID=%i", data->controllerId)); env.push_back(TelldusCore::formatf("CHANGEEVENT=%i", data->eventState)); env.push_back(TelldusCore::formatf("CHANGETYPE=%i", data->eventChangeType)); env.push_back(TelldusCore::formatf("VALUE=%s", TelldusCore::wideToString(data->eventValue).c_str())); } else { // Unknown event, should not happen return; } char *newEnv[env.size()+1]; // +1 for the last stop element for(int i = 0; i < env.size(); ++i) { newEnv[i] = new char[env.at(i).length()+1]; snprintf(newEnv[i], env.at(i).length()+1, "%s", env.at(i).c_str()); } newEnv[env.size()] = 0; // Mark end of array for(StringList::iterator it = d->fileList[dir].begin(); it != d->fileList[dir].end(); ++it) { executeScript(TelldusCore::formatf("%s/%s/%s", SCRIPT_PATH, dir.c_str(), (*it).c_str()), (*it), newEnv); } // Cleanup for(int i = 0; newEnv[i] != 0; ++i) { delete[] newEnv[i]; } #endif // _LINUX } void EventUpdateManager::executeScript(std::string script, const std::string &name, char ** env) { #ifdef _LINUX pid_t pid = fork(); if (pid == -1) { Log::error("Could not fork() to execute script %s", script.c_str()); return; } if (pid == 0) { char *n = new char[name.length()+1]; snprintf(n, name.length()+1, "%s", name.c_str()); static char * argv[] = { n }; execve(script.c_str(), argv, env); delete[] n; Log::error("Could not execute %s (%i): %s", script.c_str(), errno, strerror(errno)); exit(1); } #endif // _LINUX }