diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 5147bfca98..28464bc222 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -27,6 +27,7 @@ public: QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort, quint16 assignmentMonitorPort); ~AssignmentClient(); + private slots: void sendAssignmentRequest(); void assignmentCompleted(); diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index bd79d0fc04..2df97760fe 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -27,9 +27,30 @@ #include "ClientServerUtils.h" #include "../entities/AssignmentParentFinder.h" + +#include +#include + +using Mutex = std::mutex; +using Lock = std::lock_guard; + +static std::mutex logBufferMutex; +static std::string logBuffer; + +void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { + auto logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); + + if (!logMessage.isEmpty()) { + Lock lock(logBufferMutex); + logBuffer.append(logMessage.toStdString() + '\n'); + } +} + int EntityScriptServer::_entitiesScriptEngineCount = 0; EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) { + qInstallMessageHandler(messageHandler); + DependencyManager::get()->setPacketSender(&_entityEditSender); ResourceManager::init(); @@ -57,6 +78,18 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket"); packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket"); + packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); + + static const int LOG_INTERVAL = MSECS_PER_SECOND / 50; + auto timer = new QTimer(this); + timer->setTimerType(Qt::PreciseTimer); + timer->setInterval(LOG_INTERVAL); + connect(timer, &QTimer::timeout, this, &EntityScriptServer::pushLogs); + timer->start(); +} + +EntityScriptServer::~EntityScriptServer() { + qInstallMessageHandler(LogHandler::verboseMessageHandler); } static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server"; @@ -146,6 +179,60 @@ void EntityScriptServer::updateEntityPPS() { qDebug() << QString("Updating entity PPS to: %1 @ %2 PPS per script = %3 PPS").arg(numRunningScripts).arg(_entityPPSPerScript).arg(pps); } +void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { + // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them + // about each other. + if (senderNode->getCanRez() || senderNode->getCanRezTmp()) { + bool enable = false; + message->readPrimitive(&enable); + qInfo() << "======== Got log packet:" << enable; + + if (enable) { + _logListeners.insert(senderNode->getUUID()); + } else { + _logListeners.erase(senderNode->getUUID()); + } + } +} + +void EntityScriptServer::pushLogs() { + std::string buffer; + { + Lock lock(logBufferMutex); + std::swap(logBuffer, buffer); + } + + if (buffer.empty()) { + return; + } + if (_logListeners.empty()) { + return; + } + + auto packet = NLPacket::create(PacketType::EntityServerScriptLog, buffer.size(), true); + packet->write(buffer.data(), buffer.size()); + + auto nodeList = DependencyManager::get(); + + auto last = --std::end(_logListeners); + for (auto it = std::begin(_logListeners); it != last; ++it) { + auto node = nodeList->nodeWithUUID(*it); + if (node && node->getActiveSocket()) { + auto copy = NLPacket::createCopy(*packet); + nodeList->sendPacket(std::move(copy), *node); + } else { + qWarning() << "Node not found"; + } + } + + auto node = nodeList->nodeWithUUID(*last); + if (node && node->getActiveSocket()) { + nodeList->sendPacket(std::move(packet), *node); + } else { + qWarning() << "Node not found"; + } +} + void EntityScriptServer::run() { // make sure we request our script once the agent connects to the domain auto nodeList = DependencyManager::get(); @@ -347,15 +434,27 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, const } void EntityScriptServer::nodeKilled(SharedNodePointer killedNode) { - if (!_shuttingDown && killedNode->getType() == NodeType::EntityServer) { - if (_entitiesScriptEngine) { - _entitiesScriptEngine->unloadAllEntityScripts(); - _entitiesScriptEngine->stop(); + switch (killedNode->getType()) { + case NodeType::EntityServer: { + if (!_shuttingDown) { + if (_entitiesScriptEngine) { + _entitiesScriptEngine->unloadAllEntityScripts(); + _entitiesScriptEngine->stop(); + } + + resetEntitiesScriptEngine(); + + _entityViewer.clear(); + } + break; } - - resetEntitiesScriptEngine(); - - _entityViewer.clear(); + case NodeType::Agent: { + _logListeners.erase(killedNode->getUUID()); + break; + } + default: + // Do nothing + break; } } diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index 70f03977f8..5337b68eb7 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -12,7 +12,10 @@ #ifndef hifi_EntityScriptServer_h #define hifi_EntityScriptServer_h +#include + #include +#include #include #include @@ -28,6 +31,7 @@ class EntityScriptServer : public ThreadedAssignment { public: EntityScriptServer(ReceivedMessage& message); + ~EntityScriptServer(); virtual void aboutToFinish() override; @@ -48,6 +52,10 @@ private slots: void handleSettings(); void updateEntityPPS(); + void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + + void pushLogs(); + private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); @@ -71,6 +79,8 @@ private: int _maxEntityPPS { DEFAULT_MAX_ENTITY_PPS }; int _entityPPSPerScript { DEFAULT_ENTITY_PPS_PER_SCRIPT }; + std::set _logListeners; + QString _selectedCodecName; CodecPluginPointer _codec; Encoder* _encoder { nullptr }; diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 1e56d0cfd9..1ba8fb5ff8 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -46,6 +46,9 @@ int qTextBlockMeta = qRegisterMetaType("QTextBlock"); LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : QDialog(parent, Qt::Window) { + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + packetReceiver.registerListener(PacketType::EntityServerScriptLog, this, "handleEntityServerScriptLogPacket"); + _logger = logger; setWindowTitle("Log"); setAttribute(Qt::WA_DeleteOnClose); @@ -64,7 +67,7 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : QDialog move(screen.center() - rect().center()); setMinimumWidth(MINIMAL_WIDTH); - connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)), Qt::QueuedConnection); + //connect(_logger, SIGNAL(logReceived(QString)), this, SLOT(appendLogLine(QString)), Qt::QueuedConnection); } LogDialog::~LogDialog() { @@ -97,7 +100,8 @@ void LogDialog::initControls() { _extraDebuggingBox->setCheckState(Qt::Checked); } _extraDebuggingBox->show(); - connect(_extraDebuggingBox, SIGNAL(stateChanged(int)), SLOT(handleExtraDebuggingCheckbox(int))); + //connect(_extraDebuggingBox, SIGNAL(stateChanged(int)), SLOT(handleExtraDebuggingCheckbox(int))); + connect(_extraDebuggingBox, &QCheckBox::stateChanged, this, &LogDialog::enableToEntityServerScriptLog); _revealLogButton = new QPushButton("Reveal log file", this); // set object name for css styling @@ -156,6 +160,31 @@ void LogDialog::showLogData() { _logTextBox->ensureCursorVisible(); } + +void LogDialog::enableToEntityServerScriptLog(bool enable) { + qDebug() << Q_FUNC_INFO << enable; + auto nodeList = DependencyManager::get(); + + if (auto node = nodeList->soloNodeOfType(NodeType::EntityScriptServer)) { + auto packet = NLPacket::create(PacketType::EntityServerScriptLog, sizeof(bool), true); + packet->writePrimitive(enable); + nodeList->sendPacket(std::move(packet), *node); + + if (enable) { + appendLogLine("====================== Subscribded to the Entity Script Server's log ======================"); + } else { + appendLogLine("==================== Unsubscribded from the Entity Script Server's log ===================="); + } + } else { + qWarning() << "Entity Script Server not found"; + } +} + +void LogDialog::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { + auto lines = QString::fromUtf8(message->readAll()); + QMetaObject::invokeMethod(this, "appendLogLine", Q_ARG(QString, lines)); +} + KeywordHighlighter::KeywordHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent), keywordFormat() { keywordFormat.setForeground(QColor(HIGHLIGHT_COLOR)); } diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index 1493a43f01..4f366257ec 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -53,6 +53,9 @@ private slots: void handleExtraDebuggingCheckbox(const int); void handleSearchTextChanged(const QString); + void enableToEntityServerScriptLog(bool enable); + void handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode); + protected: void resizeEvent(QResizeEvent*) override; void showEvent(QShowEvent*) override; diff --git a/libraries/networking/src/EntityScriptClient.cpp b/libraries/networking/src/EntityScriptClient.cpp index 604a82fcca..a2c01312e6 100644 --- a/libraries/networking/src/EntityScriptClient.cpp +++ b/libraries/networking/src/EntityScriptClient.cpp @@ -162,4 +162,4 @@ void EntityScriptClient::forceFailureOfPendingRequests(SharedNodePointer node) { messageMapIt->second.clear(); } } -} \ No newline at end of file +} diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 88b5ec19ad..e1197bf8a5 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -111,7 +111,8 @@ public: EntityScriptGetStatusReply, ReloadEntityServerScript, EntityPhysics, - LAST_PACKET_TYPE = EntityPhysics + EntityServerScriptLog, + LAST_PACKET_TYPE = EntityServerScriptLog }; };