diff options
-rw-r--r-- | CMakeLists.txt | 32 | ||||
-rw-r--r-- | client/CMakeLists.txt | 14 | ||||
-rw-r--r-- | client/main.cpp | 19 | ||||
-rw-r--r-- | client/resourceaccess.cpp | 95 | ||||
-rw-r--r-- | client/resourceaccess.h | 33 | ||||
-rw-r--r-- | common/console.cpp | 48 | ||||
-rw-r--r-- | common/console.h | 20 | ||||
-rw-r--r-- | resource/CMakeLists.txt | 15 | ||||
-rw-r--r-- | resource/listener.cpp | 71 | ||||
-rw-r--r-- | resource/listener.h | 37 | ||||
-rw-r--r-- | resource/main.cpp | 23 |
11 files changed, 407 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..469c5c3 --- /dev/null +++ b/CMakeLists.txt | |||
@@ -0,0 +1,32 @@ | |||
1 | cmake_minimum_required(VERSION 2.8) | ||
2 | |||
3 | # ECM setup | ||
4 | find_package(ECM 0.0.10 REQUIRED NO_MODULE) | ||
5 | set(CMAKE_MODULE_PATH | ||
6 | ${ECM_MODULE_PATH} | ||
7 | # ${ECM_KDE_MODULE_DIR} | ||
8 | ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules | ||
9 | ${CMAKE_MODULE_PATH}) | ||
10 | |||
11 | include(FeatureSummary) | ||
12 | include(GenerateExportHeader) | ||
13 | #include(ECMSetupVersion) | ||
14 | include(ECMGenerateHeaders) | ||
15 | include(ECMPackageConfigHelpers) | ||
16 | # include(KDEInstallDirs) | ||
17 | # include(KDEFrameworkCompilerSettings) | ||
18 | # include(KDECMakeSettings) | ||
19 | |||
20 | find_package(Qt5Core REQUIRED) | ||
21 | |||
22 | set(CMAKE_AUTOMOC ON) | ||
23 | add_definitions("-Wall -std=c++0x") | ||
24 | include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}) | ||
25 | |||
26 | # the client | ||
27 | add_subdirectory(client) | ||
28 | |||
29 | # the resource | ||
30 | add_subdirectory(resource) | ||
31 | |||
32 | 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 @@ | |||
1 | project(toynadi_client) | ||
2 | |||
3 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) | ||
4 | |||
5 | set(common_path "../common/") | ||
6 | |||
7 | set(toynadiclient_SRCS | ||
8 | ${common_path}/console.cpp | ||
9 | main.cpp | ||
10 | resourceaccess.cpp | ||
11 | ) | ||
12 | add_executable(${PROJECT_NAME} ${toynadiclient_SRCS}) | ||
13 | qt5_use_modules(${PROJECT_NAME} Widgets Network) | ||
14 | 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 @@ | |||
1 | |||
2 | #include <QApplication> | ||
3 | |||
4 | #include "common/console.h" | ||
5 | #include "resourceaccess.h" | ||
6 | |||
7 | int main(int argc, char *argv[]) | ||
8 | { | ||
9 | QApplication app(argc, argv); | ||
10 | |||
11 | new Console("Toy Client"); | ||
12 | ResourceAccess *resAccess = new ResourceAccess("toyResource"); | ||
13 | |||
14 | QObject::connect(&app, &QCoreApplication::aboutToQuit, | ||
15 | resAccess, &ResourceAccess::close); | ||
16 | |||
17 | resAccess->open(); | ||
18 | return app.exec(); | ||
19 | } \ 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 @@ | |||
1 | #include "resourceaccess.h" | ||
2 | |||
3 | #include "common/console.h" | ||
4 | |||
5 | #include <QDebug> | ||
6 | #include <QProcess> | ||
7 | |||
8 | ResourceAccess::ResourceAccess(const QString &resourceName, QObject *parent) | ||
9 | : QObject(parent), | ||
10 | m_resourceName(resourceName), | ||
11 | m_socket(new QLocalSocket(this)), | ||
12 | m_startingProcess(false) | ||
13 | { | ||
14 | Console::main()->log(QString("Starting access to %1").arg(m_socket->serverName())); | ||
15 | connect(m_socket, &QLocalSocket::connected, | ||
16 | this, &ResourceAccess::connected); | ||
17 | connect(m_socket, &QLocalSocket::disconnected, | ||
18 | this, &ResourceAccess::disconnected); | ||
19 | connect(m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)), | ||
20 | this, SLOT(connectionError(QLocalSocket::LocalSocketError))); | ||
21 | } | ||
22 | |||
23 | ResourceAccess::~ResourceAccess() | ||
24 | { | ||
25 | |||
26 | } | ||
27 | |||
28 | QString ResourceAccess::resourceName() const | ||
29 | { | ||
30 | return m_resourceName; | ||
31 | } | ||
32 | |||
33 | bool ResourceAccess::isReady() const | ||
34 | { | ||
35 | return m_socket->isValid(); | ||
36 | } | ||
37 | |||
38 | void ResourceAccess::open() | ||
39 | { | ||
40 | static int count = 0; | ||
41 | if (m_startingProcess) { | ||
42 | QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection); | ||
43 | } | ||
44 | |||
45 | if (m_socket->isValid()) { | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | ++count; | ||
50 | if (count > 10000) { | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | m_socket->setServerName(m_resourceName); | ||
55 | Console::main()->log(QString("Opening: %1").arg(m_socket->serverName())); | ||
56 | //FIXME: race between starting the exec and opening the socket? | ||
57 | m_socket->open(); | ||
58 | } | ||
59 | |||
60 | void ResourceAccess::close() | ||
61 | { | ||
62 | Console::main()->log(QString("Closing: %1").arg(m_socket->fullServerName())); | ||
63 | m_socket->close(); | ||
64 | } | ||
65 | |||
66 | void ResourceAccess::connected() | ||
67 | { | ||
68 | m_startingProcess = false; | ||
69 | Console::main()->log(QString("Connected: %1").arg(m_socket->fullServerName())); | ||
70 | emit ready(true); | ||
71 | } | ||
72 | |||
73 | void ResourceAccess::disconnected() | ||
74 | { | ||
75 | Console::main()->log(QString("Disconnected: %1").arg(m_socket->fullServerName())); | ||
76 | emit ready(false); | ||
77 | } | ||
78 | |||
79 | void ResourceAccess::connectionError(QLocalSocket::LocalSocketError error) | ||
80 | { | ||
81 | Console::main()->log(QString("Could not connect to %1 due to error %2").arg(m_socket->serverName()).arg(error)); | ||
82 | if (m_startingProcess) { | ||
83 | QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection); | ||
84 | return; | ||
85 | } | ||
86 | |||
87 | m_startingProcess = true; | ||
88 | Console::main()->log(QString("Attempting to start resource...")); | ||
89 | QStringList args; | ||
90 | args << m_resourceName; | ||
91 | if (QProcess::startDetached("toynadi_resource", args)) { | ||
92 | m_socket->open(); | ||
93 | } | ||
94 | } | ||
95 | |||
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 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <QLocalSocket> | ||
4 | #include <QObject> | ||
5 | |||
6 | class ResourceAccess : public QObject | ||
7 | { | ||
8 | Q_OBJECT | ||
9 | |||
10 | public: | ||
11 | ResourceAccess(const QString &resourceName, QObject *parent = 0); | ||
12 | ~ResourceAccess(); | ||
13 | |||
14 | QString resourceName() const; | ||
15 | bool isReady() const; | ||
16 | |||
17 | public Q_SLOTS: | ||
18 | void open(); | ||
19 | void close(); | ||
20 | |||
21 | Q_SIGNALS: | ||
22 | void ready(bool isReady); | ||
23 | |||
24 | private Q_SLOTS: | ||
25 | void connected(); | ||
26 | void disconnected(); | ||
27 | void connectionError(QLocalSocket::LocalSocketError error); | ||
28 | |||
29 | private: | ||
30 | QString m_resourceName; | ||
31 | QLocalSocket *m_socket; | ||
32 | bool m_startingProcess; | ||
33 | }; | ||
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 @@ | |||
1 | #include "console.h" | ||
2 | |||
3 | #include <QLabel> | ||
4 | #include <QTextBrowser> | ||
5 | #include <QVBoxLayout> | ||
6 | |||
7 | static Console *s_console = 0; | ||
8 | |||
9 | Console *Console::main() | ||
10 | { | ||
11 | if (!s_console) { | ||
12 | s_console = new Console("Stupido!"); | ||
13 | } | ||
14 | return s_console; | ||
15 | } | ||
16 | |||
17 | Console::Console(const QString &title) | ||
18 | : QWidget(0) | ||
19 | { | ||
20 | s_console = this; | ||
21 | resize(1000, 1500); | ||
22 | |||
23 | QVBoxLayout *topLayout = new QVBoxLayout(this); | ||
24 | |||
25 | QLabel *titleLabel = new QLabel(this); | ||
26 | titleLabel->setText(title); | ||
27 | QFont font = titleLabel->font(); | ||
28 | font.setWeight(QFont::Bold); | ||
29 | titleLabel->setFont(font); | ||
30 | titleLabel->setAlignment(Qt::AlignCenter); | ||
31 | |||
32 | m_textDisplay = new QTextBrowser(this); | ||
33 | |||
34 | topLayout->addWidget(titleLabel); | ||
35 | topLayout->addWidget(m_textDisplay, 10); | ||
36 | |||
37 | show(); | ||
38 | } | ||
39 | |||
40 | Console::~Console() | ||
41 | { | ||
42 | |||
43 | } | ||
44 | |||
45 | void Console::log(const QString &message) | ||
46 | { | ||
47 | m_textDisplay->append(message); | ||
48 | } | ||
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 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <QWidget> | ||
4 | |||
5 | class QTextBrowser; | ||
6 | |||
7 | class Console : public QWidget | ||
8 | { | ||
9 | Q_OBJECT | ||
10 | public: | ||
11 | static Console *main(); | ||
12 | Console(const QString &title); | ||
13 | ~Console(); | ||
14 | |||
15 | void log(const QString &message); | ||
16 | |||
17 | private: | ||
18 | QTextBrowser *m_textDisplay; | ||
19 | static Console *s_output; | ||
20 | }; \ 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 @@ | |||
1 | project(toynadi_resource) | ||
2 | |||
3 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) | ||
4 | |||
5 | set(common_path "../common/") | ||
6 | |||
7 | set(toynadiresource_SRCS | ||
8 | ${common_path}/console.cpp | ||
9 | main.cpp | ||
10 | listener.cpp | ||
11 | ) | ||
12 | |||
13 | add_executable(${PROJECT_NAME} ${toynadiresource_SRCS}) | ||
14 | qt5_use_modules(${PROJECT_NAME} Widgets Network) | ||
15 | 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 @@ | |||
1 | #include "listener.h" | ||
2 | |||
3 | #include "common/console.h" | ||
4 | |||
5 | #include <QLocalSocket> | ||
6 | |||
7 | Listener::Listener(const QString &resource, QObject *parent) | ||
8 | : QObject(parent), | ||
9 | m_server(new QLocalServer(this)) | ||
10 | { | ||
11 | connect(m_server, &QLocalServer::newConnection, | ||
12 | this, &Listener::acceptConnection); | ||
13 | Console::main()->log(QString("Trying to open %1").arg(resource)); | ||
14 | if (!m_server->listen(resource)) { | ||
15 | // FIXME: multiple starts need to be handled here | ||
16 | m_server->removeServer(resource); | ||
17 | if (!m_server->listen(resource)) { | ||
18 | Console::main()->log("Utter failure to start server"); | ||
19 | exit(-1); | ||
20 | } | ||
21 | } | ||
22 | |||
23 | if (m_server->isListening()) { | ||
24 | Console::main()->log(QString("Listening on %1").arg(m_server->serverName())); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | Listener::~Listener() | ||
29 | { | ||
30 | } | ||
31 | |||
32 | void Listener::closeAllConnections() | ||
33 | { | ||
34 | //TODO: close all client connectionsin m_connections | ||
35 | } | ||
36 | |||
37 | void Listener::acceptConnection() | ||
38 | { | ||
39 | Console::main()->log(QString("Accepting connection")); | ||
40 | QLocalSocket *connection = m_server->nextPendingConnection(); | ||
41 | |||
42 | if (!connection) { | ||
43 | return; | ||
44 | } | ||
45 | |||
46 | Console::main()->log("Got a connection"); | ||
47 | Client client(connection); | ||
48 | m_connections << client; | ||
49 | connect(connection, &QLocalSocket::disconnected, | ||
50 | this, &Listener::clientDropped); | ||
51 | |||
52 | } | ||
53 | |||
54 | void Listener::clientDropped() | ||
55 | { | ||
56 | QLocalSocket *connection = qobject_cast<QLocalSocket *>(sender()); | ||
57 | if (!connection) { | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | Console::main()->log("Dropping connection..."); | ||
62 | QMutableListIterator<Client> it(m_connections); | ||
63 | while (it.hasNext()) { | ||
64 | const Client &client = it.next(); | ||
65 | if (client.m_socket == connection) { | ||
66 | Console::main()->log(" dropped..."); | ||
67 | it.remove(); | ||
68 | break; | ||
69 | } | ||
70 | } | ||
71 | } | ||
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 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <QLocalServer> | ||
4 | #include <QLocalSocket> | ||
5 | #include <QList> | ||
6 | #include <QObject> | ||
7 | |||
8 | class Client | ||
9 | { | ||
10 | public: | ||
11 | Client(QLocalSocket *s) | ||
12 | : m_socket(s), | ||
13 | m_commanded(false) | ||
14 | { | ||
15 | } | ||
16 | |||
17 | QLocalSocket *m_socket; | ||
18 | bool m_commanded; | ||
19 | }; | ||
20 | |||
21 | class Listener : public QObject | ||
22 | { | ||
23 | public: | ||
24 | Listener(const QString &resourceName, QObject *parent = 0); | ||
25 | ~Listener(); | ||
26 | |||
27 | public Q_SLOTS: | ||
28 | void closeAllConnections(); | ||
29 | |||
30 | private Q_SLOTS: | ||
31 | void acceptConnection(); | ||
32 | void clientDropped(); | ||
33 | |||
34 | private: | ||
35 | QLocalServer *m_server; | ||
36 | QList<Client> m_connections; | ||
37 | }; \ 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 @@ | |||
1 | |||
2 | #include <QApplication> | ||
3 | |||
4 | #include "common/console.h" | ||
5 | #include "listener.h" | ||
6 | |||
7 | int main(int argc, char *argv[]) | ||
8 | { | ||
9 | QApplication app(argc, argv); | ||
10 | |||
11 | new Console(QString("Toy Resource: %1").arg(argv[1])); | ||
12 | if (argc < 2) { | ||
13 | Console::main()->log("Not enough args"); | ||
14 | return app.exec(); | ||
15 | } | ||
16 | |||
17 | Listener *listener = new Listener(argv[1]); | ||
18 | |||
19 | QObject::connect(&app, &QCoreApplication::aboutToQuit, | ||
20 | listener, &Listener::closeAllConnections); | ||
21 | |||
22 | return app.exec(); | ||
23 | } \ No newline at end of file | ||