Add support for sending requests to entity script server

This commit is contained in:
Ryan Huffman 2017-01-18 11:15:29 -08:00
parent 340eeb94fa
commit 8137c59ef7
6 changed files with 261 additions and 3 deletions

View file

@ -25,6 +25,8 @@
#include "../entities/AssignmentParentFinder.h"
const size_t UUID_LENGTH_BYTES = 16;
int EntityScriptServer::_entitiesScriptEngineCount = 0;
EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) {
@ -52,10 +54,39 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
packetReceiver.registerListener(PacketType::BulkAvatarData, avatarHashMap.data(), "processAvatarDataPacket");
packetReceiver.registerListener(PacketType::KillAvatar, avatarHashMap.data(), "processKillAvatar");
packetReceiver.registerListener(PacketType::AvatarIdentity, avatarHashMap.data(), "processAvatarIdentityPacket");
packetReceiver.registerListener(PacketType::ReloadEntityServerScript, this, "handleReloadEntityServerScriptPacket");
packetReceiver.registerListener(PacketType::EntityScriptGetStatus, this, "handleEntityScriptGetStatusPacket");
}
static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server";
void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
auto entityID = QUuid::fromRfc4122(message->read(UUID_LENGTH_BYTES));
if (_entityViewer.getTree() && !_shuttingDown) {
qDebug() << "Reloading: " << entityID;
_entitiesScriptEngine->unloadEntityScript(entityID);
checkAndCallPreload(entityID, true);
}
}
void EntityScriptServer::handleEntityScriptGetStatusPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
MessageID messageID;
message->readPrimitive(&messageID);
auto entityID = QUuid::fromRfc4122(message->read(UUID_LENGTH_BYTES));
// TODO(Huffman) Get Status
qDebug() << "Getting script status of: " << entityID;
auto replyPacket = NLPacket::create(PacketType::EntityScriptGetStatusReply, -1, true);
replyPacket->writePrimitive(messageID);
replyPacket->writeString("running");
auto nodeList = DependencyManager::get<NodeList>();
nodeList->sendPacket(std::move(replyPacket), *senderNode);
}
void EntityScriptServer::run() {
// make sure we request our script once the agent connects to the domain
auto nodeList = DependencyManager::get<NodeList>();
@ -75,7 +106,8 @@ void EntityScriptServer::run() {
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &EntityScriptServer::nodeKilled);
nodeList->addSetOfNodeTypesToNodeInterestSet({
NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
NodeType::Agent, NodeType::AudioMixer, NodeType::AvatarMixer,
NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
});
// Setup Script Engine

View file

@ -39,6 +39,9 @@ private slots:
void handleJurisdictionPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleSelectedAudioFormat(QSharedPointer<ReceivedMessage> message);
void handleReloadEntityServerScriptPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void handleEntityScriptGetStatusPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
private:
void negotiateAudioFormat();
void selectAudioFormat(const QString& selectedCodecName);

View file

@ -61,7 +61,7 @@
#include <CursorManager.h>
#include <DebugDraw.h>
#include <DeferredLightingEffect.h>
#include <display-plugins/DisplayPlugin.h>
#include <EntityScriptClient.h>
#include <EntityScriptingInterface.h>
#include <ErrorDialog.h>
#include <FileScriptingInterface.h>
@ -173,6 +173,7 @@
#include "FrameTimingsScriptingInterface.h"
#include <GPUIdent.h>
#include <gl/GLHelpers.h>
#include <EntityScriptClient.h>
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
// FIXME seems to be broken.
@ -514,6 +515,7 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::set<EntityTreeRenderer>(true, qApp, qApp);
DependencyManager::set<CompositorHelper>();
DependencyManager::set<OffscreenQmlSurfaceCache>();
DependencyManager::set<EntityScriptClient>();
return previousSessionCrashed;
}
@ -852,7 +854,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// tell the NodeList instance who to tell the domain server we care about
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer);
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer << NodeType::EntityScriptServer);
// connect to the packet sent signal of the _entityEditSender
connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);

View file

@ -25,6 +25,7 @@
#include "QVariantGLM.h"
#include "SimulationOwner.h"
#include "ZoneEntityItem.h"
#include <EntityScriptClient.h>
EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :

View file

