Added WifiLamp server code

This commit is contained in:
0xFEEDC0DE64
2018-04-20 21:26:45 +02:00
parent 1069a3ea18
commit a25e54ac48
9 changed files with 614 additions and 0 deletions

73
.gitignore vendored Normal file
View File

@ -0,0 +1,73 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

17
WifiLamp.pro Normal file
View File

@ -0,0 +1,17 @@
QT = core network
CONFIG += c++11
CONFIG -= app_bundle
DEFINES += QT_DEPRECATED_WARNINGS QT_DISABLE_DEPRECATED_BEFORE=0x060000
HEADERS += relaisclient.h \
relaisserver.h \
relaiswebserver.h
SOURCES += main.cpp \
relaisclient.cpp \
relaisserver.cpp \
relaiswebserver.cpp
include(QtWebserver/QtWebserver.pri)

26
main.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <QCoreApplication>
#include <QTcpServer>
#include "relaisserver.h"
#include "relaiswebserver.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
RelaisServer server(&app);
if(!server.listen(QHostAddress::Any, 1234))
{
qCritical() << "server could not start listening:" << server.errorString();
return -1;
}
RelaisWebserver webServer(&server, &app);
if(!webServer.listen(QHostAddress::Any, 8080))
{
qCritical() << "webserver could not start listening:" << webServer.errorString();
return -2;
}
return app.exec();
}

93
relaisclient.cpp Normal file
View File

@ -0,0 +1,93 @@
#include "relaisclient.h"
#include <QTcpSocket>
#include "relaisserver.h"
RelaisClient::RelaisClient(QTcpSocket *socket, RelaisServer *server) :
QObject(server),
m_socket(socket),
m_server(server),
m_state(Name)
{
m_socket->setParent(this);
connect(m_socket, &QIODevice::readyRead, this, &RelaisClient::readyRead);
connect(m_socket, &QAbstractSocket::disconnected, this, &QObject::deleteLater);
}
quint16 RelaisClient::localPort() const
{
return m_socket->localPort();
}
QHostAddress RelaisClient::localAddress() const
{
return m_socket->localAddress();
}
quint16 RelaisClient::peerPort() const
{
return m_socket->peerPort();
}
QHostAddress RelaisClient::peerAddress() const
{
return m_socket->peerAddress();
}
QString RelaisClient::peerName() const
{
return m_socket->peerName();
}
const QString &RelaisClient::name() const
{
return m_name;
}
const QString &RelaisClient::status() const
{
return m_status;
}
void RelaisClient::on()
{
m_socket->write(QByteArrayLiteral("1"));
m_status = QString();
}
void RelaisClient::off()
{
m_socket->write(QByteArrayLiteral("0"));
m_status = QString();
}
void RelaisClient::toggle()
{
m_socket->write(QByteArrayLiteral("t"));
m_status = QString();
}
void RelaisClient::requestStatus()
{
m_socket->write(QByteArrayLiteral("s"));
m_status = QString();
}
void RelaisClient::readyRead()
{
m_buffer.append(m_socket->readAll());
int index;
while((index = m_buffer.indexOf(QByteArrayLiteral("\r\n"))) != -1)
{
QString line(m_buffer.left(index));
m_buffer.remove(0, index + 2);
switch(m_state)
{
case Name: m_name = line; m_state = Status; break;
case Status: m_status = line; break;
}
}
}

43
relaisclient.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <QObject>
#include <QHostAddress>
class QTcpSocket;
class RelaisServer;
class RelaisClient : public QObject
{
Q_OBJECT
public:
explicit RelaisClient(QTcpSocket *socket, RelaisServer *server);
quint16 localPort() const;
QHostAddress localAddress() const;
quint16 peerPort() const;
QHostAddress peerAddress() const;
QString peerName() const;
const QString &name() const;
const QString &status() const;
public Q_SLOTS:
void on();
void off();
void toggle();
void requestStatus();
private Q_SLOTS:
void readyRead();
private:
QTcpSocket *m_socket;
RelaisServer *m_server;
QByteArray m_buffer;
enum { Name, Status } m_state;
QString m_name;
QString m_status;
};

113
relaisserver.cpp Normal file
View File

