272 lines
7.7 KiB
C++
272 lines
7.7 KiB
C++
#include "Client.h"
|
|
#include "CallbackDispatcher.h"
|
|
#include "CallbackMainDispatcher.h"
|
|
#include "Socket.h"
|
|
#include "Strings.h"
|
|
#include "Mutex.h"
|
|
|
|
#include <list>
|
|
|
|
using namespace TelldusCore;
|
|
|
|
class Client::PrivateData {
|
|
public:
|
|
Socket eventSocket;
|
|
bool running, sensorCached, controllerCached;
|
|
std::wstring sensorCache, controllerCache;
|
|
TelldusCore::Mutex mutex;
|
|
CallbackMainDispatcher callbackMainDispatcher;
|
|
|
|
};
|
|
|
|
Client *Client::instance = 0;
|
|
|
|
Client::Client()
|
|
: Thread()
|
|
{
|
|
d = new PrivateData;
|
|
d->running = true;
|
|
d->sensorCached = false;
|
|
d->controllerCached = false;
|
|
d->callbackMainDispatcher.start();
|
|
start();
|
|
}
|
|
|
|
Client::~Client(void) {
|
|
stopThread();
|
|
wait();
|
|
{
|
|
TelldusCore::MutexLocker locker(&d->mutex);
|
|
}
|
|
delete d;
|
|
}
|
|
|
|
void Client::close() {
|
|
if (Client::instance != 0) {
|
|
delete Client::instance;
|
|
Client::instance = 0;
|
|
}
|
|
}
|
|
|
|
Client *Client::getInstance() {
|
|
if (Client::instance == 0) {
|
|
Client::instance = new Client();
|
|
}
|
|
return Client::instance;
|
|
}
|
|
|
|
bool Client::getBoolFromService(const Message &msg) {
|
|
return getIntegerFromService(msg) == TELLSTICK_SUCCESS;
|
|
}
|
|
|
|
int Client::getIntegerFromService(const Message &msg) {
|
|
std::wstring response = sendToService(msg);
|
|
if (response.compare(L"") == 0) {
|
|
return TELLSTICK_ERROR_COMMUNICATING_SERVICE;
|
|
}
|
|
return Message::takeInt(&response);
|
|
}
|
|
|
|
std::wstring Client::getWStringFromService(const Message &msg) {
|
|
std::wstring response = sendToService(msg);
|
|
return Message::takeString(&response);
|
|
}
|
|
|
|
int Client::registerEvent( CallbackStruct::CallbackType type, void *eventFunction, void *context ) {
|
|
//LOGGA, client is registering callback
|
|
debuglog(555, "Client, Registering callback");
|
|
return d->callbackMainDispatcher.registerCallback(type, eventFunction, context );
|
|
}
|
|
|
|
void Client::run(){
|
|
//listen here
|
|
d->eventSocket.connect(L"TelldusEvents");
|
|
|
|
while(d->running){
|
|
|
|
if(!d->eventSocket.isConnected()){
|
|
//LOGGA trying to (re)connect to TelldusEvents
|
|
debuglog(555, "Client, Trying to (re)connect to TelldusEvents");
|
|
d->eventSocket.connect(L"TelldusEvents"); //try to reconnect to service
|
|
if(!d->eventSocket.isConnected()){
|
|
//reconnect didn't succeed, wait a while and try again
|
|
msleep(2000);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
std::wstring clientMessage = d->eventSocket.read(1000); //testing 5 second timeout
|
|
|
|
while(clientMessage != L""){
|
|
//a message arrived
|
|
std::wstring type = Message::takeString(&clientMessage);
|
|
if(type == L"TDDeviceChangeEvent"){
|
|
DeviceChangeEventCallbackData *data = new DeviceChangeEventCallbackData();
|
|
data->deviceId = Message::takeInt(&clientMessage);
|
|
data->changeEvent = Message::takeInt(&clientMessage);
|
|
data->changeType = Message::takeInt(&clientMessage);
|
|
d->callbackMainDispatcher.retrieveCallbackEvent()->signal(data);
|
|
|
|
} else if(type == L"TDDeviceEvent"){
|
|
DeviceEventCallbackData *data = new DeviceEventCallbackData();
|
|
data->deviceId = Message::takeInt(&clientMessage);
|
|
data->deviceState = Message::takeInt(&clientMessage);
|
|
data->deviceStateValue = TelldusCore::wideToString(Message::takeString(&clientMessage));
|
|
d->callbackMainDispatcher.retrieveCallbackEvent()->signal(data);
|
|
|
|
} else if(type == L"TDRawDeviceEvent"){
|
|
RawDeviceEventCallbackData *data = new RawDeviceEventCallbackData();
|
|
data->data = TelldusCore::wideToString(Message::takeString(&clientMessage));
|
|
data->controllerId = Message::takeInt(&clientMessage);
|
|
d->callbackMainDispatcher.retrieveCallbackEvent()->signal(data);
|
|
|
|
} else if(type == L"TDSensorEvent"){
|
|
SensorEventCallbackData *data = new SensorEventCallbackData();
|
|
data->protocol = TelldusCore::wideToString(Message::takeString(&clientMessage));
|
|
data->model = TelldusCore::wideToString(Message::takeString(&clientMessage));
|
|
data->id = Message::takeInt(&clientMessage);
|
|
data->dataType = Message::takeInt(&clientMessage);
|
|
data->value = TelldusCore::wideToString(Message::takeString(&clientMessage));
|
|
data->timestamp = Message::takeInt(&clientMessage);
|
|
d->callbackMainDispatcher.retrieveCallbackEvent()->signal(data);
|
|
|
|
} else if(type == L"TDControllerEvent") {
|
|
ControllerEventCallbackData *data = new ControllerEventCallbackData();
|
|
data->controllerId = Message::takeInt(&clientMessage);
|
|
data->changeEvent = Message::takeInt(&clientMessage);
|
|
data->changeType = Message::takeInt(&clientMessage);
|
|
data->newValue = TelldusCore::wideToString(Message::takeString(&clientMessage));
|
|
d->callbackMainDispatcher.retrieveCallbackEvent()->signal(data);
|
|
|
|
} else {
|
|
clientMessage = L""; //cleanup, if message contained garbage/unhandled data
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::wstring Client::sendToService(const Message &msg) {
|
|
|
|
int tries = 0;
|
|
std::wstring readData;
|
|
while(tries < 20){
|
|
tries++;
|
|
if(tries == 20){
|
|
TelldusCore::Message msg;
|
|
msg.addArgument(TELLSTICK_ERROR_CONNECTING_SERVICE);
|
|
return msg;
|
|
}
|
|
Socket s;
|
|
s.connect(L"TelldusClient");
|
|
if (!s.isConnected()) { //Connection failed
|
|
msleep(500);
|
|
continue; //retry
|
|
}
|
|
s.write(msg.data());
|
|
if (!s.isConnected()) { //Connection failed sometime during operation... (better check here, instead of 5 seconds timeout later)
|
|
msleep(500);
|
|
continue; //retry
|
|
}
|
|
readData = s.read(8000); //TODO changed to 10000 from 5000, how much does this do...?
|
|
if(readData == L""){
|
|
msleep(500);
|
|
continue; //TODO can we be really sure it SHOULD be anything?
|
|
//TODO perhaps break here instead?
|
|
}
|
|
|
|
if (!s.isConnected()) { //Connection failed sometime during operation...
|
|
msleep(500);
|
|
continue; //retry
|
|
}
|
|
break;
|
|
}
|
|
|
|
return readData;
|
|
}
|
|
|
|
void Client::stopThread(){
|
|
d->running = false;
|
|
d->eventSocket.stopReadWait();
|
|
}
|
|
|
|
int Client::unregisterCallback( int callbackId ) {
|
|
//LOGGA, client correctly unregistering callback
|
|
debuglog(555, "Client, correctly unregistering callback");
|
|
return d->callbackMainDispatcher.unregisterCallback(callbackId);
|
|
}
|
|
|
|
int Client::getSensor(char *protocol, int protocolLen, char *model, int modelLen, int *sensorId, int *dataTypes) {
|
|
if (!d->sensorCached) {
|
|
Message msg(L"tdSensor");
|
|
std::wstring response = Client::getWStringFromService(msg);
|
|
int count = Message::takeInt(&response);
|
|
d->sensorCached = true;
|
|
d->sensorCache = L"";
|
|
if (count > 0) {
|
|
d->sensorCache = response;
|
|
}
|
|
}
|
|
|
|
if (d->sensorCache == L"") {
|
|
d->sensorCached = false;
|
|
return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
std::wstring p = Message::takeString(&d->sensorCache);
|
|
std::wstring m = Message::takeString(&d->sensorCache);
|
|
int id = Message::takeInt(&d->sensorCache);
|
|
int dt = Message::takeInt(&d->sensorCache);
|
|
|
|
if (protocol && protocolLen) {
|
|
strncpy(protocol, TelldusCore::wideToString(p).c_str(), protocolLen);
|
|
}
|
|
if (model && modelLen) {
|
|
strncpy(model, TelldusCore::wideToString(m).c_str(), modelLen);
|
|
}
|
|
if (sensorId) {
|
|
(*sensorId) = id;
|
|
}
|
|
if (dataTypes) {
|
|
(*dataTypes) = dt;
|
|
}
|
|
|
|
return TELLSTICK_SUCCESS;
|
|
}
|
|
|
|
int Client::getController(int *controllerId, int *controllerType, char *name, int nameLen, int *available) {
|
|
if (!d->controllerCached) {
|
|
Message msg(L"tdController");
|
|
std::wstring response = Client::getWStringFromService(msg);
|
|
int count = Message::takeInt(&response);
|
|
d->controllerCached = true;
|
|
d->controllerCache = L"";
|
|
if (count > 0) {
|
|
d->controllerCache = response;
|
|
}
|
|
}
|
|
|
|
if (d->controllerCache == L"") {
|
|
d->controllerCached = false;
|
|
return TELLSTICK_ERROR_NOT_FOUND;
|
|
}
|
|
|
|
int id = Message::takeInt(&d->controllerCache);
|
|
int type = Message::takeInt(&d->controllerCache);
|
|
std::wstring n = Message::takeString(&d->controllerCache);
|
|
int a = Message::takeInt(&d->controllerCache);
|
|
|
|
if (controllerId) {
|
|
(*controllerId) = id;
|
|
}
|
|
if (controllerType) {
|
|
(*controllerType) = type;
|
|
}
|
|
if (name && nameLen) {
|
|
strncpy(name, TelldusCore::wideToString(n).c_str(), nameLen);
|
|
}
|
|
if (available) {
|
|
(*available) = a;
|
|
}
|
|
|
|
return TELLSTICK_SUCCESS;
|
|
}
|