@ -0,0 +1,153 @@
#include "EntityScriptClient.h"
#include "NodeList.h"
#include "NetworkLogging.h"
#include <QThread>
MessageID EntityScriptClient::_currentID = 0;
GetScriptStatusRequest::GetScriptStatusRequest(QUuid entityID) : _entityID(entityID) {
}
GetScriptStatusRequest::~GetScriptStatusRequest() {
}
void GetScriptStatusRequest::start() {
auto client = DependencyManager::get<EntityScriptClient>();
qDebug() << "Sending script status request";
client->getEntityServerScriptStatus(_entityID, [this](bool responseReceived) {
qDebug() << "Received script status request";
emit finished(this);
});
}
EntityScriptClient::EntityScriptClient() {
setCustomDeleter([](Dependency* dependency){
static_cast<EntityScriptClient*>(dependency)->deleteLater();
});
auto nodeList = DependencyManager::get<NodeList>();
auto& packetReceiver = nodeList->getPacketReceiver();
packetReceiver.registerListener(PacketType::EntityScriptGetStatusReply, this, "handleGetScriptStatusReply");
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &EntityScriptClient::handleNodeKilled);
connect(nodeList.data(), &LimitedNodeList::clientConnectionToNodeReset,
this, &EntityScriptClient::handleNodeClientConnectionReset);
}
GetScriptStatusRequest* EntityScriptClient::createScriptStatusRequest(QUuid entityID) {
auto request = new GetScriptStatusRequest(entityID);
request->moveToThread(thread());
return request;
}
bool EntityScriptClient::reloadServerScript(QUuid entityID) {
// Send packet to entity script server
auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer);
if (entityScriptServer) {
auto id = entityID.toRfc4122();
auto payloadSize = id.size();
auto packet = NLPacket::create(PacketType::ReloadEntityServerScript, payloadSize, true);
packet->write(id);
if (nodeList->sendPacket(std::move(packet), *entityScriptServer) != -1) {
return true;
}
}
return false;
}
MessageID EntityScriptClient::getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback) {
auto nodeList = DependencyManager::get<NodeList>();
SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer);
if (entityScriptServer) {
auto packetList = NLPacketList::create(PacketType::EntityScriptGetStatus, QByteArray(), true, true);
auto messageID = ++_currentID;
packetList->writePrimitive(messageID);
packetList->write(entityID.toRfc4122());
if (nodeList->sendPacketList(std::move(packetList), *entityScriptServer) != -1) {
_pendingEntityScriptStatusRequests[entityScriptServer][messageID] = callback;
return messageID;
}
}
callback(false);
return INVALID_MESSAGE_ID;
}
void EntityScriptClient::handleGetScriptStatusReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
Q_ASSERT(QThread::currentThread() == thread());
MessageID messageID;
message->readPrimitive(&messageID);
auto status = message->readString();
// Check if we have any pending requests for this node
auto messageMapIt = _pendingEntityScriptStatusRequests.find(senderNode);
if (messageMapIt != _pendingEntityScriptStatusRequests.end()) {
// Found the node, get the MessageID -> Callback map
auto& messageCallbackMap = messageMapIt->second;
// Check if we have this pending request
auto requestIt = messageCallbackMap.find(messageID);
if (requestIt != messageCallbackMap.end()) {
auto callback = requestIt->second;
callback(true);
messageCallbackMap.erase(requestIt);
}
// Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from
// it to avoid constantly creating/deleting the map on subsequent requests.
}
}
void EntityScriptClient::handleNodeKilled(SharedNodePointer node) {
Q_ASSERT(QThread::currentThread() == thread());
if (node->getType() != NodeType::EntityScriptServer) {
return;
}
forceFailureOfPendingRequests(node);
}
void EntityScriptClient::handleNodeClientConnectionReset(SharedNodePointer node) {
// a client connection to a Node was reset
// if it was an EntityScriptServer we need to cause anything pending to fail so it is re-attempted
if (node->getType() != NodeType::EntityScriptServer) {
return;
}
//qCDebug(entity_script_client) << "EntityScriptClient detected client connection reset handshake with Asset Server - failing any pending requests";
forceFailureOfPendingRequests(node);
}
void EntityScriptClient::forceFailureOfPendingRequests(SharedNodePointer node) {
{
auto messageMapIt = _pendingEntityScriptStatusRequests.find(node);
if (messageMapIt != _pendingEntityScriptStatusRequests.end()) {
for (const auto& value : messageMapIt->second) {
value.second(false);
}
messageMapIt->second.clear();
}
}
}

View file

@ -0,0 +1,67 @@
//
// EntityScriptClient.h
// libraries/networking/src
//
// Created by Ryan Huffman on 2017/01/13
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_EntityScriptClient_h
#define hifi_EntityScriptClient_h
#include "LimitedNodeList.h"
#include "ReceivedMessage.h"
#include "AssetUtils.h"
#include <DependencyManager.h>
#include <cstdint>
#include <unordered_map>
using MessageID = uint32_t;
using GetScriptStatusCallback = std::function<void(bool responseReceived)>;
class GetScriptStatusRequest : public QObject {
Q_OBJECT
public:
GetScriptStatusRequest(QUuid);
~GetScriptStatusRequest();
Q_INVOKABLE void start();
signals:
void finished(GetScriptStatusRequest* request);
private:
QUuid _entityID;
MessageID _messageID;
QString status;
};
class EntityScriptClient : public QObject, public Dependency {
Q_OBJECT
public:
EntityScriptClient();
Q_INVOKABLE GetScriptStatusRequest* createScriptStatusRequest(QUuid entityID);
bool reloadServerScript(QUuid entityID);
MessageID getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback);
private slots:
void handleNodeKilled(SharedNodePointer node);
void handleNodeClientConnectionReset(SharedNodePointer node);
void handleGetScriptStatusReply(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
private:
static MessageID _currentID;
std::unordered_map<SharedNodePointer, std::unordered_map<MessageID, GetScriptStatusCallback>> _pendingEntityScriptStatusRequests;
void forceFailureOfPendingRequests(SharedNodePointer node);
};
#endif