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
|
||||
DEFINES += NDEBUG
|
||||
RESOURCES += resources.qrc
|
||||
|
@ -295,6 +295,12 @@ HEADERS += src/cutdocument.h
|
|||
SOURCES += src/cuttemplate.cpp
|
||||
HEADERS += src/cuttemplate.h
|
||||
|
||||
SOURCES += src/remoteioserver.cpp
|
||||
HEADERS += src/remoteioserver.h
|
||||
|
||||
SOURCES += src/remoteioconnection.cpp
|
||||
HEADERS += src/remoteioconnection.h
|
||||
|
||||
SOURCES += src/main.cpp
|
||||
|
||||
HEADERS += src/version.h
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <QMenuBar>
|
||||
#include <QPointer>
|
||||
#include <QApplication>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <QDesktopServices>
|
||||
#include <QDockWidget>
|
||||
#include "documentwindow.h"
|
||||
|
@ -45,7 +45,7 @@ int DocumentWindow::m_skeletonRenderWidgetInitialY = DocumentWindow::m_modelRend
|
|||
int DocumentWindow::m_skeletonRenderWidgetInitialSize = DocumentWindow::m_modelRenderWidgetInitialSize;
|
||||
|
||||
LogBrowser *g_logBrowser = nullptr;
|
||||
std::set<DocumentWindow *> g_documentWindows;
|
||||
std::map<DocumentWindow *, QUuid> g_documentWindows;
|
||||
QTextBrowser *g_acknowlegementsWidget = nullptr;
|
||||
AboutWidget *g_aboutWidget = 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);
|
||||
}
|
||||
|
||||
const std::map<DocumentWindow *, QUuid> &DocumentWindow::documentWindows()
|
||||
{
|
||||
return g_documentWindows;
|
||||
}
|
||||
|
||||
void DocumentWindow::showAcknowlegements()
|
||||
{
|
||||
if (!g_acknowlegementsWidget) {
|
||||
|
@ -112,7 +117,7 @@ DocumentWindow::DocumentWindow() :
|
|||
qInstallMessageHandler(&outputMessage);
|
||||
}
|
||||
|
||||
g_documentWindows.insert(this);
|
||||
g_documentWindows.insert({this, QUuid::createUuid()});
|
||||
|
||||
m_document = new Document;
|
||||
|
||||
|
@ -1025,8 +1030,8 @@ void DocumentWindow::saveAs()
|
|||
|
||||
void DocumentWindow::saveAll()
|
||||
{
|
||||
for (auto &window: g_documentWindows) {
|
||||
window->save();
|
||||
for (auto &it: g_documentWindows) {
|
||||
it.first->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1088,6 +1093,7 @@ void DocumentWindow::initLockButton(QPushButton *button)
|
|||
|
||||
DocumentWindow::~DocumentWindow()
|
||||
{
|
||||
emit uninialized();
|
||||
g_documentWindows.erase(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QTextBrowser>
|
||||
#include <map>
|
||||
#include "document.h"
|
||||
#include "modelwidget.h"
|
||||
#include "exportpreviewwidget.h"
|
||||
|
@ -22,10 +23,12 @@ class DocumentWindow : public QMainWindow
|
|||
Q_OBJECT
|
||||
signals:
|
||||
void initialized();
|
||||
void uninialized();
|
||||
public:
|
||||
DocumentWindow();
|
||||
~DocumentWindow();
|
||||
static DocumentWindow *createDocumentWindow();
|
||||
static const std::map<DocumentWindow *, QUuid> &documentWindows();
|
||||
static void showAcknowlegements();
|
||||
static void showContributors();
|
||||
static void showAbout();
|
||||
|
|
13
src/main.cpp
13
src/main.cpp
|
@ -5,9 +5,11 @@
|
|||
#include <QDebug>
|
||||
#include <QtGlobal>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QSettings>
|
||||
#include "documentwindow.h"
|
||||
#include "theme.h"
|
||||
#include "version.h"
|
||||
#include "remoteioserver.h"
|
||||
|
||||
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; }");
|
||||
|
||||
QCoreApplication::setApplicationName(APP_NAME);
|
||||
QCoreApplication::setOrganizationName(APP_COMPANY);
|
||||
QCoreApplication::setOrganizationDomain(APP_HOMEPAGE_URL);
|
||||
|
||||
QFont font;
|
||||
font.setWeight(QFont::Light);
|
||||
|
@ -50,5 +54,14 @@ int main(int argc, char ** argv)
|
|||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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