@ -0,0 +1,113 @@
#include "relaisserver.h"
#include <QTcpServer>
#include "relaisclient.h"
RelaisServer::RelaisServer(QObject *parent) :
QObject(parent),
m_server(new QTcpServer(this))
{
connect(m_server, &QTcpServer::acceptError, this, &RelaisServer::acceptError);
connect(m_server, &QTcpServer::newConnection, this, &RelaisServer::newConnection);
}
bool RelaisServer::listen(const QHostAddress &address, quint16 port)
{
return m_server->listen(address, port);
}
void RelaisServer::close()
{
m_server->close();
}
bool RelaisServer::isListening() const
{
return m_server->isListening();
}
void RelaisServer::setMaxPendingConnections(int numConnections)
{
m_server->setMaxPendingConnections(numConnections);
}
int RelaisServer::maxPendingConnections() const
{
return m_server->maxPendingConnections();
}
quint16 RelaisServer::serverPort() const
{
return m_server->serverPort();
}
QHostAddress RelaisServer::serverAddress() const
{
return m_server->serverAddress();
}
qintptr RelaisServer::socketDescriptor() const
{
return m_server->socketDescriptor();
}
bool RelaisServer::setSocketDescriptor(qintptr socketDescriptor)
{
return m_server->setSocketDescriptor(socketDescriptor);
}
bool RelaisServer::hasPendingConnections() const
{
return m_server->hasPendingConnections();
}
QAbstractSocket::SocketError RelaisServer::serverError() const
{
return m_server->serverError();
}
QString RelaisServer::errorString() const
{
return m_server->errorString();
}
void RelaisServer::pauseAccepting()
{
m_server->pauseAccepting();
}
void RelaisServer::resumeAccepting()
{
m_server->resumeAccepting();
}
#ifndef QT_NO_NETWORKPROXY
void RelaisServer::setProxy(const QNetworkProxy &networkProxy)
{
m_server->setProxy(networkProxy);
}
QNetworkProxy RelaisServer::proxy() const
{
return m_server->proxy();
}
#endif
const QSet<RelaisClient *> &RelaisServer::clients() const
{
return m_clients;
}
void RelaisServer::newConnection()
{
auto connection = m_server->nextPendingConnection();
if(!connection)
return;
auto client = new RelaisClient(connection, this);
m_clients.insert(client);
connect(client, &QObject::destroyed, this, [=](){
m_clients.remove(client);
});
}

61
relaisserver.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include <QObject>
#include <QHostAddress>
#include <QAbstractSocket>
#ifndef QT_NO_NETWORKPROXY
#include <QNetworkProxy>
#endif
class QTcpServer;
class RelaisClient;
class RelaisServer : public QObject
{
Q_OBJECT
public:
explicit RelaisServer(QObject *parent = Q_NULLPTR);
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
void close();
bool isListening() const;
void setMaxPendingConnections(int numConnections);
int maxPendingConnections() const;
quint16 serverPort() const;
QHostAddress serverAddress() const;
qintptr socketDescriptor() const;
bool setSocketDescriptor(qintptr socketDescriptor);
bool hasPendingConnections() const;
QAbstractSocket::SocketError serverError() const;
QString errorString() const;
void pauseAccepting();
void resumeAccepting();
#ifndef QT_NO_NETWORKPROXY
void setProxy(const QNetworkProxy &networkProxy);
QNetworkProxy proxy() const;
#endif
const QSet<RelaisClient*> &clients() const;
Q_SIGNALS:
void acceptError(QAbstractSocket::SocketError socketError);
protected:
QSet<RelaisClient*> m_clients;
private Q_SLOTS:
void newConnection();
private:
QTcpServer *m_server;
};

161
relaiswebserver.cpp Normal file
View File

