Fixed Session load recursion, allow higher level of imbrication

Recursive load of SessionFile in a Session is now detected by filename and prevented. Deeper level of integration of sessionfile inside session is thus possible (set to 3). Sessions now have an id, allowing to reference them by id in the logs. Terminology is clarified between level and recursion.
This commit is contained in:
Bruno Herbelin
2022-04-08 17:44:39 +02:00
parent ef65dd8cc6
commit 33756c775c
7 changed files with 84 additions and 49 deletions

View File

@@ -42,9 +42,13 @@ SessionNote::SessionNote(const std::string &t, bool l, int s): label(std::to_str
{
}
Session::Session() : active_(true), activation_threshold_(MIXING_MIN_THRESHOLD),
Session::Session(uint64_t id) : id_(id), active_(true), activation_threshold_(MIXING_MIN_THRESHOLD),
filename_(""), failedSource_(nullptr), thumbnail_(nullptr)
{
// create unique id
if (id_ == 0)
id_ = BaseToolkit::uniqueId();
config_[View::RENDERING] = new Group;
config_[View::RENDERING]->scale_ = glm::vec3(0.f);
@@ -669,10 +673,10 @@ void Session::validate (SourceList &sources)
}
}
Session *Session::load(const std::string& filename, uint recursion)
Session *Session::load(const std::string& filename, uint level)
{
// create session
SessionCreator creator(recursion);
SessionCreator creator(level);
creator.load(filename);
// return created session

View File

@@ -38,10 +38,13 @@ class Session
friend class RenderSource;
public:
Session();
Session(uint64_t id = 0);
~Session();
static Session *load(const std::string& filename, uint recursion = 0);
// Get unique id
inline uint64_t id () const { return id_; }
static Session *load(const std::string& filename, uint level = 0);
static std::string save(const std::string& filename, Session *session, const std::string& snapshot_name = "");
// add given source into the session
@@ -169,6 +172,7 @@ public:
Metronome::Synchronicity inputSynchrony(uint input);
protected:
uint64_t id_;
bool active_;
float activation_threshold_;
RenderView render_;

View File

@@ -94,25 +94,34 @@ SessionInformation SessionCreator::info(const std::string& filename)
return ret;
}
SessionCreator::SessionCreator(int recursion): SessionLoader(nullptr, recursion)
SessionCreator::SessionCreator(uint level): SessionLoader(nullptr, level)
{
}
void SessionCreator::load(const std::string& filename)
{
// avoid imbricated sessions at too many depth
if (level_ > MAX_SESSION_LEVEL) {
Log::Warning("Too many imbricated sessions detected! Interrupting loading at depth %d.\n", MAX_SESSION_LEVEL);
return;
}
// Load XML document
XMLError eResult = xmlDoc_.LoadFile(filename.c_str());
if ( XMLResultError(eResult)){
Log::Warning("%s could not be opened.\n%s", filename.c_str(), xmlDoc_.ErrorStr());
return;
}
// check header
XMLElement *header = xmlDoc_.FirstChildElement(APP_NAME);
if (header == nullptr) {
Log::Warning("%s is not a %s session file.", filename.c_str(), APP_NAME);
Log::Warning("%s is not a %s file.", filename.c_str(), APP_NAME);
return;
}
// check version
int version_major = -1, version_minor = -1;
header->QueryIntAttribute("major", &version_major);
header->QueryIntAttribute("minor", &version_minor);
@@ -124,15 +133,28 @@ void SessionCreator::load(const std::string& filename)
// return;
}
// check content
XMLElement *sessionNode = xmlDoc_.FirstChildElement("Session");
if (sessionNode == nullptr) {
Log::Warning("%s is not a %s session file.", filename.c_str(), APP_NAME);
return;
}
// read id of session
uint64_t id__ = 0;
sessionNode->QueryUnsigned64Attribute("id", &id__);
// session file seems legit, create a session
session_ = new Session;
session_ = new Session(id__);
// set filename and current path
sessionFilePath_ = SystemToolkit::path_filename(filename);
session_->setFilename( filename );
// load views config (includes resolution of session rendering)
loadConfig( xmlDoc_.FirstChildElement("Views") );
// ready to read sources
sessionFilePath_ = SystemToolkit::path_filename(filename);
XMLElement *sessionNode = xmlDoc_.FirstChildElement("Session");
SessionLoader::load( sessionNode );
// load snapshots
@@ -157,7 +179,9 @@ void SessionCreator::load(const std::string& filename)
}
// all good
session_->setFilename(filename);
Log::Info("Session %s Opened '%s' (%d sources)", std::to_string(session_->id()).c_str(),
filename.c_str(), session_->numSource());
}
@@ -295,21 +319,13 @@ void SessionCreator::loadPlayGroups(tinyxml2::XMLElement *playgroupNode)
}
}
SessionLoader::SessionLoader(): Visitor(),
session_(nullptr), xmlCurrent_(nullptr), recursion_(0)
SessionLoader::SessionLoader(Session *session, uint level): Visitor(),
session_(session), xmlCurrent_(nullptr), level_(level)
{
// impose C locale
setlocale(LC_ALL, "C");
}
SessionLoader::SessionLoader(Session *session, int recursion): Visitor(),
session_(session), xmlCurrent_(nullptr), recursion_(recursion)
{
// impose C locale
setlocale(LC_ALL, "C");
}
std::map< uint64_t, Source* > SessionLoader::getSources() const
{
return sources_id_;
@@ -345,16 +361,12 @@ void SessionLoader::load(XMLElement *sessionNode)
{
sources_id_.clear();
if (recursion_ > MAX_SESSION_LEVEL) {
Log::Warning("Recursive or imbricated sessions detected! Interrupting loading after %d iterations.\n", MAX_SESSION_LEVEL);
return;
}
if (sessionNode != nullptr && session_ != nullptr)
{
//
// session attributes
//
// read and set activation threshold
float t = MIXING_MIN_THRESHOLD;
sessionNode->QueryFloatAttribute("activationThreshold", &t);
session_->setActivationThreshold(t);
@@ -411,6 +423,9 @@ void SessionLoader::load(XMLElement *sessionNode)
else if ( std::string(pType) == "SrtReceiverSource") {
load_source = new SrtReceiverSource(id_xml_);
}
else if ( std::string(pType) != "CloneSource") {
Log::Info("Unknown source type '%s' ignored.", pType);
}
// skip failed (including clones)
if (!load_source)
@@ -764,7 +779,7 @@ void SessionLoader::visit(MediaPlayer &n)
XMLElement* mediaplayerNode = xmlCurrent_->FirstChildElement("MediaPlayer");
if (mediaplayerNode) {
uint64_t id__ = -1;
uint64_t id__ = 0;
mediaplayerNode->QueryUnsigned64Attribute("id", &id__);
// timeline
@@ -1004,17 +1019,28 @@ void SessionLoader::visit (SessionFileSource& s)
const char * text = pathNode->GetText();
if (text) {
std::string path(text);
// load only new files
if ( path != s.path() ) {
if ( !SystemToolkit::file_exists(path)){
if ( !SystemToolkit::file_exists(path) ){
const char * relative;
if ( pathNode->QueryStringAttribute("relative", &relative) == XML_SUCCESS) {
std::string rel = SystemToolkit::path_absolute_from_path(std::string( relative ), sessionFilePath_);
Log::Info("File %s not found; Trying %s instead.", path.c_str(), rel.c_str());
Log::Info("File '%s' not found; Trying '%s' instead.", path.c_str(), rel.c_str());
path = rel;
}
}
s.load(path, recursion_ + 1);
// load only if session source s is new
if ( path != s.path() ) {
// level of session imbrication
uint l = level_;
if ( path == session_->filename() && l < MAX_SESSION_LEVEL) {
// prevent recursive load by reaching maximum level of inclusion immediately
l += MAX_SESSION_LEVEL;
Log::Warning("Prevending recursive inclusion of Session '%s' into itself.", path.c_str());
}
else
// normal increment level of inclusion
++l;
// launch session loader at incremented level
s.load(path, l);
}
}
}
@@ -1032,7 +1058,7 @@ void SessionLoader::visit (SessionGroupSource& s)
// only parse if newly created
if (s.session()->empty()) {
// load session inside group
SessionLoader grouploader( s.session(), recursion_ + 1 );
SessionLoader grouploader( s.session(), level_ + 1 );
grouploader.load( sessionGroupNode );
}
}

View File

@@ -1,6 +1,7 @@
#ifndef SESSIONCREATOR_H
#define SESSIONCREATOR_H
#include <list>
#include <map>
#include <tinyxml2.h>
@@ -13,11 +14,9 @@ class FrameBufferImage;
class SessionLoader : public Visitor {
SessionLoader();
public:
SessionLoader(Session *session, int recursion = 0);
SessionLoader(Session *session = nullptr, uint level = 0);
inline Session *session() const { return session_; }
void load(tinyxml2::XMLElement *sessionNode);
@@ -84,8 +83,8 @@ protected:
std::string sessionFilePath_;
// parsing current xml
tinyxml2::XMLElement *xmlCurrent_;
// level of loading recursion
int recursion_;
// level of loading imbricated sessions and recursion
uint level_;
// map of correspondance from xml source id (key) to new source pointer (value)
std::map< uint64_t, Source* > sources_id_;
// list of groups (lists of xml source id)
@@ -115,7 +114,7 @@ class SessionCreator : public SessionLoader {
void loadInputCallbacks(tinyxml2::XMLElement *inputsNode);
public:
SessionCreator(int recursion = 0);
SessionCreator(uint level = 0);
void load(const std::string& filename);

View File

@@ -174,7 +174,7 @@ SessionFileSource::SessionFileSource(uint64_t id) : SessionSource(id), path_("")
}
void SessionFileSource::load(const std::string &p, uint recursion)
void SessionFileSource::load(const std::string &p, uint level)
{
path_ = p;
@@ -192,7 +192,7 @@ void SessionFileSource::load(const std::string &p, uint recursion)
}
else {
// launch a thread to load the session file
sessionLoader_ = std::async(std::launch::async, Session::load, path_, recursion);
sessionLoader_ = std::async(std::launch::async, Session::load, path_, level);
Log::Notify("Opening %s", p.c_str());
}
@@ -229,7 +229,7 @@ void SessionFileSource::init()
// done init
wait_for_sources_ = false;
initialized_ = true;
Log::Info("Source Session %s loaded %d sources.", path_.c_str(), session_->numSource());
Log::Info("Source '%s' linked to Session %s.", name().c_str(), std::to_string(session_->id()).c_str());
}
}
else if ( !failed_ ) {
@@ -254,7 +254,7 @@ void SessionFileSource::init()
wait_for_sources_ = true;
else {
initialized_ = true;
Log::Info("New Session created (%d x %d).", renderbuffer->width(), renderbuffer->height());
Log::Info("Source '%s' linked to new Session %s.", name().c_str(), std::to_string(session_->id()).c_str());
}
}
}

View File

@@ -43,7 +43,7 @@ public:
void render() override;
// SessionFile Source specific interface
void load(const std::string &p = "", uint recursion = 0);
void load(const std::string &p = "", uint level = 0);
inline std::string path() const { return path_; }

View File

@@ -75,6 +75,7 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
(*iter)->accept(sv);
// save session attributes
sessionNode->SetAttribute("id", session->id());
sessionNode->SetAttribute("activationThreshold", session->activationThreshold());
// save the thumbnail
@@ -664,6 +665,7 @@ void SessionVisitor::visit (SessionGroupSource& s)
Session *se = s.session();
if (se) {
XMLElement *sessionNode = xmlDoc_->NewElement("Session");
sessionNode->SetAttribute("id", se->id());
xmlCurrent_->InsertEndChild(sessionNode);
for (auto iter = se->begin(); iter != se->end(); ++iter){