Added WifiLamp server code
This commit is contained in:
73
.gitignore
vendored
Normal file
73
.gitignore
vendored
Normal 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
17
WifiLamp.pro
Normal 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
26
main.cpp
Normal 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
93
relaisclient.cpp
Normal 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
43
relaisclient.h
Normal 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
113
relaisserver.cpp
Normal 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
61
relaisserver.h
Normal 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
161
relaiswebserver.cpp
Normal 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
27
relaiswebserver.h
Normal 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;
|
||||
};
|
Reference in New Issue
Block a user