@ -0,0 +1,161 @@
#include "relaiswebserver.h"
#include <QStringBuilder>
#include "httpclientconnection.h"
#include "httpcontainers.h"
#include "relaisserver.h"
#include "relaisclient.h"
RelaisWebserver::RelaisWebserver(RelaisServer *relaisServer, QObject *parent) :
HttpServer(parent),
m_relaisServer(relaisServer)
{
}
void RelaisWebserver::handleRequest(HttpClientConnection *connection, const HttpRequest &request)
{
qDebug() << request.path;
if(!request.path.startsWith('/'))
{
HttpResponse response;
response.protocol = request.protocol;
response.statusCode = HttpResponse::StatusCode::BadRequest;
response.body = "Path does not start with /";
response.headers.insert(QStringLiteral("Server"), QStringLiteral("Hatschi Server 1.0"));
response.headers.insert(QStringLiteral("Content-Type"), QStringLiteral("text/html"));
connection->sendResponse(response);
return;
}
if(request.path == QStringLiteral("/"))
{
handleRoot(connection, request);
}
else if(request.path.startsWith("/devices/"))
{
auto parts = request.path.split('/');
if(parts.count() != 4)
{
handle404(connection, request);
return;
}
RelaisClient *client = Q_NULLPTR;
for(auto _client : m_relaisServer->clients())
{
if(!_client->name().isEmpty() &&
_client->name() == parts.at(2))
{
client = _client;
break;
}
}
if(!client)
{
handle404(connection, request);
return;
}
if(parts.at(3) == "on")
{
client->on();
redirectRoot(connection, request);
return;
}
else if(parts.at(3) == "off")
{
client->off();
redirectRoot(connection, request);
return;
}
else if(parts.at(3) == "toggle")
{
client->toggle();
redirectRoot(connection, request);
return;
}
else
{
handle404(connection, request);
return;
}
}
else
{
handle404(connection, request);
}
}
void RelaisWebserver::handleRoot(HttpClientConnection *connection, const HttpRequest &request)
{
QString output = "<p>" % tr("%0 clients").arg(m_relaisServer->clients().count()) % "</p>";
output.append("<table border=\"1\">");
output.append("<thead>");
output.append("<tr>");
output.append("<th>IP-Adress</th>");
output.append("<th>Name</th>");
output.append("<th>Status</th>");
output.append("<th>Actions</th>");
output.append("</tr>");
output.append("</thead>");
output.append("<tbody>");
for(auto client : m_relaisServer->clients())
{
output.append("<tr>");
output.append("<td>" % client->peerAddress().toString() % ':' % QString::number(client->peerPort()) % "</td>");
output.append("<td>" % client->name() % "</td>");
output.append("<td>" % client->status() % "</td>");
if(!client->name().isEmpty())
{
output.append("<td><a href=\"/devices/" % client->name().toHtmlEscaped() % "/toggle\">" % tr("toggle") % "</a> ");
if(client->status() != QStringLiteral("on"))
output.append("<a href=\"/devices/" % client->name().toHtmlEscaped() % "/on\">" % tr("on") % "</a> ");
if(client->status() != QStringLiteral("off"))
output.append("<a href=\"/devices/" % client->name().toHtmlEscaped() % "/off\">" % tr("off") % "</a> ");
output.append("</td>");
}
output.append("</tr>");
}
output.append("</tbody>");
output.append("</table>");
HttpResponse response;
response.protocol = request.protocol;
response.statusCode = HttpResponse::StatusCode::OK;
response.body = output.toUtf8();
response.headers.insert(QStringLiteral("Server"), QStringLiteral("Hatschi Server 1.0"));
response.headers.insert(QStringLiteral("Content-Type"), QStringLiteral("text/html"));
connection->sendResponse(response);
}
void RelaisWebserver::redirectRoot(HttpClientConnection *connection, const HttpRequest &request)
{
HttpResponse response;
response.protocol = request.protocol;
response.statusCode = HttpResponse::StatusCode::Found;
response.body = QByteArrayLiteral("<a href=\"/\">Follow this link</a>");
response.headers.insert(QStringLiteral("Server"), QStringLiteral("Hatschi Server 1.0"));
response.headers.insert(QStringLiteral("Content-Type"), QStringLiteral("text/html"));
response.headers.insert(QStringLiteral("Location"), QStringLiteral("/"));
connection->sendResponse(response);
}
void RelaisWebserver::handle404(HttpClientConnection *connection, const HttpRequest &request)
{
HttpResponse response;
response.protocol = request.protocol;
response.statusCode = HttpResponse::StatusCode::NotFound;
response.body = "Not Found";
response.headers.insert(QStringLiteral("Server"), QStringLiteral("Hatschi Server 1.0"));
response.headers.insert(QStringLiteral("Content-Type"), QStringLiteral("text/html"));
connection->sendResponse(response);
}

27
relaiswebserver.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <QObject>
#include "httpserver.h"
class RelaisServer;
class HttpClientConnection;
class HttpRequest;
class RelaisWebserver : public HttpServer
{
Q_OBJECT
public:
explicit RelaisWebserver(RelaisServer *relaisServer, QObject *parent = Q_NULLPTR);
protected:
void handleRequest(HttpClientConnection *connection, const HttpRequest &request) Q_DECL_OVERRIDE;
private:
void handleRoot(HttpClientConnection *connection, const HttpRequest &request);
void redirectRoot(HttpClientConnection *connection, const HttpRequest &request);
void handle404(HttpClientConnection *connection, const HttpRequest &request);
RelaisServer *m_relaisServer;
};