From ed20c3082d4fd5e90703e4d6c37093dcecb5cfd1 Mon Sep 17 00:00:00 2001 From: Aaron Seigo Date: Thu, 20 Nov 2014 16:28:31 +0100 Subject: sketch in the client/resource model --- CMakeLists.txt | 32 ++++++++++++++++ client/CMakeLists.txt | 14 +++++++ client/main.cpp | 19 ++++++++++ client/resourceaccess.cpp | 95 +++++++++++++++++++++++++++++++++++++++++++++++ client/resourceaccess.h | 33 ++++++++++++++++ common/console.cpp | 48 ++++++++++++++++++++++++ common/console.h | 20 ++++++++++ resource/CMakeLists.txt | 15 ++++++++ resource/listener.cpp | 71 +++++++++++++++++++++++++++++++++++ resource/listener.h | 37 ++++++++++++++++++ resource/main.cpp | 23 ++++++++++++ 11 files changed, 407 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 client/CMakeLists.txt create mode 100644 client/main.cpp create mode 100644 client/resourceaccess.cpp create mode 100644 client/resourceaccess.h create mode 100644 common/console.cpp create mode 100644 common/console.h create mode 100644 resource/CMakeLists.txt create mode 100644 resource/listener.cpp create mode 100644 resource/listener.h create mode 100644 resource/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..469c5c3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 2.8) + +# ECM setup +find_package(ECM 0.0.10 REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH + ${ECM_MODULE_PATH} + # ${ECM_KDE_MODULE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules + ${CMAKE_MODULE_PATH}) + +include(FeatureSummary) +include(GenerateExportHeader) +#include(ECMSetupVersion) +include(ECMGenerateHeaders) +include(ECMPackageConfigHelpers) +# include(KDEInstallDirs) +# include(KDEFrameworkCompilerSettings) +# include(KDECMakeSettings) + +find_package(Qt5Core REQUIRED) + +set(CMAKE_AUTOMOC ON) +add_definitions("-Wall -std=c++0x") +include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}) + +# the client +add_subdirectory(client) + +# the resource +add_subdirectory(resource) + +feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 0000000..186e3fe --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,14 @@ +project(toynadi_client) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +set(common_path "../common/") + +set(toynadiclient_SRCS + ${common_path}/console.cpp + main.cpp + resourceaccess.cpp +) +add_executable(${PROJECT_NAME} ${toynadiclient_SRCS}) +qt5_use_modules(${PROJECT_NAME} Widgets Network) +install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/client/main.cpp b/client/main.cpp new file mode 100644 index 0000000..2fbb8fe --- /dev/null +++ b/client/main.cpp @@ -0,0 +1,19 @@ + +#include + +#include "common/console.h" +#include "resourceaccess.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + new Console("Toy Client"); + ResourceAccess *resAccess = new ResourceAccess("toyResource"); + + QObject::connect(&app, &QCoreApplication::aboutToQuit, + resAccess, &ResourceAccess::close); + + resAccess->open(); + return app.exec(); +} \ No newline at end of file diff --git a/client/resourceaccess.cpp b/client/resourceaccess.cpp new file mode 100644 index 0000000..1eadc34 --- /dev/null +++ b/client/resourceaccess.cpp @@ -0,0 +1,95 @@ +#include "resourceaccess.h" + +#include "common/console.h" + +#include +#include + +ResourceAccess::ResourceAccess(const QString &resourceName, QObject *parent) + : QObject(parent), + m_resourceName(resourceName), + m_socket(new QLocalSocket(this)), + m_startingProcess(false) +{ + Console::main()->log(QString("Starting access to %1").arg(m_socket->serverName())); + connect(m_socket, &QLocalSocket::connected, + this, &ResourceAccess::connected); + connect(m_socket, &QLocalSocket::disconnected, + this, &ResourceAccess::disconnected); + connect(m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)), + this, SLOT(connectionError(QLocalSocket::LocalSocketError))); +} + +ResourceAccess::~ResourceAccess() +{ + +} + +QString ResourceAccess::resourceName() const +{ + return m_resourceName; +} + +bool ResourceAccess::isReady() const +{ + return m_socket->isValid(); +} + +void ResourceAccess::open() +{ + static int count = 0; + if (m_startingProcess) { + QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection); + } + + if (m_socket->isValid()) { + return; + } + + ++count; + if (count > 10000) { + return; + } + + m_socket->setServerName(m_resourceName); + Console::main()->log(QString("Opening: %1").arg(m_socket->serverName())); + //FIXME: race between starting the exec and opening the socket? + m_socket->open(); +} + +void ResourceAccess::close() +{ + Console::main()->log(QString("Closing: %1").arg(m_socket->fullServerName())); + m_socket->close(); +} + +void ResourceAccess::connected() +{ + m_startingProcess = false; + Console::main()->log(QString("Connected: %1").arg(m_socket->fullServerName())); + emit ready(true); +} + +void ResourceAccess::disconnected() +{ + Console::main()->log(QString("Disconnected: %1").arg(m_socket->fullServerName())); + emit ready(false); +} + +void ResourceAccess::connectionError(QLocalSocket::LocalSocketError error) +{ + Console::main()->log(QString("Could not connect to %1 due to error %2").arg(m_socket->serverName()).arg(error)); + if (m_startingProcess) { + QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection); + return; + } + + m_startingProcess = true; + Console::main()->log(QString("Attempting to start resource...")); + QStringList args; + args << m_resourceName; + if (QProcess::startDetached("toynadi_resource", args)) { + m_socket->open(); + } +} + diff --git a/client/resourceaccess.h b/client/resourceaccess.h new file mode 100644 index 0000000..f4c4ad4 --- /dev/null +++ b/client/resourceaccess.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +class ResourceAccess : public QObject +{ + Q_OBJECT + +public: + ResourceAccess(const QString &resourceName, QObject *parent = 0); + ~ResourceAccess(); + + QString resourceName() const; + bool isReady() const; + +public Q_SLOTS: + void open(); + void close(); + +Q_SIGNALS: + void ready(bool isReady); + +private Q_SLOTS: + void connected(); + void disconnected(); + void connectionError(QLocalSocket::LocalSocketError error); + +private: + QString m_resourceName; + QLocalSocket *m_socket; + bool m_startingProcess; +}; diff --git a/common/console.cpp b/common/console.cpp new file mode 100644 index 0000000..4ed7960 --- /dev/null +++ b/common/console.cpp @@ -0,0 +1,48 @@ +#include "console.h" + +#include +#include +#include + +static Console *s_console = 0; + +Console *Console::main() +{ + if (!s_console) { + s_console = new Console("Stupido!"); + } + return s_console; +} + +Console::Console(const QString &title) + : QWidget(0) +{ + s_console = this; + resize(1000, 1500); + + QVBoxLayout *topLayout = new QVBoxLayout(this); + + QLabel *titleLabel = new QLabel(this); + titleLabel->setText(title); + QFont font = titleLabel->font(); + font.setWeight(QFont::Bold); + titleLabel->setFont(font); + titleLabel->setAlignment(Qt::AlignCenter); + + m_textDisplay = new QTextBrowser(this); + + topLayout->addWidget(titleLabel); + topLayout->addWidget(m_textDisplay, 10); + + show(); +} + +Console::~Console() +{ + +} + +void Console::log(const QString &message) +{ + m_textDisplay->append(message); +} diff --git a/common/console.h b/common/console.h new file mode 100644 index 0000000..d504fb1 --- /dev/null +++ b/common/console.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +class QTextBrowser; + +class Console : public QWidget +{ + Q_OBJECT +public: + static Console *main(); + Console(const QString &title); + ~Console(); + + void log(const QString &message); + +private: + QTextBrowser *m_textDisplay; + static Console *s_output; +}; \ No newline at end of file diff --git a/resource/CMakeLists.txt b/resource/CMakeLists.txt new file mode 100644 index 0000000..3de51b5 --- /dev/null +++ b/resource/CMakeLists.txt @@ -0,0 +1,15 @@ +project(toynadi_resource) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +set(common_path "../common/") + +set(toynadiresource_SRCS + ${common_path}/console.cpp + main.cpp + listener.cpp +) + +add_executable(${PROJECT_NAME} ${toynadiresource_SRCS}) +qt5_use_modules(${PROJECT_NAME} Widgets Network) +install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/resource/listener.cpp b/resource/listener.cpp new file mode 100644 index 0000000..efdfe3e --- /dev/null +++ b/resource/listener.cpp @@ -0,0 +1,71 @@ +#include "listener.h" + +#include "common/console.h" + +#include + +Listener::Listener(const QString &resource, QObject *parent) + : QObject(parent), + m_server(new QLocalServer(this)) +{ + connect(m_server, &QLocalServer::newConnection, + this, &Listener::acceptConnection); + Console::main()->log(QString("Trying to open %1").arg(resource)); + if (!m_server->listen(resource)) { + // FIXME: multiple starts need to be handled here + m_server->removeServer(resource); + if (!m_server->listen(resource)) { + Console::main()->log("Utter failure to start server"); + exit(-1); + } + } + + if (m_server->isListening()) { + Console::main()->log(QString("Listening on %1").arg(m_server->serverName())); + } +} + +Listener::~Listener() +{ +} + +void Listener::closeAllConnections() +{ + //TODO: close all client connectionsin m_connections +} + +void Listener::acceptConnection() +{ + Console::main()->log(QString("Accepting connection")); + QLocalSocket *connection = m_server->nextPendingConnection(); + + if (!connection) { + return; + } + + Console::main()->log("Got a connection"); + Client client(connection); + m_connections << client; + connect(connection, &QLocalSocket::disconnected, + this, &Listener::clientDropped); + +} + +void Listener::clientDropped() +{ + QLocalSocket *connection = qobject_cast(sender()); + if (!connection) { + return; + } + + Console::main()->log("Dropping connection..."); + QMutableListIterator it(m_connections); + while (it.hasNext()) { + const Client &client = it.next(); + if (client.m_socket == connection) { + Console::main()->log(" dropped..."); + it.remove(); + break; + } + } +} diff --git a/resource/listener.h b/resource/listener.h new file mode 100644 index 0000000..79c7ba5 --- /dev/null +++ b/resource/listener.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +class Client +{ +public: + Client(QLocalSocket *s) + : m_socket(s), + m_commanded(false) + { + } + + QLocalSocket *m_socket; + bool m_commanded; +}; + +class Listener : public QObject +{ +public: + Listener(const QString &resourceName, QObject *parent = 0); + ~Listener(); + +public Q_SLOTS: + void closeAllConnections(); + +private Q_SLOTS: + void acceptConnection(); + void clientDropped(); + +private: + QLocalServer *m_server; + QList m_connections; +}; \ No newline at end of file diff --git a/resource/main.cpp b/resource/main.cpp new file mode 100644 index 0000000..3bd4656 --- /dev/null +++ b/resource/main.cpp @@ -0,0 +1,23 @@ + +#include + +#include "common/console.h" +#include "listener.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + new Console(QString("Toy Resource: %1").arg(argv[1])); + if (argc < 2) { + Console::main()->log("Not enough args"); + return app.exec(); + } + + Listener *listener = new Listener(argv[1]); + + QObject::connect(&app, &QCoreApplication::aboutToQuit, + listener, &Listener::closeAllConnections); + + return app.exec(); +} \ No newline at end of file -- cgit v1.2.3