Feature/documentation topic (#822)

- Implement documentation topic that can be used to query documentation using the network API.
- Implement a way to pass arguments to lua scripts using json (rather than formatting entire lua string clientside)
- Implement ability to attach callback to lua script executions
- Implement abillity to transport return values from lua scripts back to network API clients.
- Do not initialize server interface on slave nodes.
- Implement Dictionary -> json converter using nlohmann json library
This commit is contained in:
Emil Axelsson
2019-04-03 10:30:28 +02:00
committed by GitHub
parent 4ef0bdc0a5
commit 53e07d90e1
30 changed files with 414 additions and 550 deletions

View File

@@ -161,7 +161,7 @@ bool ScriptEngine::hasLibrary(const std::string& name) {
return (it != _registeredLibraries.end());
}
bool ScriptEngine::runScript(const std::string& script) {
bool ScriptEngine::runScript(const std::string& script, ScriptCallback callback) {
if (script.empty()) {
LWARNING("Script was empty");
return false;
@@ -173,7 +173,13 @@ bool ScriptEngine::runScript(const std::string& script) {
}
try {
ghoul::lua::runScript(_state, script);
if (callback) {
ghoul::Dictionary returnValue =
ghoul::lua::loadArrayDictionaryFromString(script, _state);
callback.value()(returnValue);
} else {
ghoul::lua::runScript(_state, script);
}
}
catch (const ghoul::lua::LuaLoadingException& e) {
LERRORC(e.component, e.message);
@@ -183,6 +189,10 @@ bool ScriptEngine::runScript(const std::string& script) {
LERRORC(e.component, e.message);
return false;
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
return false;
}
return true;
}
@@ -639,72 +649,82 @@ void ScriptEngine::preSync(bool isMaster) {
return;
}
_mutex.lock();
if (!_queuedScripts.empty()) {
_currentSyncedScript = _queuedScripts.back().first;
const bool remoteScripting = _queuedScripts.back().second;
std::lock_guard<std::mutex> guard(_slaveScriptsMutex);
while (!_incomingScripts.empty()) {
QueueItem item = std::move(_incomingScripts.front());
_incomingScripts.pop();
_scriptsToSync.push_back(item.script);
const bool remoteScripting = item.remoteScripting;
// Not really a received script but the master also needs to run the script...
_receivedScripts.push_back(_currentSyncedScript);
_queuedScripts.pop_back();
_masterScriptQueue.push(item);
if (global::parallelPeer.isHost() && remoteScripting) {
global::parallelPeer.sendScript(_currentSyncedScript);
global::parallelPeer.sendScript(item.script);
}
if (global::sessionRecording.isRecording()) {
global::sessionRecording.saveScriptKeyframe(_currentSyncedScript);
global::sessionRecording.saveScriptKeyframe(item.script);
}
}
_mutex.unlock();
}
void ScriptEngine::encode(SyncBuffer* syncBuffer) {
syncBuffer->encode(_currentSyncedScript);
_currentSyncedScript.clear();
size_t nScripts = _scriptsToSync.size();
syncBuffer->encode(nScripts);
for (const std::string& s : _scriptsToSync) {
syncBuffer->encode(s);
}
_scriptsToSync.clear();
}
void ScriptEngine::decode(SyncBuffer* syncBuffer) {
syncBuffer->decode(_currentSyncedScript);
std::lock_guard<std::mutex> guard(_slaveScriptsMutex);
size_t nScripts;
syncBuffer->decode(nScripts);
if (!_currentSyncedScript.empty()) {
_mutex.lock();
_receivedScripts.push_back(_currentSyncedScript);
_mutex.unlock();
for (size_t i = 0; i < nScripts; ++i) {
std::string script;
syncBuffer->decode(script);
_slaveScriptQueue.push(std::move(script));
}
}
void ScriptEngine::postSync(bool) {
std::vector<std::string> scripts;
_mutex.lock();
scripts.assign(_receivedScripts.begin(), _receivedScripts.end());
_receivedScripts.clear();
_mutex.unlock();
while (!scripts.empty()) {
try {
runScript(scripts.back());
void ScriptEngine::postSync(bool isMaster) {
if (isMaster) {
while (!_masterScriptQueue.empty()) {
std::string script = std::move(_masterScriptQueue.front().script);
ScriptCallback callback = std::move(_masterScriptQueue.front().callback);
_masterScriptQueue.pop();
try {
runScript(script, callback);
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
continue;
}
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
} else {
std::lock_guard<std::mutex> guard(_slaveScriptsMutex);
while (!_slaveScriptQueue.empty()) {
try {
runScript(_slaveScriptQueue.front());
_slaveScriptQueue.pop();
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
}
}
scripts.pop_back();
}
}
void ScriptEngine::queueScript(const std::string& script,
ScriptEngine::RemoteScripting remoteScripting)
ScriptEngine::RemoteScripting remoteScripting,
ScriptCallback callback)
{
if (script.empty()) {
return;
if (!script.empty()) {
_incomingScripts.push({ script, remoteScripting, callback });
}
_mutex.lock();
_queuedScripts.insert(
_queuedScripts.begin(),
std::make_pair(script, remoteScripting)
);
_mutex.unlock();
}
} // namespace openspace::scripting