This commit is contained in:
gallaert
2018-05-26 19:05:11 +01:00
15 changed files with 573 additions and 52 deletions

View File

@@ -900,8 +900,10 @@ namespace canvas
else if( name == "coord" )
_attributes_dirty |= COORDS;
else if ( name == "svg")
{
_hasSVG = true;
_attributes_dirty |= SVG;
}
}
//----------------------------------------------------------------------------

View File

@@ -242,8 +242,13 @@ void Client::makeRequest(const Request_ptr& r)
if( r->isComplete() )
return;
if (r->url().empty()) {
r->setFailure(EINVAL, "no URL specified on request");
return;
}
if( r->url().find("://") == std::string::npos ) {
r->setFailure(EINVAL, "malformed URL");
r->setFailure(EINVAL, "malformed URL: '" + r->url() + "'");
return;
}

View File

@@ -92,6 +92,11 @@ public:
path = ss.str();
}
}
// return zip data for this computed URL
if (path.find("/catalogTest1/movies") == 0) {
path = "/catalogTest1/movies-data.zip";
}
localPath.append(path);
@@ -152,7 +157,7 @@ int parseTest()
SG_CHECK_EQUAL(cat->description(), "First test catalog");
// check the packages too
SG_CHECK_EQUAL(cat->packages().size(), 4);
SG_CHECK_EQUAL(cat->packages().size(), 5);
pkg::PackageRef p1 = cat->packages().front();
SG_CHECK_EQUAL(p1->catalog(), cat.ptr());
@@ -326,7 +331,7 @@ void testAddCatalog(HTTP::Client* cl)
p.append("org.flightgear.test.catalog1");
p.append("catalog.xml");
SG_VERIFY(p.exists());
SG_CHECK_EQUAL(root->allPackages().size(), 4);
SG_CHECK_EQUAL(root->allPackages().size(), 5);
SG_CHECK_EQUAL(root->catalogs().size(), 1);
pkg::PackageRef p1 = root->getPackageById("alpha");
@@ -559,6 +564,43 @@ void testInstallTarPackage(HTTP::Client* cl)
SG_VERIFY(p.exists());
}
void testInstallArchiveType(HTTP::Client* cl)
{
global_catalogVersion = 0;
SGPath rootPath(simgear::Dir::current().path());
rootPath.append("pkg_install_archive_type");
simgear::Dir pd(rootPath);
pd.removeChildren();
pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
// specify a test dir
root->setHTTPClient(cl);
pkg::CatalogRef c = pkg::Catalog::createFromUrl(root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
waitForUpdateComplete(cl, root);
pkg::PackageRef p1 = root->getPackageById("org.flightgear.test.catalog1.movies");
SG_CHECK_EQUAL(p1->id(), "movies");
pkg::InstallRef ins = p1->install();
SG_VERIFY(ins->isQueued());
waitForUpdateComplete(cl, root);
SG_VERIFY(p1->isInstalled());
SG_VERIFY(p1->existingInstall() == ins);
// verify on disk state
SGPath p(rootPath);
p.append("org.flightgear.test.catalog1");
p.append("Aircraft");
p.append("movies");
SG_CHECK_EQUAL(p, ins->path());
p.append("movie-list.json");
SG_VERIFY(p.exists());
}
void testDisableDueToVersion(HTTP::Client* cl)
{
global_catalogVersion = 0;
@@ -915,7 +957,9 @@ int main(int argc, char* argv[])
testRefreshCatalog(&cl);
testInstallTarPackage(&cl);
testInstallArchiveType(&cl);
testDisableDueToVersion(&cl);
testOfflineMode(&cl);

View File

@@ -57,6 +57,10 @@ public:
throw sg_exception("no package download URLs");
}
if (m_owner->package()->properties()->hasChild("archive-type")) {
setArchiveTypeFromExtension(m_owner->package()->properties()->getStringValue("archive-type"));
}
// TODO randomise order of m_urls
m_extractPath = aOwner->path().dir();
@@ -165,7 +169,12 @@ protected:
// build a path like /path/to/packages/org.some.catalog/Aircraft/extract_xxxx/MyAircraftDir
SGPath extractedPath = m_extractPath;
extractedPath.append(m_owner->package()->dirName());
if (m_owner->package()->properties()->hasChild("archive-path")) {
extractedPath.append(m_owner->package()->properties()->getStringValue("archive-path"));
} else {
extractedPath.append(m_owner->package()->dirName());
}
// rename it to path/to/packages/org.some.catalog/Aircraft/MyAircraftDir
bool ok = extractedPath.rename(m_owner->path());
@@ -175,6 +184,8 @@ protected:
}
// extract_xxxx directory is now empty, so remove it
// (note it might not be empty if the archive contained some other
// files, but we delete those in such a case
if (m_extractPath.exists()) {
simgear::Dir(m_extractPath).remove();
}
@@ -196,7 +207,22 @@ protected:
}
private:
void setArchiveTypeFromExtension(const std::string& ext)
{
if (ext.empty())
return;
if (ext == "zip") {
m_archiveType = ZIP;
return;
}
if ((ext == "tar.gz") || (ext == "tgz")) {
m_archiveType = TAR_GZ;
return;
}
}
void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize)
{
unz_file_info fileInfo;
@@ -262,14 +288,22 @@ private:
{
const std::string u(url());
const size_t ul(u.length());
if (u.rfind(".zip") == (ul - 4)) {
return extractUnzip();
if (m_archiveType == AUTO_DETECT) {
if (u.rfind(".zip") == (ul - 4)) {
m_archiveType = ZIP;
} else if (u.rfind(".tar.gz") == (ul - 7)) {
m_archiveType = TAR_GZ;
}
// we will fall through to the error case now
}
if (u.rfind(".tar.gz") == (ul - 7)) {
if (m_archiveType == ZIP) {
return extractUnzip();
} else if (m_archiveType == TAR_GZ) {
return extractTar();
}
SG_LOG(SG_IO, SG_WARN, "unsupported archive format:" << u);
return false;
}
@@ -330,7 +364,14 @@ private:
m_owner->installResult(aReason);
}
enum ArchiveType {
AUTO_DETECT = 0,
ZIP,
TAR_GZ
};
InstallRef m_owner;
ArchiveType m_archiveType = AUTO_DETECT;
string_list m_urls;
SG_MD5_CTX m_md5;
std::string m_buffer;

View File

@@ -99,10 +99,8 @@ public:
/**
* human-readable name - note this is probably not localised,
* although this is not ruled out for the future.
*
* Deprecated - please use nameForVariant
*/
SG_DEPRECATED(std::string name() const);
std::string name() const;
/**
* Human readable name of a variant
@@ -112,12 +110,9 @@ public:
std::string nameForVariant(const unsigned int vIndex) const;
/**
* syntactic sugar to get the localised description
*
* Deprecated - please use getLocalisedProp to get the variant-specific
* description.
* syntactic sugar to get the localised description of the main aircraft
*/
SG_DEPRECATED(std::string description() const);
std::string description() const;
/**
* access the raw property data in the package

View File

@@ -778,6 +778,11 @@ bool Root::removeCatalogById(const std::string& aId)
void Root::requestThumbnailData(const std::string& aUrl)
{
if (aUrl.empty()) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, "requestThumbnailData: empty URL requested");
return;
}
auto it = d->thumbnailCache.find(aUrl);
if (it == d->thumbnailCache.end()) {
bool cachedOnDisk = d->checkPersistentCache(aUrl);

View File

@@ -177,4 +177,18 @@
<file-size-bytes>360</file-size-bytes>
<md5>acf9eb89cf396eb42f8823d9cdf17584</md5>
</package>
<package>
<id>movies</id>
<name>movies files for test catalog aircraft</name>
<revision>10</revision>
<dir>movies</dir>
<!-- url has no file extension, instead we set arcive-type -->
<url>http://localhost:2000/catalogTest1/movies?wierd=foo;bar=thing</url>
<archive-type>zip</archive-type>
<archive-path>movies_6789</archive-path>
<file-size-bytes>232</file-size-bytes>
<md5>e5f89c3f1ed1bdda16174c868f3c7b30</md5>
</package>
</PropertyList>

Binary file not shown.

View File

@@ -0,0 +1,3 @@
{
"id": "awesomething"
}

View File

@@ -69,6 +69,9 @@ void SGEventMgr::init()
return;
}
// The event manager dtor and ctor are not called on reset, so reset the flag here.
_shutdown = false;
_inited = true;
}

View File

@@ -27,11 +27,14 @@
#include "exception.hxx"
#include "subsystem_mgr.hxx"
#include "commands.hxx"
#include <simgear/props/props.hxx>
#include <simgear/math/SGMath.hxx>
#include "SGSmplstat.hxx"
const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
const char SUBSYSTEM_NAME_SEPARATOR = '.';
using std::string;
using State = SGSubsystem::State;
@@ -136,6 +139,26 @@ void SGSubsystem::set_name(const std::string &n)
_name = n;
}
std::string SGSubsystem::typeName() const
{
auto pos = _name.find(SUBSYSTEM_NAME_SEPARATOR);
if (pos == std::string::npos) {
return _name;
}
return _name.substr(0, pos);
}
std::string SGSubsystem::instanceName() const
{
auto pos = _name.find(SUBSYSTEM_NAME_SEPARATOR);
if (pos == std::string::npos) {
return {};
}
return _name.substr(pos+1);
}
void SGSubsystem::set_group(SGSubsystemGroup* group)
{
_group = group;
@@ -156,6 +179,7 @@ SGSubsystemMgr* SGSubsystem::get_manager() const
std::string SGSubsystem::nameForState(State s)
{
switch (s) {
case State::INVALID: return "invalid";
case State::INIT: return "init";
case State::REINIT: return "reinit";
case State::POSTINIT: return "post-init";
@@ -215,11 +239,13 @@ SGSubsystemGroup::~SGSubsystemGroup ()
void
SGSubsystemGroup::init ()
{
assert(_state == State::BIND);
forEach([this](SGSubsystem* s){
this->notifyWillChange(s, State::INIT);
s->init();
this->notifyDidChange(s, State::INIT);
});
_state = State::INIT;
}
SGSubsystem::InitStatus
@@ -232,11 +258,13 @@ SGSubsystemGroup::incrementalInit()
// termination test
if (_initPosition >= static_cast<int>(_members.size())) {
_state = State::INIT;
return INIT_DONE;
}
if (_initPosition < 0) {
// first call
assert(_state == State::BIND);
_initPosition = 0;
notifyWillChange(_members.front()->subsystem, State::INIT);
}
@@ -278,11 +306,13 @@ void SGSubsystemGroup::reverseForEach(std::function<void(SGSubsystem*)> f)
void
SGSubsystemGroup::postinit ()
{
assert(_state == State::INIT);
forEach([this](SGSubsystem* s){
this->notifyWillChange(s, State::POSTINIT);
s->postinit();
this->notifyDidChange(s, State::POSTINIT);
});
_state = State::POSTINIT;
}
void
@@ -303,6 +333,7 @@ SGSubsystemGroup::shutdown ()
s->shutdown();
this->notifyDidChange(s, State::SHUTDOWN);
});
_state = State::SHUTDOWN;
_initPosition = -1;
}
@@ -314,6 +345,7 @@ SGSubsystemGroup::bind ()
s->bind();
this->notifyDidChange(s, State::BIND);
});
_state = State::BIND;
}
void
@@ -324,6 +356,7 @@ SGSubsystemGroup::unbind ()
s->unbind();
this->notifyDidChange(s, State::UNBIND);
});
_state = State::UNBIND;
}
void
@@ -419,6 +452,16 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
member->min_step_sec = min_step_sec;
subsystem->set_group(this);
notifyDidChange(subsystem, State::ADD);
if (_state != State::INVALID) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when adding after init");
// transition to the correct state
// bind
// init
// post-init
}
}
void
@@ -456,6 +499,16 @@ SGSubsystemGroup::remove_subsystem(const string &name)
if (it != _members.end()) {
// found it, great
const auto sub = (*it)->subsystem;
if (_state != State::INVALID) {
// transition out correctly
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when removing before shutdown");
// shutdown
// unbind
}
notifyWillChange(sub, State::REMOVE);
delete *it;
_members.erase(it);
@@ -562,7 +615,6 @@ void SGSubsystemGroup::set_manager(SGSubsystemMgr *manager)
// Implementation of SGSubsystemGroup::Member
////////////////////////////////////////////////////////////////////////
SGSubsystemGroup::Member::Member ()
: name(""),
subsystem(0),
@@ -614,10 +666,29 @@ SGSubsystemGroup::Member::update (double delta_time_sec)
// Implementation of SGSubsystemMgr.
////////////////////////////////////////////////////////////////////////
namespace {
SGSubsystemMgr* global_defaultSubsystemManager = nullptr;
void registerSubsystemCommands();
} // end of anonymous namespace
SGSubsystemMgr::SGSubsystemMgr () :
_groups(MAX_GROUPS)
{
if (global_defaultSubsystemManager == nullptr) {
// register ourselves as the default
global_defaultSubsystemManager = this;
}
// disabled until subsystemfactory is removed from FlightGear
#if 0
auto commandManager = SGCommandMgr::instance();
if (commandManager && !commandManager->getCommand("add-subsystem")) {
registerSubsystemCommands();
}
#endif
for (int i = 0; i < MAX_GROUPS; i++) {
auto g = new SGSubsystemGroup;
g->set_manager(this);
@@ -628,7 +699,24 @@ SGSubsystemMgr::SGSubsystemMgr () :
SGSubsystemMgr::~SGSubsystemMgr ()
{
_destructorActive = true;
_groups.clear();
_groups.clear();
// if we were the global one, null out the pointer so it doesn't dangle.
// don't do anything clever to track multiple subsystems for now; if we
// a smarter scheme, let's wait until it's clearer what that might be.
if (global_defaultSubsystemManager == this) {
global_defaultSubsystemManager = nullptr;
}
}
SGSubsystemMgr* SGSubsystemMgr::getManager(const std::string& id)
{
if (id.empty()) {
return global_defaultSubsystemManager;
}
// remove me when if/when we supprot multiple subsystem instances
throw sg_exception("multiple subsystem instances not supported yet");
}
void
@@ -784,7 +872,7 @@ SGSubsystemMgr::get_subsystem (const string &name) const
SGSubsystem*
SGSubsystemMgr::get_subsystem(const std::string &name, const std::string& instanceName) const
{
return get_subsystem(name + "-" + instanceName);
return get_subsystem(name + SUBSYSTEM_NAME_SEPARATOR + instanceName);
}
@@ -825,10 +913,15 @@ namespace {
using SybsystemRegistrationVec = std::vector<RegisteredSubsystemData>;
SybsystemRegistrationVec global_registrations;
SybsystemRegistrationVec &getGlobalRegistrations()
{
static SybsystemRegistrationVec global_registrations;
return global_registrations;
}
SybsystemRegistrationVec::const_iterator findRegistration(const std::string& name)
{
auto &global_registrations = getGlobalRegistrations();
auto it = std::find_if(global_registrations.begin(),
global_registrations.end(),
[name](const RegisteredSubsystemData& d)
@@ -844,6 +937,7 @@ void SGSubsystemMgr::registerSubsystem(const std::string& name,
double updateInterval,
std::initializer_list<Dependency> deps)
{
auto &global_registrations = getGlobalRegistrations();
if (findRegistration(name) != global_registrations.end()) {
throw sg_exception("duplicate subsystem registration for: " + name);
}
@@ -857,6 +951,7 @@ void SGSubsystemMgr::registerSubsystem(const std::string& name,
auto SGSubsystemMgr::defaultGroupFor(const char* name) -> GroupType
{
auto it = findRegistration(name);
auto &global_registrations = getGlobalRegistrations();
if (it == global_registrations.end()) {
throw sg_exception("unknown subsystem registration for: " + std::string(name));
}
@@ -867,6 +962,7 @@ auto SGSubsystemMgr::defaultGroupFor(const char* name) -> GroupType
double SGSubsystemMgr::defaultUpdateIntervalFor(const char* name)
{
auto it = findRegistration(name);
auto &global_registrations = getGlobalRegistrations();
if (it == global_registrations.end()) {
throw sg_exception("unknown subsystem registration for: " + std::string(name));
}
@@ -878,6 +974,7 @@ const SGSubsystemMgr::DependencyVec&
SGSubsystemMgr::dependsFor(const char* name)
{
auto it = findRegistration(name);
auto &global_registrations = getGlobalRegistrations();
if (it == global_registrations.end()) {
throw sg_exception("unknown subsystem registration for: " + std::string(name));
}
@@ -889,6 +986,7 @@ SGSubsystemRef
SGSubsystemMgr::create(const std::string& name)
{
auto it = findRegistration(name);
auto &global_registrations = getGlobalRegistrations();
if (it == global_registrations.end()) {
return {}; // or should this throw with a 'not registered'?
}
@@ -910,6 +1008,7 @@ SGSubsystemRef
SGSubsystemMgr::createInstance(const std::string& name, const std::string& instanceName)
{
auto it = findRegistration(name);
auto &global_registrations = getGlobalRegistrations();
if (it == global_registrations.end()) {
return {}; // or should this throw with a 'not registered'?
}
@@ -923,7 +1022,7 @@ SGSubsystemMgr::createInstance(const std::string& name, const std::string& insta
throw sg_exception("SGSubsystemMgr::create: functor failed to create an instsance of " + name);
}
const auto combinedName = name + "-" + instanceName;
const auto combinedName = name + SUBSYSTEM_NAME_SEPARATOR + instanceName;
ref->set_name(combinedName);
return ref;
}
@@ -966,5 +1065,218 @@ void SGSubsystemMgr::notifyDelegatesDidChange(SGSubsystem* sub, State state)
{ d->didChange(sub, state); });
}
void SGSubsystemMgr::set_root_node(SGPropertyNode_ptr node)
{
_rootNode = node;
}
SGPropertyNode_ptr
SGSubsystemMgr::root_node() const
{
return _rootNode;
}
namespace {
bool
do_check_subsystem_running(const SGPropertyNode * arg, SGPropertyNode * root)
{
auto manager = SGSubsystemMgr::getManager({});
return (manager->get_subsystem(arg->getStringValue("name")) != nullptr);
}
SGSubsystemMgr::GroupType mapGroupNameToType(const std::string& s)
{
if (s == "init") return SGSubsystemMgr::INIT;
if (s == "general") return SGSubsystemMgr::GENERAL;
if (s == "fdm") return SGSubsystemMgr::FDM;
if (s == "post-fdm") return SGSubsystemMgr::POST_FDM;
if (s == "display") return SGSubsystemMgr::DISPLAY;
if (s == "sound") return SGSubsystemMgr::SOUND;
SG_LOG(SG_GENERAL, SG_ALERT, "unrecognized subsystem group:" << s);
return SGSubsystemMgr::GENERAL;
}
bool
do_add_subsystem (const SGPropertyNode * arg, SGPropertyNode * root)
{
auto manager = SGSubsystemMgr::getManager({});
std::string subsystem = arg->getStringValue("subsystem");
// allow override of the name but defaultt o the subsystem name
std::string name = arg->getStringValue("name");
std::string instanceName = arg->getStringValue("instance");
if (name.empty()) {
// default name to subsystem name, but before we parse any instance name
name = subsystem;
}
auto separatorPos = subsystem.find(SUBSYSTEM_NAME_SEPARATOR);
if (separatorPos != std::string::npos) {
if (!instanceName.empty()) {
SG_LOG(SG_GENERAL, SG_WARN, "Specified a composite subsystem name and an instance name, please do one or the other: "
<< instanceName << " and " << subsystem);
return false;
}
instanceName = subsystem.substr(separatorPos + 1);
subsystem = subsystem.substr(0, separatorPos);
}
SGSubsystem* sub = nullptr;
if (!instanceName.empty()) {
sub = manager->createInstance(subsystem, instanceName);
} else {
sub = manager->create(subsystem);
}
if (!sub)
return false;
std::string groupArg = arg->getStringValue("group");
SGSubsystemMgr::GroupType group = SGSubsystemMgr::GENERAL;
if (!groupArg.empty()) {
group = mapGroupNameToType(groupArg);
}
double minTime = arg->getDoubleValue("min-time-sec", 0.0);
const auto combinedName = subsystem + SUBSYSTEM_NAME_SEPARATOR + instanceName;
manager->add(combinedName.c_str(),
sub,
group,
minTime);
if (arg->getBoolValue("do-bind-init", false)) {
sub->bind();
sub->init();
}
return true;
}
bool do_remove_subsystem(const SGPropertyNode * arg, SGPropertyNode * root)
{
auto manager = SGSubsystemMgr::getManager({});
std::string name = arg->getStringValue("subsystem");
SGSubsystem* instance = manager->get_subsystem(name);
if (!instance) {
SG_LOG(SG_GENERAL, SG_ALERT, "do_remove_subsystem: unknown subsytem:" << name);
return false;
}
// is it safe to always call these? let's assume so!
instance->shutdown();
instance->unbind();
// unplug from the manager (this also deletes the instance!)
manager->remove(name.c_str());
return true;
}
/**
* Built-in command: reinitialize one or more subsystems.
*
* subsystem[*]: the name(s) of the subsystem(s) to reinitialize; if
* none is specified, reinitialize all of them.
*/
bool do_reinit (const SGPropertyNode * arg, SGPropertyNode * root)
{
bool result = true;
auto manager = SGSubsystemMgr::getManager({});
auto subsystems = arg->getChildren("subsystem");
if (subsystems.empty()) {
SG_LOG(SG_GENERAL, SG_INFO, "do_reinit: reinit-ing subsystem manager");
manager->reinit();
} else {
for (auto sub : subsystems) {
const char * name = sub->getStringValue();
SGSubsystem* subsystem = manager->get_subsystem(name);
if (subsystem == nullptr) {
result = false;
SG_LOG( SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found" );
} else {
subsystem->reinit();
}
}
}
return result;
}
/**
* Built-in command: suspend one or more subsystems.
*
* subsystem[*] - the name(s) of the subsystem(s) to suspend.
*/
bool do_suspend (const SGPropertyNode * arg, SGPropertyNode * root)
{
bool result = true;
auto manager = SGSubsystemMgr::getManager({});
for (auto subNode : arg->getChildren("subsystem")) {
const char * name = subNode->getStringValue();
SGSubsystem * subsystem = manager->get_subsystem(name);
if (subsystem == nullptr) {
result = false;
SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found");
} else {
subsystem->suspend();
}
}
return result;
}
/**
* Built-in command: suspend one or more subsystems.
*
* subsystem[*] - the name(s) of the subsystem(s) to suspend.
*/
bool do_resume (const SGPropertyNode * arg, SGPropertyNode * root)
{
bool result = true;
auto manager = SGSubsystemMgr::getManager({});
for (auto subNode : arg->getChildren("subsystem")) {
const char * name = subNode->getStringValue();
SGSubsystem * subsystem = manager->get_subsystem(name);
if (subsystem == nullptr) {
result = false;
SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found");
} else {
subsystem->resume();
}
}
return result;
}
struct CommandDef {
const char * name;
SGCommandMgr::command_t command;
};
CommandDef built_ins[] = {
{ "add-subsystem", do_add_subsystem },
{ "remove-subsystem", do_remove_subsystem },
{ "subsystem-running", do_check_subsystem_running },
{ "reinit", do_reinit },
{ "suspend", do_suspend },
{ "resume", do_resume },
};
void registerSubsystemCommands()
{
auto commandManager = SGCommandMgr::instance();
for (auto b : built_ins) {
commandManager->addCommand(b.name, b.command);
}
}
} // anonymous namespace implementing subsystem commands
// end of subsystem_mgr.cxx

View File

@@ -33,6 +33,7 @@
#include <simgear/timing/timestamp.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/props/propsfwd.hxx>
class TimingInfo
{
@@ -275,9 +276,23 @@ public:
*/
void stamp(const std::string& name);
/**
* composite name for this subsystem (type name & optional instance name)
*/
std::string name() const
{ return _name; }
/**
* @brief the type (class)-specific part of the subsystem name.
*/
std::string typeName() const;
/**
* @brief the instance part of the subsystem name. Empty if this
* subsystem is not instanced
*/
std::string instanceName() const;
virtual bool is_group() const
{ return false; }
@@ -287,7 +302,8 @@ public:
SGSubsystemGroup* get_group() const;
enum class State {
ADD,
INVALID = -1,
ADD = 0,
BIND,
INIT,
POSTINIT,
@@ -311,7 +327,11 @@ protected:
void set_group(SGSubsystemGroup* group);
std::string _name;
/// composite name for the subsystem (type name and instance name if this
/// is an instanced subsystem. (Since this member was originally defined as
/// protected, not private, we can't rename it easily)
std::string _name;
bool _suspended = false;
eventTimeVec timingInfo;
@@ -400,6 +420,9 @@ private:
using MemberVec = std::vector<Member*>;
MemberVec _members;
// track the state of this group, so we can transition added/removed
// members correctly
SGSubsystem::State _state = SGSubsystem::State::INVALID;
double _fixedUpdateTime;
double _updateTimeRemainder;
@@ -433,6 +456,8 @@ typedef SGSharedPtr<SGSubsystemGroup> SGSubsystemGroupRef;
class SGSubsystemMgr : public SGSubsystem
{
public:
SGSubsystemMgr(const SGSubsystemMgr&) = delete;
SGSubsystemMgr& operator=(const SGSubsystemMgr&) = delete;
/**
* Types of subsystem groups.
@@ -483,6 +508,18 @@ public:
void reportTiming();
void setReportTimingCb(void* userData,SGSubsystemTimingCb cb) {reportTimingCb = cb;reportTimingUserData = userData;}
/**
* @brief set the root property node for this subsystem manager
* subsystems can retrieve this value during init/bind (or at any time)
* to base their own properties trees off of.
*/
void set_root_node(SGPropertyNode_ptr node);
/**
* @brief retrieve the root property node for this subsystem manager
*/
SGPropertyNode_ptr root_node() const;
template<class T>
T* get_subsystem() const
{
@@ -621,6 +658,13 @@ public:
void addDelegate(Delegate * d);
void removeDelegate(Delegate * d);
/**
* @brief return a particular subsystem manager by name. Passing an
* empty string retrived the default/global subsystem manager, assuming it
* has been created.
*/
static SGSubsystemMgr* getManager(const std::string& id);
private:
friend class SGSubsystem;
friend class SGSubsystemGroup;
@@ -631,6 +675,7 @@ private:
std::vector<SGSubsystemGroupRef> _groups;
unsigned int _initPosition = 0;
bool _destructorActive = false;
SGPropertyNode_ptr _rootNode;
// non-owning reference, this is to accelerate lookup
// by name which otherwise needs a full walk of the entire tree

View File

@@ -7,6 +7,7 @@
#include <simgear/constants.h>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/misc/test_macros.hxx>
#include <simgear/props/props.hxx>
using std::string;
using std::cout;
@@ -26,6 +27,13 @@ public:
wasInited = true;
}
void bind() override
{
auto node = get_manager()->root_node();
if (node)
node->setIntValue("mysub/foo", 42);
}
void update(double dt) override
{
@@ -44,6 +52,13 @@ public:
}
void bind() override
{
auto node = get_manager()->root_node();
if (node)
node->setIntValue("anothersub/bar", 172);
}
void update(double dt) override
{
lastUpdateTime = dt;
@@ -155,7 +170,9 @@ void testRegistrationAndCreation()
SG_VERIFY(anotherSub);
SG_CHECK_EQUAL(anotherSub->name(), AnotherSub::subsystemName());
SG_CHECK_EQUAL(anotherSub->name(), std::string("anothersub"));
SG_CHECK_EQUAL(anotherSub->typeName(), std::string("anothersub"));
SG_CHECK_EQUAL(anotherSub->instanceName(), std::string());
auto radio1 = manager->createInstance<FakeRadioSub>("nav1");
auto radio2 = manager->createInstance<FakeRadioSub>("nav2");
@@ -221,18 +238,21 @@ void testSubGrouping()
auto radio1 = manager->createInstance<FakeRadioSub>("nav1");
auto radio2 = manager->createInstance<FakeRadioSub>("nav2");
SG_CHECK_EQUAL(radio1->name(), std::string("fake-radio-nav1"));
SG_CHECK_EQUAL(radio2->name(), std::string("fake-radio-nav2"));
SG_CHECK_EQUAL(radio1->name(), std::string("fake-radio.nav1"));
SG_CHECK_EQUAL(radio2->name(), std::string("fake-radio.nav2"));
SG_CHECK_EQUAL(radio1->typeName(), std::string("fake-radio"));
SG_CHECK_EQUAL(radio2->instanceName(), std::string("nav2"));
instruments->set_subsystem(radio1);
instruments->set_subsystem(radio2);
SG_VERIFY(d->hasEvent("fake-radio-nav1-did-add"));
SG_VERIFY(d->hasEvent("fake-radio-nav1-will-add"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-add"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-add"));
// lookup of the group should also work
SG_CHECK_EQUAL(manager->get_subsystem<InstrumentGroup>(), instruments);
manager->bind();
manager->init();
SG_VERIFY(instruments->wasInited);
@@ -241,24 +261,27 @@ void testSubGrouping()
SG_VERIFY(d->hasEvent("instruments-will-init"));
SG_VERIFY(d->hasEvent("instruments-did-init"));
SG_VERIFY(d->hasEvent("fake-radio-nav1-will-init"));
SG_VERIFY(d->hasEvent("fake-radio-nav2-did-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-init"));
manager->update(0.5);
SG_CHECK_EQUAL_EP(0.5, instruments->lastUpdateTime);
SG_CHECK_EQUAL_EP(0.5, radio1->lastUpdateTime);
SG_CHECK_EQUAL_EP(0.5, radio2->lastUpdateTime);
SG_CHECK_EQUAL(radio1, instruments->get_subsystem("fake-radio-nav1"));
SG_CHECK_EQUAL(radio2, instruments->get_subsystem("fake-radio-nav2"));
SG_CHECK_EQUAL(0, instruments->get_subsystem("fake-radio"));
SG_CHECK_EQUAL(radio1, instruments->get_subsystem("fake-radio.nav1"));
SG_CHECK_EQUAL(radio2, instruments->get_subsystem("fake-radio.nav2"));
// type-safe lookup of instanced
SG_CHECK_EQUAL(radio1, manager->get_subsystem<FakeRadioSub>("nav1"));
SG_CHECK_EQUAL(radio2, manager->get_subsystem<FakeRadioSub>("nav2"));
bool ok = manager->remove("fake-radio-nav2");
bool ok = manager->remove("fake-radio.nav2");
SG_VERIFY(ok);
SG_VERIFY(instruments->get_subsystem("fake-radio-nav2") == nullptr);
SG_VERIFY(instruments->get_subsystem("fake-radio.nav2") == nullptr);
manager->update(1.0);
SG_CHECK_EQUAL_EP(1.0, instruments->lastUpdateTime);
@@ -270,7 +293,7 @@ void testSubGrouping()
manager->unbind();
SG_VERIFY(d->hasEvent("instruments-will-unbind"));
SG_VERIFY(d->hasEvent("instruments-did-unbind"));
SG_VERIFY(d->hasEvent("fake-radio-nav1-will-unbind"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-unbind"));
}
@@ -291,16 +314,13 @@ void testIncrementalInit()
instruments->set_subsystem(radio1);
instruments->set_subsystem(radio2);
manager->bind();
for ( ; ; ) {
auto status = manager->incrementalInit();
if (status == SGSubsystemMgr::INIT_DONE)
break;
}
for (auto ev : d->events) {
std::cerr << "ev:" << ev.nameForEvent() << std::endl;
}
SG_VERIFY(mySub->wasInited);
SG_VERIFY(d->hasEvent("mysub-will-init"));
@@ -313,11 +333,11 @@ void testIncrementalInit()
// SG_VERIFY(d->hasEvent("instruments-did-init"));
SG_VERIFY(d->hasEvent("fake-radio-nav1-will-init"));
SG_VERIFY(d->hasEvent("fake-radio-nav1-did-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-init"));
SG_VERIFY(d->hasEvent("fake-radio-nav2-will-init"));
SG_VERIFY(d->hasEvent("fake-radio-nav2-did-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav2-will-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-init"));
@@ -338,6 +358,7 @@ void testSuspendResume()
instruments->set_subsystem(radio1);
instruments->set_subsystem(radio2);
manager->bind();
manager->init();
manager->update(1.0);
@@ -350,7 +371,7 @@ void testSuspendResume()
SG_VERIFY(d->hasEvent("anothersub-will-suspend"));
SG_VERIFY(d->hasEvent("anothersub-did-suspend"));
SG_VERIFY(!d->hasEvent("radio1-will-suspend"));
SG_VERIFY(!d->hasEvent("fake-radio.nav1-will-suspend"));
manager->update(0.5);
@@ -392,6 +413,32 @@ void testSuspendResume()
SG_CHECK_EQUAL_EP(5.0, radio2->lastUpdateTime);
}
void testPropertyRoot()
{
SGSharedPtr<SGSubsystemMgr> manager = new SGSubsystemMgr;
SGPropertyNode_ptr props(new SGPropertyNode);
manager->set_root_node(props);
auto d = new RecorderDelegate;
manager->addDelegate(d);
manager->add<MySub1>();
auto anotherSub = manager->add<AnotherSub>();
auto instruments = manager->add<InstrumentGroup>();
auto radio1 = manager->createInstance<FakeRadioSub>("nav1");
auto radio2 = manager->createInstance<FakeRadioSub>("nav2");
instruments->set_subsystem(radio1);
instruments->set_subsystem(radio2);
manager->bind();
manager->init();
SG_CHECK_EQUAL(props->getIntValue("mysub/foo"), 42);
SG_CHECK_EQUAL(props->getIntValue("anothersub/bar"), 172);
}
///////////////////////////////////////////////////////////////////////////////
@@ -402,6 +449,7 @@ int main(int argc, char* argv[])
testSubGrouping();
testIncrementalInit();
testSuspendResume();
testPropertyRoot();
cout << __FILE__ << ": All tests passed" << endl;
return EXIT_SUCCESS;

View File

@@ -72,10 +72,14 @@ void SGTime::init( const SGGeod& location, const SGPath& root, time_t init_time
cur_time = time(NULL);
}
char* gmt = asctime(gmtime(&cur_time));
char* local = asctime(localtime(&cur_time));
gmt[strlen(gmt) - 1] = '\0';
local[strlen(local) - 1] = '\0';
SG_LOG( SG_EVENT, SG_DEBUG,
"Current greenwich mean time = " << asctime(gmtime(&cur_time)));
"Current greenwich mean time = " << gmt);
SG_LOG( SG_EVENT, SG_DEBUG,
"Current local time = " << asctime(localtime(&cur_time)));
"Current local time = " << local);
if ( !root.isNull()) {
if (!static_tzContainer.get()) {

View File

@@ -1 +1 @@
2018.2.0
2018.3.0