Start implementation of Remote IO
Finished server creation, implemented two commands: listwindow, selectwindow Ideally, all the UI should be possible manipulated by remote IO, a local TCP/IP connection, this could be useful to make a VR front end for Dust3D.master
parent
a1249f5fcb
commit
ceeccc7211
|
@ -1,4 +1,4 @@
|
||||||
QT += core widgets opengl
|
QT += core widgets opengl network
|
||||||
CONFIG += release
|
CONFIG += release
|
||||||
DEFINES += NDEBUG
|
DEFINES += NDEBUG
|
||||||
RESOURCES += resources.qrc
|
RESOURCES += resources.qrc
|
||||||
|
@ -295,6 +295,12 @@ HEADERS += src/cutdocument.h
|
||||||
SOURCES += src/cuttemplate.cpp
|
SOURCES += src/cuttemplate.cpp
|
||||||
HEADERS += src/cuttemplate.h
|
HEADERS += src/cuttemplate.h
|
||||||
|
|
||||||
|
SOURCES += src/remoteioserver.cpp
|
||||||
|
HEADERS += src/remoteioserver.h
|
||||||
|
|
||||||
|
SOURCES += src/remoteioconnection.cpp
|
||||||
|
HEADERS += src/remoteioconnection.h
|
||||||
|
|
||||||
SOURCES += src/main.cpp
|
SOURCES += src/main.cpp
|
||||||
|
|
||||||
HEADERS += src/version.h
|
HEADERS += src/version.h
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <set>
|
#include <map>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include "documentwindow.h"
|
#include "documentwindow.h"
|
||||||
|
@ -45,7 +45,7 @@ int DocumentWindow::m_skeletonRenderWidgetInitialY = DocumentWindow::m_modelRend
|
||||||
int DocumentWindow::m_skeletonRenderWidgetInitialSize = DocumentWindow::m_modelRenderWidgetInitialSize;
|
int DocumentWindow::m_skeletonRenderWidgetInitialSize = DocumentWindow::m_modelRenderWidgetInitialSize;
|
||||||
|
|
||||||
LogBrowser *g_logBrowser = nullptr;
|
LogBrowser *g_logBrowser = nullptr;
|
||||||
std::set<DocumentWindow *> g_documentWindows;
|
std::map<DocumentWindow *, QUuid> g_documentWindows;
|
||||||
QTextBrowser *g_acknowlegementsWidget = nullptr;
|
QTextBrowser *g_acknowlegementsWidget = nullptr;
|
||||||
AboutWidget *g_aboutWidget = nullptr;
|
AboutWidget *g_aboutWidget = nullptr;
|
||||||
QTextBrowser *g_contributorsWidget = nullptr;
|
QTextBrowser *g_contributorsWidget = nullptr;
|
||||||
|
@ -56,6 +56,11 @@ void outputMessage(QtMsgType type, const QMessageLogContext &context, const QStr
|
||||||
g_logBrowser->outputMessage(type, msg, context.file, context.line);
|
g_logBrowser->outputMessage(type, msg, context.file, context.line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::map<DocumentWindow *, QUuid> &DocumentWindow::documentWindows()
|
||||||
|
{
|
||||||
|
return g_documentWindows;
|
||||||
|
}
|
||||||
|
|
||||||
void DocumentWindow::showAcknowlegements()
|
void DocumentWindow::showAcknowlegements()
|
||||||
{
|
{
|
||||||
if (!g_acknowlegementsWidget) {
|
if (!g_acknowlegementsWidget) {
|
||||||
|
@ -112,7 +117,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
qInstallMessageHandler(&outputMessage);
|
qInstallMessageHandler(&outputMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_documentWindows.insert(this);
|
g_documentWindows.insert({this, QUuid::createUuid()});
|
||||||
|
|
||||||
m_document = new Document;
|
m_document = new Document;
|
||||||
|
|
||||||
|
@ -1025,8 +1030,8 @@ void DocumentWindow::saveAs()
|
||||||
|
|
||||||
void DocumentWindow::saveAll()
|
void DocumentWindow::saveAll()
|
||||||
{
|
{
|
||||||
for (auto &window: g_documentWindows) {
|
for (auto &it: g_documentWindows) {
|
||||||
window->save();
|
it.first->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1088,6 +1093,7 @@ void DocumentWindow::initLockButton(QPushButton *button)
|
||||||
|
|
||||||
DocumentWindow::~DocumentWindow()
|
DocumentWindow::~DocumentWindow()
|
||||||
{
|
{
|
||||||
|
emit uninialized();
|
||||||
g_documentWindows.erase(this);
|
g_documentWindows.erase(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QTextBrowser>
|
#include <QTextBrowser>
|
||||||
|
#include <map>
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "modelwidget.h"
|
#include "modelwidget.h"
|
||||||
#include "exportpreviewwidget.h"
|
#include "exportpreviewwidget.h"
|
||||||
|
@ -22,10 +23,12 @@ class DocumentWindow : public QMainWindow
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
signals:
|
signals:
|
||||||
void initialized();
|
void initialized();
|
||||||
|
void uninialized();
|
||||||
public:
|
public:
|
||||||
DocumentWindow();
|
DocumentWindow();
|
||||||
~DocumentWindow();
|
~DocumentWindow();
|
||||||
static DocumentWindow *createDocumentWindow();
|
static DocumentWindow *createDocumentWindow();
|
||||||
|
static const std::map<DocumentWindow *, QUuid> &documentWindows();
|
||||||
static void showAcknowlegements();
|
static void showAcknowlegements();
|
||||||
static void showContributors();
|
static void showContributors();
|
||||||
static void showAbout();
|
static void showAbout();
|
||||||
|
|
13
src/main.cpp
13
src/main.cpp
|
@ -5,9 +5,11 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QSurfaceFormat>
|
#include <QSurfaceFormat>
|
||||||
|
#include <QSettings>
|
||||||
#include "documentwindow.h"
|
#include "documentwindow.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "remoteioserver.h"
|
||||||
|
|
||||||
int main(int argc, char ** argv)
|
int main(int argc, char ** argv)
|
||||||
{
|
{
|
||||||
|
@ -39,6 +41,8 @@ int main(int argc, char ** argv)
|
||||||
//qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #fc6621; border: 1px solid white; }");
|
//qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #fc6621; border: 1px solid white; }");
|
||||||
|
|
||||||
QCoreApplication::setApplicationName(APP_NAME);
|
QCoreApplication::setApplicationName(APP_NAME);
|
||||||
|
QCoreApplication::setOrganizationName(APP_COMPANY);
|
||||||
|
QCoreApplication::setOrganizationDomain(APP_HOMEPAGE_URL);
|
||||||
|
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setWeight(QFont::Light);
|
font.setWeight(QFont::Light);
|
||||||
|
@ -50,5 +54,14 @@ int main(int argc, char ** argv)
|
||||||
|
|
||||||
DocumentWindow::createDocumentWindow();
|
DocumentWindow::createDocumentWindow();
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
QVariant remoteIoListenPort = settings.value("RemoteIo/ListenPort");
|
||||||
|
//if (remoteIoListenPort.isNull()) {
|
||||||
|
// settings.setValue("RemoteIo/ListenPort", "53309");
|
||||||
|
//}
|
||||||
|
if (!remoteIoListenPort.isNull()) {
|
||||||
|
new RemoteIoServer(remoteIoListenPort.toInt());
|
||||||
|
}
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include "remoteioconnection.h"
|
||||||
|
|
||||||
|
RemoteIoConnection::RemoteIoConnection(QTcpSocket *tcpSocket) :
|
||||||
|
m_tcpSocket(tcpSocket)
|
||||||
|
{
|
||||||
|
qDebug() << "Received new remote io connection from:" << m_tcpSocket->peerAddress();
|
||||||
|
|
||||||
|
connect(m_tcpSocket, &QAbstractSocket::disconnected, this, [&]() {
|
||||||
|
qDebug() << "Remote connection disconnected from:" << m_tcpSocket->peerAddress();
|
||||||
|
});
|
||||||
|
connect(m_tcpSocket, SIGNAL(readyRead()),this, SLOT(handleRead()));
|
||||||
|
|
||||||
|
m_commandHandlers["listwindow"] = &RemoteIoConnection::commandListWindow;
|
||||||
|
m_commandHandlers["selectwindow"] = &RemoteIoConnection::commandSelectWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteIoConnection::~RemoteIoConnection()
|
||||||
|
{
|
||||||
|
qDebug() << "Delete remote io connection";
|
||||||
|
|
||||||
|
delete m_tcpSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteIoConnection::handleRead()
|
||||||
|
{
|
||||||
|
m_receiveCache += m_tcpSocket->readAll();
|
||||||
|
|
||||||
|
for (auto command = nextCommandFromCache();
|
||||||
|
!command.isEmpty();
|
||||||
|
command = nextCommandFromCache()) {
|
||||||
|
qDebug() << "Received remote io command:" << command;
|
||||||
|
int parametersBegin = -1;
|
||||||
|
QString commandName = nameFromCommand(command, ¶metersBegin);
|
||||||
|
commandName = commandName.toLower();
|
||||||
|
auto findHandler = m_commandHandlers.find(commandName);
|
||||||
|
if (findHandler == m_commandHandlers.end()) {
|
||||||
|
qDebug() << "Unrecognized command:" << commandName;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QString errorMessage;
|
||||||
|
auto response = findHandler->second(this, -1 == parametersBegin ? QByteArray() : command.mid(parametersBegin), &errorMessage);
|
||||||
|
if (errorMessage.isEmpty())
|
||||||
|
m_tcpSocket->write(QByteArray("+OK\r\n").toHex());
|
||||||
|
else
|
||||||
|
m_tcpSocket->write(("-" + errorMessage + "\r\n").toUtf8().toHex());
|
||||||
|
m_tcpSocket->write(response.toHex());
|
||||||
|
m_tcpSocket->write(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoteIoConnection::isWhitespace(char c)
|
||||||
|
{
|
||||||
|
return ' ' == c || '\t' == c || '\r' == c || '\n' == c;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RemoteIoConnection::nameFromCommand(const QByteArray &command, int *parametersBegin)
|
||||||
|
{
|
||||||
|
if (nullptr != parametersBegin) {
|
||||||
|
*parametersBegin = -1;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < command.size(); ++i) {
|
||||||
|
if (isWhitespace(command[i])) {
|
||||||
|
int nameEnd = i;
|
||||||
|
if (nullptr != parametersBegin) {
|
||||||
|
while (isWhitespace(command[i]))
|
||||||
|
++i;
|
||||||
|
if (i < command.size())
|
||||||
|
*parametersBegin = i;
|
||||||
|
}
|
||||||
|
return command.mid(0, nameEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray RemoteIoConnection::nextCommandFromCache()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_receiveCache.size(); ++i) {
|
||||||
|
if ('\0' == m_receiveCache[i]) {
|
||||||
|
auto hexBuffer = m_receiveCache.mid(0, i);
|
||||||
|
if (0 != hexBuffer.size() % 2) {
|
||||||
|
qDebug() << "Received invalid remote io packet with length:" << hexBuffer.size();
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
auto command = QByteArray::fromHex(hexBuffer);
|
||||||
|
m_receiveCache = m_receiveCache.mid(i + 1);
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray RemoteIoConnection::commandListWindow(const QByteArray ¶meters, QString *errorMessage)
|
||||||
|
{
|
||||||
|
Q_UNUSED(parameters);
|
||||||
|
Q_UNUSED(errorMessage);
|
||||||
|
|
||||||
|
QByteArray response;
|
||||||
|
for (const auto &it: DocumentWindow::documentWindows()) {
|
||||||
|
response += it.second.toString() + QString(" ") + it.first->windowTitle().replace(" ", "%20") + "\r\n";
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray RemoteIoConnection::commandSelectWindow(const QByteArray ¶meters, QString *errorMessage)
|
||||||
|
{
|
||||||
|
Q_UNUSED(parameters);
|
||||||
|
Q_UNUSED(errorMessage);
|
||||||
|
|
||||||
|
QByteArray response;
|
||||||
|
if (parameters.isEmpty()) {
|
||||||
|
*errorMessage = "Must specify window id";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
QUuid windowId = QUuid(QString(parameters));
|
||||||
|
if (windowId.isNull()) {
|
||||||
|
*errorMessage = "Window id is invalid:" + QString(parameters);
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
for (const auto &it: DocumentWindow::documentWindows()) {
|
||||||
|
if (it.second == windowId) {
|
||||||
|
qDebug() << "Remote io select window:" << it.second;
|
||||||
|
m_currentDocumentWindow = it.first;
|
||||||
|
connect(m_currentDocumentWindow, &DocumentWindow::uninialized, this, [&]() {
|
||||||
|
if (sender() == m_currentDocumentWindow) {
|
||||||
|
m_currentDocumentWindow = nullptr;
|
||||||
|
qDebug() << "Selected window destroyed";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*errorMessage = "Window id not found:" + QString(parameters);
|
||||||
|
return QByteArray();
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef REMOTE_IO_CONNECTION_H
|
||||||
|
#define REMOTE_IO_CONNECTION_H
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <vector>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <map>
|
||||||
|
#include "documentwindow.h"
|
||||||
|
|
||||||
|
class RemoteIoConnection;
|
||||||
|
using CommandHandler = std::function<QByteArray(RemoteIoConnection *, const QByteArray&, QString *)>;
|
||||||
|
|
||||||
|
class RemoteIoConnection : QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit RemoteIoConnection(QTcpSocket *tcpSocket);
|
||||||
|
~RemoteIoConnection();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleRead();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTcpSocket *m_tcpSocket = nullptr;
|
||||||
|
QByteArray m_receiveCache;
|
||||||
|
DocumentWindow *m_currentDocumentWindow = nullptr;
|
||||||
|
std::map<QString, CommandHandler> m_commandHandlers;
|
||||||
|
|
||||||
|
QByteArray nextCommandFromCache();
|
||||||
|
QString nameFromCommand(const QByteArray &command, int *parametersBegin=nullptr);
|
||||||
|
bool isWhitespace(char c);
|
||||||
|
|
||||||
|
QByteArray commandListWindow(const QByteArray ¶meters, QString *errorMessage);
|
||||||
|
QByteArray commandSelectWindow(const QByteArray ¶meters, QString *errorMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include <QNetworkConfigurationManager>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include "remoteioserver.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "remoteioconnection.h"
|
||||||
|
|
||||||
|
RemoteIoServer::RemoteIoServer(int listenPort) :
|
||||||
|
m_listenPort(listenPort)
|
||||||
|
{
|
||||||
|
QNetworkConfigurationManager manager;
|
||||||
|
if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) {
|
||||||
|
// Get saved network configuration
|
||||||
|
QSettings settings;
|
||||||
|
settings.beginGroup(QLatin1String("QtNetwork"));
|
||||||
|
const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
// If the saved network configuration is not currently discovered use the system default
|
||||||
|
QNetworkConfiguration config = manager.configurationFromIdentifier(id);
|
||||||
|
if ((config.state() & QNetworkConfiguration::Discovered) !=
|
||||||
|
QNetworkConfiguration::Discovered) {
|
||||||
|
config = manager.defaultConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_networkSession = new QNetworkSession(config, this);
|
||||||
|
connect(m_networkSession, &QNetworkSession::opened, this, &RemoteIoServer::sessionOpened);
|
||||||
|
|
||||||
|
m_networkSession->open();
|
||||||
|
} else {
|
||||||
|
sessionOpened();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteIoServer::~RemoteIoServer()
|
||||||
|
{
|
||||||
|
delete m_currentConnection;
|
||||||
|
delete m_tcpServer;
|
||||||
|
delete m_networkSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteIoServer::sessionOpened()
|
||||||
|
{
|
||||||
|
// Save the used configuration
|
||||||
|
if (m_networkSession) {
|
||||||
|
QNetworkConfiguration config = m_networkSession->configuration();
|
||||||
|
QString id;
|
||||||
|
if (config.type() == QNetworkConfiguration::UserChoice)
|
||||||
|
id = m_networkSession->sessionProperty(QLatin1String("UserChoiceConfiguration")).toString();
|
||||||
|
else
|
||||||
|
id = config.identifier();
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
settings.beginGroup(QLatin1String("QtNetwork"));
|
||||||
|
settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id);
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_tcpServer = new QTcpServer(this);
|
||||||
|
if (!m_tcpServer->listen(QHostAddress::LocalHost, m_listenPort)) {
|
||||||
|
qDebug() << "Unable to listen on remote io port, error:" << m_tcpServer->errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_tcpServer, &QTcpServer::newConnection, this, &RemoteIoServer::handleConnection);
|
||||||
|
|
||||||
|
qDebug() << "Remote io listen on port:" << m_tcpServer->serverPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteIoServer::handleConnection()
|
||||||
|
{
|
||||||
|
QTcpSocket *clientSocket = m_tcpServer->nextPendingConnection();
|
||||||
|
if (nullptr == clientSocket)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (nullptr != m_currentConnection) {
|
||||||
|
delete m_currentConnection;
|
||||||
|
m_currentConnection = nullptr;
|
||||||
|
}
|
||||||
|
m_currentConnection = new RemoteIoConnection(clientSocket);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef DUST3D_REMOTE_IO_SERVER_H
|
||||||
|
#define DUST3D_REMOTE_IO_SERVER_H
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <QNetworkSession>
|
||||||
|
#include "remoteioconnection.h"
|
||||||
|
|
||||||
|
class RemoteIoServer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit RemoteIoServer(int listenPort);
|
||||||
|
~RemoteIoServer();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void sessionOpened();
|
||||||
|
void handleConnection();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_listenPort = 0;
|
||||||
|
QTcpServer *m_tcpServer = nullptr;
|
||||||
|
QNetworkSession *m_networkSession = nullptr;
|
||||||
|
RemoteIoConnection *m_currentConnection = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue