diff --git a/guh.pri b/guh.pri index a4958934..82ebc9d0 100644 --- a/guh.pri +++ b/guh.pri @@ -13,11 +13,15 @@ QT+= network websockets QMAKE_CXXFLAGS += -Werror -std=c++11 -g QMAKE_LFLAGS += -std=c++11 -#QMAKE_CXX = g++ ccache top_srcdir=$$PWD top_builddir=$$shadowed($$PWD) +# Check if ccache is enabled +ccache { + QMAKE_CXX = ccache g++ +} + # Check for Bluetoot LE support (Qt >= 5.4) equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 3) { QT += bluetooth diff --git a/server/bluetoothserver.cpp b/server/bluetoothserver.cpp index 9054fe39..fc0582f5 100644 --- a/server/bluetoothserver.cpp +++ b/server/bluetoothserver.cpp @@ -18,6 +18,22 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/*! + \class guhserver::BluetoothServer + \brief This class represents the bluetooth server for guhd. + + \ingroup server + \inmodule core + + \inherits TransportInterface + + The bluetooth server allowes clients to connect to the JSON-RPC API using an RFCOMM bluetooth connection. If the server is enabled, a client + can discover the services running on this host. The service for the JSON-RPC api is called \tt guhIO and has the uuid \tt 997936b5-d2cd-4c57-b41b-c6048320cd2b . + + \sa TransportInterface +*/ + + #include "bluetoothserver.h" #include "loggingcategories.h" @@ -26,7 +42,7 @@ namespace guhserver { -static const QLatin1String serviceUuid("81679f09-1404-4242-b685-a7f7e23df8cf"); +static const QBluetoothUuid serviceUuid(QUuid("997936b5-d2cd-4c57-b41b-c6048320cd2b")); BluetoothServer::BluetoothServer(QObject *parent) : TransportInterface(parent), @@ -37,6 +53,9 @@ BluetoothServer::BluetoothServer(QObject *parent) : BluetoothServer::~BluetoothServer() { + if (m_server && m_server->isListening()) + qCDebug(dcApplication) << "Shutting down \"Bluetooth server\""; + stopServer(); } @@ -51,7 +70,7 @@ void BluetoothServer::sendData(const QUuid &clientId, const QVariantMap &data) QBluetoothSocket *client = 0; client = m_clientList.value(clientId); if (client) - client->write(QJsonDocument::fromVariant(data).toJson() + "\n"); + client->write(QJsonDocument::fromVariant(data).toJson(QJsonDocument::Compact) + '\n'); } void BluetoothServer::sendData(const QList &clients, const QVariantMap &data) @@ -101,9 +120,15 @@ void BluetoothServer::readData() if (!client) return; + QByteArray message; while (client->canReadLine()) { - QByteArray line = client->readLine().trimmed(); - qCDebug(dcConnection()) << "Bluetooth server: line in:" << QString::fromUtf8(line.constData(), line.length()); + QByteArray dataLine = client->readLine(); + message.append(dataLine); + if (dataLine.endsWith('\n')) { + qCDebug(dcConnection()) << "Bluetooth data received:" << message; + validateMessage(m_clientList.key(client), message); + message.clear(); + } } } @@ -115,9 +140,8 @@ bool BluetoothServer::startServer() // Check if Bluetooth is available on this device QBluetoothLocalDevice localDevice; if (localDevice.isValid()) { - // Turn Bluetooth on + qCDebug(dcConnection()) << "Bluetooth: using adapter" << localDevice.name() << localDevice.address().toString(); localDevice.powerOn(); - // Make it visible to others localDevice.setHostMode(QBluetoothLocalDevice::HostDiscoverable); } else { qCWarning(dcConnection()) << "Bluetooth server: could find any bluetooth hardware"; @@ -133,33 +157,41 @@ bool BluetoothServer::startServer() qCDebug(dcConnection) << "Started bluetooth server" << m_server->serverAddress().toString(); + // Set service attributes + QBluetoothServiceInfo::Sequence browseSequence; + browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, browseSequence); + QBluetoothServiceInfo::Sequence classId; classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)); m_serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList, classId); - - classId.prepend(QVariant::fromValue(QBluetoothUuid(serviceUuid))); + classId.prepend(QVariant::fromValue(serviceUuid)); m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::BluetoothProfileDescriptorList,classId); - m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, tr("guhIO JSON-RPC")); - m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription, tr("The JSON-RPC interface for guhIO.")); - m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceProvider, "guh.io"); - m_serviceInfo.setServiceUuid(QBluetoothUuid(serviceUuid)); - - QBluetoothServiceInfo::Sequence publicBrowse; - publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)); - m_serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, publicBrowse); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, QVariant("guhIO")); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceDescription, QVariant("The JSON-RPC interface for guhIO.")); + m_serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceProvider, QVariant("https://guh.io")); + // Define protocol QBluetoothServiceInfo::Sequence protocolDescriptorList; QBluetoothServiceInfo::Sequence protocol; - protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap)); - protocolDescriptorList.append(QVariant::fromValue(protocol)); - protocol.clear(); protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm)) << QVariant::fromValue(quint8(m_server->serverPort())); protocolDescriptorList.append(QVariant::fromValue(protocol)); m_serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList); - m_serviceInfo.registerService(localDevice.address()); + + // Set UUID + m_serviceInfo.setServiceUuid(serviceUuid); + + // Register the service in the local device + if (!m_serviceInfo.registerService(localDevice.address())) { + qCWarning(dcConnection()) << "Bluetooth: Could not register service" << m_serviceInfo.serviceName() << serviceUuid.toString(); + return false; + } + + qCDebug(dcConnection()) << "Bluetooth: Registered successfully service" << m_serviceInfo.serviceName() << serviceUuid.toString(); return true; } @@ -169,10 +201,16 @@ bool BluetoothServer::stopServer() client->close(); } + if (!m_server) + return true; + + m_serviceInfo.unregisterService(); + m_server->close(); m_server->deleteLater(); m_server = 0; return true; } + } diff --git a/server/guhcore.cpp b/server/guhcore.cpp index 23c71419..98126135 100644 --- a/server/guhcore.cpp +++ b/server/guhcore.cpp @@ -438,11 +438,13 @@ GuhCore::GuhCore(QObject *parent) : m_serverManager->jsonServer()->registerTransportInterface(m_tcpServer); m_serverManager->jsonServer()->registerTransportInterface(m_webSocketServer); m_serverManager->jsonServer()->registerTransportInterface(m_cloudManager); - m_serverManager->jsonServer()->registerTransportInterface(m_bluetoothServer); + m_serverManager->jsonServer()->registerTransportInterface(m_bluetoothServer, m_configuration->bluetoothServerEnabled()); + // Webserver setup m_webServer = new WebServer(m_configuration->webServerAddress(), m_configuration->webServerPort(), m_configuration->webServerPublicFolder(), this); m_serverManager->restServer()->registerWebserver(m_webServer); + // Connect the configuration changes connect(m_configuration, &GuhConfiguration::cloudEnabledChanged, m_cloudManager, &CloudManager::onCloudEnabledChanged); connect(m_configuration, &GuhConfiguration::cloudProxyServerChanged, m_cloudManager, &CloudManager::onProxyServerUrlChanged); diff --git a/server/jsonrpc/actionhandler.h b/server/jsonrpc/actionhandler.h index 4cf9abd9..d8026847 100644 --- a/server/jsonrpc/actionhandler.h +++ b/server/jsonrpc/actionhandler.h @@ -35,15 +35,14 @@ public: QString name() const; - Q_INVOKABLE JsonReply* ExecuteAction(const QVariantMap ¶ms); - - Q_INVOKABLE JsonReply* GetActionType(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *ExecuteAction(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetActionType(const QVariantMap ¶ms) const; private slots: void actionExecuted(const ActionId &id, DeviceManager::DeviceError status); private: - QHash m_asyncActionExecutions; + QHash m_asyncActionExecutions; }; } diff --git a/server/jsonrpc/cloudhandler.h b/server/jsonrpc/cloudhandler.h index 280de747..f9cce8cf 100644 --- a/server/jsonrpc/cloudhandler.h +++ b/server/jsonrpc/cloudhandler.h @@ -37,8 +37,13 @@ public: QString name() const; - Q_INVOKABLE JsonReply* Authenticate(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply* GetConnectionStatus(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *Authenticate(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetConnectionStatus(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *Enable(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *Disable(const QVariantMap ¶ms) const; + +private: + QList m_asyncAuthenticationReplies; signals: void ConnectionStatusChanged(const QVariantMap ¶ms); diff --git a/server/jsonrpc/configurationhandler.h b/server/jsonrpc/configurationhandler.h index c6754a40..4c55005a 100644 --- a/server/jsonrpc/configurationhandler.h +++ b/server/jsonrpc/configurationhandler.h @@ -35,13 +35,13 @@ public: ConfigurationHandler(QObject *parent = 0); QString name() const; - Q_INVOKABLE JsonReply* GetConfigurations(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply* GetTimeZones(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply* SetServerName(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply* SetTimeZone(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply* SetTcpServerConfiguration(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetConfigurations(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetTimeZones(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetServerName(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetTimeZone(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetTcpServerConfiguration(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetWebServerConfiguration(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply* SetWebSocketServerConfiguration(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetWebSocketServerConfiguration(const QVariantMap ¶ms) const; signals: void BasicConfigurationChanged(const QVariantMap ¶ms); diff --git a/server/jsonrpc/devicehandler.h b/server/jsonrpc/devicehandler.h index 55157c3c..e74f01b9 100644 --- a/server/jsonrpc/devicehandler.h +++ b/server/jsonrpc/devicehandler.h @@ -35,41 +35,26 @@ public: QString name() const override; - Q_INVOKABLE JsonReply* GetSupportedVendors(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetSupportedVendors(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetSupportedDevices(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetDiscoveredDevices(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetPlugins(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetPluginConfiguration(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetPluginConfiguration(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* GetSupportedDevices(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *AddConfiguredDevice(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *PairDevice(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *ConfirmPairing(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetConfiguredDevices(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *ReconfigureDevice(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *EditDevice(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *RemoveConfiguredDevice(const QVariantMap ¶ms); - Q_INVOKABLE JsonReply* GetDiscoveredDevices(const QVariantMap ¶ms) const; - - Q_INVOKABLE JsonReply* GetPlugins(const QVariantMap ¶ms) const; - - Q_INVOKABLE JsonReply* GetPluginConfiguration(const QVariantMap ¶ms) const; - - Q_INVOKABLE JsonReply* SetPluginConfiguration(const QVariantMap ¶ms); - - Q_INVOKABLE JsonReply* AddConfiguredDevice(const QVariantMap ¶ms); - - Q_INVOKABLE JsonReply* PairDevice(const QVariantMap ¶ms); - - Q_INVOKABLE JsonReply* ConfirmPairing(const QVariantMap ¶ms); - - Q_INVOKABLE JsonReply* GetConfiguredDevices(const QVariantMap ¶ms) const; - - Q_INVOKABLE JsonReply* ReconfigureDevice(const QVariantMap ¶ms); - - Q_INVOKABLE JsonReply* EditDevice(const QVariantMap ¶ms); - - Q_INVOKABLE JsonReply* RemoveConfiguredDevice(const QVariantMap ¶ms); - - Q_INVOKABLE JsonReply* GetEventTypes(const QVariantMap ¶ms) const; - - Q_INVOKABLE JsonReply* GetActionTypes(const QVariantMap ¶ms) const; - - Q_INVOKABLE JsonReply* GetStateTypes(const QVariantMap ¶ms) const; - - Q_INVOKABLE JsonReply* GetStateValue(const QVariantMap ¶ms) const; - - Q_INVOKABLE JsonReply* GetStateValues(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetEventTypes(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetActionTypes(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetStateTypes(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetStateValue(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetStateValues(const QVariantMap ¶ms) const; signals: void StateChanged(const QVariantMap ¶ms); diff --git a/server/jsonrpc/eventhandler.h b/server/jsonrpc/eventhandler.h index 70ba691a..90c7b488 100644 --- a/server/jsonrpc/eventhandler.h +++ b/server/jsonrpc/eventhandler.h @@ -34,6 +34,7 @@ public: QString name() const override; Q_INVOKABLE JsonReply *GetEventType(const QVariantMap ¶ms) const; + signals: void EventTriggered(const QVariantMap ¶ms); diff --git a/server/jsonrpc/jsonhandler.h b/server/jsonrpc/jsonhandler.h index c90fef79..8b011d60 100644 --- a/server/jsonrpc/jsonhandler.h +++ b/server/jsonrpc/jsonhandler.h @@ -42,8 +42,8 @@ public: TypeAsync }; - static JsonReply* createReply(JsonHandler *handler, const QVariantMap &data); - static JsonReply* createAsyncReply(JsonHandler *handler, const QString &method); + static JsonReply *createReply(JsonHandler *handler, const QVariantMap &data); + static JsonReply *createAsyncReply(JsonHandler *handler, const QString &method); Type type() const; QVariantMap data() const; diff --git a/server/jsonrpc/jsonrpcserver.cpp b/server/jsonrpc/jsonrpcserver.cpp index 74b8b02f..fdd4f181 100644 --- a/server/jsonrpc/jsonrpcserver.cpp +++ b/server/jsonrpc/jsonrpcserver.cpp @@ -150,14 +150,15 @@ QHash JsonRPCServer::handlers() const return m_handlers; } -void JsonRPCServer::registerTransportInterface(TransportInterface *interface) +void JsonRPCServer::registerTransportInterface(TransportInterface *interface, const bool &enabled) { // Now set up the logic connect(interface, SIGNAL(clientConnected(const QUuid &)), this, SLOT(clientConnected(const QUuid &))); connect(interface, SIGNAL(clientDisconnected(const QUuid &)), this, SLOT(clientDisconnected(const QUuid &))); connect(interface, SIGNAL(dataAvailable(QUuid, QString, QString, QVariantMap)), this, SLOT(processData(QUuid, QString, QString, QVariantMap))); - QMetaObject::invokeMethod(interface, "startServer", Qt::QueuedConnection); + if (enabled) + QMetaObject::invokeMethod(interface, "startServer", Qt::QueuedConnection); m_interfaces.append(interface); } diff --git a/server/jsonrpc/jsonrpcserver.h b/server/jsonrpc/jsonrpcserver.h index 09b10eab..e6e0570f 100644 --- a/server/jsonrpc/jsonrpcserver.h +++ b/server/jsonrpc/jsonrpcserver.h @@ -46,13 +46,13 @@ public: // JsonHandler API implementation QString name() const; - Q_INVOKABLE JsonReply* Introspect(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply* Version(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply* SetNotificationStatus(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *Introspect(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *Version(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetNotificationStatus(const QVariantMap ¶ms); - QHash handlers() const; + QHash handlers() const; - void registerTransportInterface(TransportInterface *interface); + void registerTransportInterface(TransportInterface *interface, const bool &enabled = true); private slots: void setup(); diff --git a/server/jsonrpc/logginghandler.h b/server/jsonrpc/logginghandler.h index 6d5a8faf..02a53028 100644 --- a/server/jsonrpc/logginghandler.h +++ b/server/jsonrpc/logginghandler.h @@ -35,6 +35,7 @@ public: QString name() const override; Q_INVOKABLE JsonReply *GetLogEntries(const QVariantMap ¶ms) const; + signals: void LogEntryAdded(const QVariantMap ¶ms); void LogDatabaseUpdated(const QVariantMap ¶ms); diff --git a/server/jsonrpc/statehandler.h b/server/jsonrpc/statehandler.h index e738a1d8..e3cbc959 100644 --- a/server/jsonrpc/statehandler.h +++ b/server/jsonrpc/statehandler.h @@ -34,6 +34,7 @@ public: QString name() const override; Q_INVOKABLE JsonReply *GetStateType(const QVariantMap ¶ms) const; + }; }