#include "httpdaemon.h" #include "plugin/device.h" #include "plugin/deviceclass.h" #include "plugin/deviceplugin.h" #include "types/statetype.h" #include #include #include #include #include #include HttpDaemon::HttpDaemon(Device *device, DevicePlugin *parent): QTcpServer(parent), disabled(false), m_plugin(parent), m_device(device) { listen(QHostAddress::Any, device->params().value("httpport").toInt()); } void HttpDaemon::incomingConnection(qintptr socket) { qDebug() << "incoming connection"; if (disabled) return; // When a new client connects, the server constructs a QTcpSocket and all // communication with the client is done over this QTcpSocket. QTcpSocket // works asynchronously, this means that all the communication is done // in the two slots readClient() and discardClient(). QTcpSocket* s = new QTcpSocket(this); connect(s, SIGNAL(readyRead()), this, SLOT(readClient())); connect(s, SIGNAL(disconnected()), this, SLOT(discardClient())); s->setSocketDescriptor(socket); } void HttpDaemon::actionExecuted(const QUuid &actionTypeId) { m_actionList.append(qMakePair(actionTypeId, QDateTime::currentDateTime())); } void HttpDaemon::readClient() { if (disabled) return; // This slot is called when the client sent data to the server. The // server looks if it was a get request and sends a very simple HTML // document back. QTcpSocket* socket = (QTcpSocket*)sender(); if (socket->canReadLine()) { QByteArray data = socket->readLine(); QStringList tokens = QString(data).split(QRegExp("[ \r\n][ \r\n]*")); qDebug() << "incoming data" << tokens[1]; QUrl url("http://foo.bar" + tokens[1]); QUrlQuery query(url); qDebug() << "query is" << url.path(); if (url.path() == "/setstate") { emit setState(StateTypeId(query.queryItems().first().first), QVariant(query.queryItems().first().second)); } else if (url.path() == "/generateevent") { qDebug() << "got generateevent" << query.queryItemValue("eventid"); emit triggerEvent(EventTypeId(query.queryItemValue("eventid"))); } else if (url.path() == "/actionhistory") { QTextStream os(socket); os.setAutoDetectUnicode(true); os << generateHeader(); for (int i = 0; i < m_actionList.count(); ++i) { os << m_actionList.at(i).first.toString() << '\n'; } socket->close(); return; } else if (url.path() == "/clearactionhistory") { m_actionList.clear(); } if (tokens[0] == "GET") { QTextStream os(socket); os.setAutoDetectUnicode(true); os << generateWebPage(); socket->close(); qDebug() << "Wrote to client"; if (socket->state() == QTcpSocket::UnconnectedState) { delete socket; qDebug() << "Connection closed"; } } } } void HttpDaemon::discardClient() { QTcpSocket* socket = (QTcpSocket*)sender(); socket->deleteLater(); qDebug() << "Connection closed"; } QString HttpDaemon::generateHeader() { QString contentHeader( "HTTP/1.0 200 Ok\r\n" "Content-Type: text/html; charset=\"utf-8\"\r\n" "\r\n" ); return contentHeader; } QString HttpDaemon::generateWebPage() { DeviceClass deviceClass = m_plugin->supportedDevices().first(); QString body = QString( "" "" "

Mock device Controller

\n" "
" "

Device Information

" "Name: %1
" "ID: %2
" "DeviceClass ID: %3
").arg(m_device->name()).arg(m_device->id().toString()).arg(deviceClass.id().toString()); body.append("
"); body.append("

States

"); body.append(""); for (int i = 0; i < deviceClass.states().count(); ++i) { body.append(""); body.append(""); const StateType &stateType = deviceClass.states().at(i); body.append(""); body.append(QString("").arg(stateType.id().toString()).arg(m_device->states().at(i).value().toString())); body.append(""); body.append(""); body.append(""); } body.append("
" + stateType.name() + "
"); body.append("
"); body.append("

Events

"); body.append(""); for (int i = 0; i < deviceClass.events().count(); ++i) { const EventType &eventType = deviceClass.events().at(i); body.append(QString( "" "" "" "" "" "" ).arg(eventType.name()).arg(eventType.id().toString())); } body.append("
%1
"); body.append("
"); body.append("

Actions

"); body.append(""); body.append(""); for (int i = 0; i < m_actionList.count(); ++i) { QUuid actionTypeId = m_actionList.at(i).first; QDateTime timestamp = m_actionList.at(i).second; QString actionName; foreach (const ActionType &at, deviceClass.actions()) { if (at.id() == actionTypeId) { actionName = at.name(); break; } } body.append(QString( "" "" "" "" "" ).arg(actionName).arg(actionTypeId.toString()).arg(timestamp.toString())); } body.append("
NameType IDTimestamp
%1%2%3
"); body.append("\n"); return generateHeader() + body; }