summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-03-06 18:23:17 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-03-06 18:23:17 (GMT)
commite1a31a44c946d58a1b4654e5daa2d10d9c6f881d (patch)
tree7ce434b9bfb30c2de74cfe1f226c2ceda4ee8178 /src/uscxml/plugins
parent8c4977361f9e7998da298b9648f3ad4be5e772ff (diff)
downloaduscxml-e1a31a44c946d58a1b4654e5daa2d10d9c6f881d.zip
uscxml-e1a31a44c946d58a1b4654e5daa2d10d9c6f881d.tar.gz
uscxml-e1a31a44c946d58a1b4654e5daa2d10d9c6f881d.tar.bz2
Changed directory monitor to polling behaviour :(
Diffstat (limited to 'src/uscxml/plugins')
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp6
-rw-r--r--src/uscxml/plugins/element/postpone/PostponeElement.cpp69
-rw-r--r--src/uscxml/plugins/element/postpone/PostponeElement.h12
-rw-r--r--src/uscxml/plugins/element/response/ResponseElement.cpp133
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp423
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h59
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp62
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h3
-rw-r--r--src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp316
-rw-r--r--src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h15
-rw-r--r--src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp2
11 files changed, 725 insertions, 375 deletions
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
index d791b9e..d00ad43 100644
--- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
+++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp
@@ -320,9 +320,9 @@ v8::Handle<v8::Value> V8DataModel::evalAsValue(const std::string& expr) {
exceptionEvent.data.compound["filename"] = Data(filename, Data::VERBATIM);
std::string sourceLine(*v8::String::AsciiValue(message->GetSourceLine()));
- size_t startpos = sourceLine.find_first_not_of(" \t");
- if(std::string::npos != startpos) // removoe leading white space
- sourceLine = sourceLine.substr(startpos);
+ size_t startpos = sourceLine.find_first_not_of(" \t");
+ if(std::string::npos != startpos) // removoe leading white space
+ sourceLine = sourceLine.substr(startpos);
exceptionEvent.data.compound["sourceline"] = Data(sourceLine, Data::VERBATIM);
diff --git a/src/uscxml/plugins/element/postpone/PostponeElement.cpp b/src/uscxml/plugins/element/postpone/PostponeElement.cpp
index 5dc1c60..b50b5c2 100644
--- a/src/uscxml/plugins/element/postpone/PostponeElement.cpp
+++ b/src/uscxml/plugins/element/postpone/PostponeElement.cpp
@@ -41,16 +41,16 @@ void PostponeElement::enterElement(const Arabica::DOM::Node<std::string>& node)
}
// when will we refire the event?
- std::string until;
- try {
- if (HAS_ATTR(node, "untilexpr")) {
- until = _interpreter->getDataModel().evalAsString(ATTR(node, "untilexpr"));
- } else if (HAS_ATTR(node, "until")) {
- until = ATTR(node, "until");
- }
+ std::string until;
+ try {
+ if (HAS_ATTR(node, "untilexpr")) {
+ until = _interpreter->getDataModel().evalAsString(ATTR(node, "untilexpr"));
+ } else if (HAS_ATTR(node, "until")) {
+ until = ATTR(node, "until");
+ }
} catch (Event e) {
LOG(ERROR) << "Syntax error in postpone element untilexpr:" << std::endl << e << std::endl;
- return;
+ return;
}
if (until.length() == 0) {
@@ -58,30 +58,65 @@ void PostponeElement::enterElement(const Arabica::DOM::Node<std::string>& node)
return;
}
+ LOG(INFO) << until;
+
+#if 0
+ std::string timeoutStr = "0s";
+ try {
+ if (HAS_ATTR(node, "timeoutexpr")) {
+ timeoutStr = _interpreter->getDataModel().evalAsString(ATTR(node, "timeoutexpr"));
+ } else if (HAS_ATTR(node, "timeout")) {
+ timeoutStr = ATTR(node, "timeout");
+ }
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in postpone element timeoutexpr:" << std::endl << e << std::endl;
+ return;
+ }
+
+ uint64_t timeout = 0;
+ NumAttr timeoutAttr(timeoutStr);
+ if (boost::iequals(timeoutAttr.unit, "s")) {
+ timeout = strTo<int>(timeoutAttr.value) * 1000;
+ } else if (boost::iequals(timeoutAttr.unit, "ms")) {
+ timeout = strTo<int>(timeoutAttr.value);
+ }
+ if (timeout > 0) {
+ timeout += tthread::chrono::system_clock::now();
+ }
+#endif
Event currEvent = _interpreter->getCurrentEvent();
- Resubmitter::postpone(currEvent, until, _interpreter);
+ Resubmitter::postpone(currEvent, until, 0, _interpreter);
}
void PostponeElement::exitElement(const Arabica::DOM::Node<std::string>& node) {
}
-void PostponeElement::Resubmitter::postpone(const Event& event, std::string until, Interpreter* interpreter) {
+void PostponeElement::Resubmitter::postpone(const Event& event, std::string until, uint64_t timeout, Interpreter* interpreter) {
Resubmitter* resubmitter = getInstance(interpreter);
- resubmitter->_postponedEvents.push_back(std::make_pair(until, event));
+ resubmitter->_postponedEvents.push_back(Postponed(event, until, timeout));
}
void PostponeElement::Resubmitter::onStableConfiguration(Interpreter* interpreter) {
- std::list<std::pair<std::string, Event> >::iterator eventIter = _postponedEvents.begin();
+ std::list<Postponed>::iterator eventIter = _postponedEvents.begin();
while(eventIter != _postponedEvents.end()) {
try {
- LOG(INFO) << "Reevaluating: >> " << eventIter->first << " <<";
- if (interpreter->getDataModel().evalAsBool(eventIter->first)) {
- LOG(INFO) << " -> is TRUE";
- interpreter->receive(eventIter->second, true);
+// LOG(INFO) << "Reevaluating: >> " << eventIter->first << " <<";
+ if (eventIter->timeout > 0 && tthread::chrono::system_clock::now() < eventIter->timeout) {
+ // TODO: We should use an event queue
+// LOG(INFO) << " -> Timeout";
+ eventIter->event.name += ".timeout";
+ interpreter->receive(eventIter->event, true);
+ _postponedEvents.erase(eventIter);
+ break;
+ }
+ if (interpreter->getDataModel().evalAsBool(eventIter->until)) {
+// LOG(INFO) << " -> is TRUE";
+ eventIter->event.name += ".postponed";
+ interpreter->receive(eventIter->event, true);
_postponedEvents.erase(eventIter);
break;
}
- LOG(INFO) << " -> is FALSE";
+// LOG(INFO) << " -> is FALSE";
} catch (Event e) {
LOG(ERROR) << "Syntax error while evaluating until attribute of postpone element:" << std::endl << e << std::endl;
_postponedEvents.erase(eventIter++);
diff --git a/src/uscxml/plugins/element/postpone/PostponeElement.h b/src/uscxml/plugins/element/postpone/PostponeElement.h
index 03aafde..eb7a738 100644
--- a/src/uscxml/plugins/element/postpone/PostponeElement.h
+++ b/src/uscxml/plugins/element/postpone/PostponeElement.h
@@ -12,6 +12,14 @@ namespace uscxml {
class PostponeElement : public ExecutableContentImpl {
public:
+ struct Postponed {
+ Postponed(const Event& event, const std::string& until, long timeout) :
+ event(event), until(until), timeout(timeout) {}
+ Event event;
+ std::string until;
+ uint64_t timeout;
+ };
+
PostponeElement() {}
virtual ~PostponeElement() {}
boost::shared_ptr<ExecutableContentImpl> create(Interpreter* interpreter);
@@ -40,13 +48,13 @@ protected:
}
static Resubmitter* getInstance(Interpreter* interpreter);
- static void postpone(const Event& event, std::string until, Interpreter* interpreter);
+ static void postpone(const Event& event, std::string until, uint64_t timeout, Interpreter* interpreter);
// InterpreterMonitor
void onStableConfiguration(Interpreter* interpreter);
void afterCompletion(Interpreter* interpreter);
- std::list<std::pair<std::string, Event> > _postponedEvents;
+ std::list<Postponed> _postponedEvents;
static std::map<Interpreter*, Resubmitter*> _instances;
static tthread::recursive_mutex _accessLock;
diff --git a/src/uscxml/plugins/element/response/ResponseElement.cpp b/src/uscxml/plugins/element/response/ResponseElement.cpp
index 62ebf34..2e25b27 100644
--- a/src/uscxml/plugins/element/response/ResponseElement.cpp
+++ b/src/uscxml/plugins/element/response/ResponseElement.cpp
@@ -52,7 +52,7 @@ void ResponseElement::enterElement(const Arabica::DOM::Node<std::string>& node)
return;
}
httpReply.status = strTo<int>(statusStr);;
-
+
// extract the content
Arabica::XPath::NodeSet<std::string> contents = Interpreter::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "content", node);
if (contents.size() > 0) {
@@ -63,91 +63,90 @@ void ResponseElement::enterElement(const Arabica::DOM::Node<std::string>& node)
httpReply.content = contentValue;
} catch (Event e) {
LOG(ERROR) << "Syntax error with expr in content child of response element:" << std::endl << e << std::endl;
- return;
+ return;
}
} else {
LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
- return;
+ return;
}
} else if (HAS_ATTR(contents[0], "file") || HAS_ATTR(contents[0], "fileexpr")) { // -- content is from file ------
- URL file;
+ URL file;
if (HAS_ATTR(contents[0], "fileexpr")) {
- if (_interpreter->getDataModel()) {
- try {
- file = "file://" + _interpreter->getDataModel().evalAsString(ATTR(contents[0], "fileexpr"));
- } catch (Event e) {
- LOG(ERROR) << "Syntax error with fileexpr in content child of response element:" << std::endl << e << std::endl;
- return;
- }
+ if (_interpreter->getDataModel()) {
+ try {
+ file = "file://" + _interpreter->getDataModel().evalAsString(ATTR(contents[0], "fileexpr"));
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error with fileexpr in content child of response element:" << std::endl << e << std::endl;
+ return;
+ }
}
} else {
- file = "file://" + ATTR(contents[0], "fileexpr");
+ file = "file://" + ATTR(contents[0], "fileexpr");
+ }
+ if (file) {
+ httpReply.content = file.getInContent();
+ size_t lastDot;
+ if ((lastDot = file.path().find_last_of(".")) != std::string::npos) {
+ std::string extension = file.path().substr(lastDot + 1);
+ std::string mimeType = HTTPServer::mimeTypeForExtension(extension);
+ if (mimeType.length() > 0) {
+ httpReply.headers["Content-Type"] = mimeType;
+ }
+ }
}
- if (file) {
- httpReply.content = file.getInContent();
- size_t lastDot;
- if ((lastDot = file.path().find_last_of(".")) != std::string::npos) {
- std::string extension = file.path().substr(lastDot + 1);
- std::string mimeType = HTTPServer::mimeTypeForExtension(extension);
- if (mimeType.length() > 0) {
- httpReply.headers["Content-Type"] = mimeType;
- }
- }
- }
} else if (contents[0].hasChildNodes()) { // -- content embedded as child nodes ------
httpReply.content = contents[0].getFirstChild().getNodeValue();
} else {
LOG(ERROR) << "content element does not specify any content.";
- return;
+ return;
}
}
- // process headers
+ // process headers
Arabica::XPath::NodeSet<std::string> headers = Interpreter::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "header", node);
- for (int i = 0; i < headers.size(); i++) {
- std::string name;
- if (HAS_ATTR(headers[i], "name")) {
- name = ATTR(headers[i], "name");
- } else if(HAS_ATTR(headers[i], "nameexpr")) {
- if (_interpreter->getDataModel()) {
- try {
- name = _interpreter->getDataModel().evalAsString(ATTR(headers[i], "nameexpr"));
- } catch (Event e) {
- LOG(ERROR) << "Syntax error with nameexpr in header child of response element:" << std::endl << e << std::endl;
- return;
- }
- } else {
+ for (int i = 0; i < headers.size(); i++) {
+ std::string name;
+ if (HAS_ATTR(headers[i], "name")) {
+ name = ATTR(headers[i], "name");
+ } else if(HAS_ATTR(headers[i], "nameexpr")) {
+ if (_interpreter->getDataModel()) {
+ try {
+ name = _interpreter->getDataModel().evalAsString(ATTR(headers[i], "nameexpr"));
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error with nameexpr in header child of response element:" << std::endl << e << std::endl;
+ return;
+ }
+ } else {
LOG(ERROR) << "header element has nameexpr attribute but no datamodel is specified.";
- return;
- }
- } else {
- LOG(ERROR) << "header element has no name or nameexpr attribute.";
- return;
- }
-
- std::string value;
- if (HAS_ATTR(headers[i], "value")) {
- value = ATTR(headers[i], "value");
- } else if(HAS_ATTR(headers[i], "expr")) {
- if (_interpreter->getDataModel()) {
- try {
- value = _interpreter->getDataModel().evalAsString(ATTR(headers[i], "expr"));
- } catch (Event e) {
- LOG(ERROR) << "Syntax error with expr in header child of response element:" << std::endl << e << std::endl;
- return;
- }
- } else {
+ return;
+ }
+ } else {
+ LOG(ERROR) << "header element has no name or nameexpr attribute.";
+ return;
+ }
+
+ std::string value;
+ if (HAS_ATTR(headers[i], "value")) {
+ value = ATTR(headers[i], "value");
+ } else if(HAS_ATTR(headers[i], "expr")) {
+ if (_interpreter->getDataModel()) {
+ try {
+ value = _interpreter->getDataModel().evalAsString(ATTR(headers[i], "expr"));
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error with expr in header child of response element:" << std::endl << e << std::endl;
+ return;
+ }
+ } else {
LOG(ERROR) << "header element has expr attribute but no datamodel is specified.";
- return;
- }
- } else {
- LOG(ERROR) << "header element has no value or expr attribute.";
- return;
- }
-
- httpReply.headers[name] = value;
- }
-
+ return;
+ }
+ } else {
+ LOG(ERROR) << "header element has no value or expr attribute.";
+ return;
+ }
+
+ httpReply.headers[name] = value;
+ }
// send the reply
HTTPServer::reply(httpReply);
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
index 37be3e0..675135a 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
@@ -25,10 +25,10 @@ bool connect(pluma::Host& host) {
#endif
DirMonInvoker::DirMonInvoker() :
- _reportExisting(true),
- _reportHidden(false),
- _recurse(false),
- _thread(NULL) {
+ _reportExisting(true),
+ _reportHidden(false),
+ _recurse(false),
+ _thread(NULL) {
}
DirMonInvoker::~DirMonInvoker() {
@@ -55,222 +55,329 @@ void DirMonInvoker::cancel(const std::string sendId) {
}
void DirMonInvoker::invoke(const InvokeRequest& req) {
- if (req.params.find("dir") != req.params.end() && boost::iequals(req.params.find("reportexisting")->second, "false"))
+ if (req.params.find("dir") == req.params.end()) {
+ LOG(ERROR) << "No dir param given";
+ return;
+ }
+
+ if (boost::iequals(req.params.find("reportexisting")->second, "false"))
_reportExisting = false;
- if (req.params.find("recurse") != req.params.end() && boost::iequals(req.params.find("recurse")->second, "true"))
+ if (req.params.find("recurse") != req.params.end() &&
+ boost::iequals(req.params.find("recurse")->second, "true"))
_recurse = true;
- if (req.params.find("reporthidden") != req.params.end() && boost::iequals(req.params.find("reporthidden")->second, "true"))
+ if (req.params.find("reporthidden") != req.params.end() &&
+ boost::iequals(req.params.find("reporthidden")->second, "true"))
_reportHidden = true;
-
- std::string suffixList;
- if (req.params.find("suffix") != req.params.end()) {
- suffixList = req.params.find("suffix")->second;
- } else if (req.params.find("suffixes") != req.params.end()) {
- suffixList = req.params.find("suffixes")->second;
- }
-
- if (suffixList.size() > 0) {
- // seperate path into components
- std::stringstream ss(suffixList);
- std::string item;
- while(std::getline(ss, item, ' ')) {
- if (item.length() == 0)
- continue;
- _suffixes.insert(item);
- }
- }
-
+
+ std::string suffixList;
+ if (req.params.find("suffix") != req.params.end()) {
+ suffixList = req.params.find("suffix")->second;
+ } else if (req.params.find("suffixes") != req.params.end()) {
+ suffixList = req.params.find("suffixes")->second;
+ }
+
+ if (suffixList.size() > 0) {
+ // seperate path into components
+ std::stringstream ss(suffixList);
+ std::string item;
+ while(std::getline(ss, item, ' ')) {
+ if (item.length() == 0)
+ continue;
+ _suffixes.insert(item);
+ }
+ }
+
std::multimap<std::string, std::string>::const_iterator dirIter = req.params.find("dir");
while(dirIter != req.params.upper_bound("dir")) {
URL url(dirIter->second);
if (!_interpreter->toAbsoluteURI(url) || !boost::iequals(url.scheme(), "file")) {
LOG(ERROR) << "Given directory '" << dirIter->second << "' cannot be transformed to absolute path";
} else {
- _watchIds.insert(std::make_pair(url.path(), _fileWatcher.addWatch(url.path(), this, _recurse)));
+ _dir = url.path();
}
- dirIter++;
+ break;
}
+
+ _watcher = new DirectoryWatch(_dir, _recurse);
+ _watcher->addMonitor(this);
+ _watcher->updateEntries(true);
+
_isRunning = true;
_thread = new tthread::thread(DirMonInvoker::run, this);
}
void DirMonInvoker::run(void* instance) {
- if (((DirMonInvoker*)instance)->_reportExisting)
- ((DirMonInvoker*)instance)->reportExisting();
-
- while(((DirMonInvoker*)instance)->_isRunning)
- ((DirMonInvoker*)instance)->_fileWatcher.update();
+ while(((DirMonInvoker*)instance)->_isRunning) {
+ ((DirMonInvoker*)instance)->_watcher->updateEntries();
+ tthread::this_thread::sleep_for(tthread::chrono::milliseconds(20));
+ }
}
-void DirMonInvoker::reportExisting() {
- std::multimap<std::string, FW::WatchID>::iterator watchIter = _watchIds.begin();
- while(watchIter != _watchIds.end()) {
- reportExistingIn(watchIter->first, watchIter->second);
- watchIter++;
+void DirMonInvoker::handleChanges(DirectoryWatch::Action action, const std::string reportedDir, const std::string reportedFilename, struct stat fileStat) {
+
+// std::cout << action << " on " << reportedFilename << std::endl;
+
+ std::string path; // complete path to the file including filename
+ std::string relPath; // path relative to monitored directory including filename
+ std::string dir; // the name of the directory we monitor
+ std::string relDir; // the directory from dir to the actual directory where we found a file
+ std::string basename; // filename including suffix
+ std::string strippedName; // filename without the suffix
+ std::string extension; // the extension
+
+ dir = reportedDir;
+
+ path = dir + reportedFilename;
+ boost::algorithm::replace_all(path, "\\", "/");
+ boost::algorithm::replace_all(path, "//", "/");
+
+ assert(boost::algorithm::starts_with(path, dir));
+ relPath = path.substr(dir.length());
+ assert(boost::equal(path, dir + relPath));
+
+ size_t lastSep;
+ if ((lastSep = path.find_last_of(PATH_SEPERATOR)) != std::string::npos) {
+ lastSep++;
+ basename = path.substr(lastSep, path.length() - lastSep);
+ } else {
+ assert(false);
}
-}
+ assert(boost::algorithm::ends_with(relPath, basename));
+
+ // extension is the suffix and strippedName the basename without the suffix
+ size_t lastDot;
+ if ((lastDot = basename.find_last_of(".")) != std::string::npos) {
+ if (lastDot == 0) {
+ // hidden file
+ strippedName = basename;
+ } else {
+ extension = basename.substr(lastDot + 1);
+ strippedName = basename.substr(0, lastDot);
+ }
+ } else {
+ strippedName = basename;
+ }
+
+ relDir = relPath.substr(0, relPath.length() - basename.length());
+ assert(boost::equal(path, dir + relDir + basename));
-void DirMonInvoker::handleFileAction(FW::WatchID watchid, const FW::String& dir, const FW::String& filename, FW::Action action) {
-
- std::string path;
- if (!boost::algorithm::starts_with(filename, dir)) {
- path = dir + filename;
- } else {
- path = filename;
- }
-
- if (_suffixes.size() > 0) {
- bool validSuffix = false;
- std::set<std::string>::iterator suffixIter = _suffixes.begin();
- while(suffixIter != _suffixes.end()) {
- if (boost::algorithm::ends_with(path, *suffixIter)) {
- validSuffix = true;
- break;
- }
- suffixIter++;
- }
- if (!validSuffix)
- return;
- }
+ // return if this is a hidden file
+ if (boost::algorithm::starts_with(basename, ".") && !_reportHidden)
+ return;
+
+ // ilter suffixes
+ if (_suffixes.size() > 0) {
+ bool validSuffix = false;
+ std::set<std::string>::iterator suffixIter = _suffixes.begin();
+ while(suffixIter != _suffixes.end()) {
+ if (boost::algorithm::ends_with(path, *suffixIter)) {
+ validSuffix = true;
+ break;
+ }
+ suffixIter++;
+ }
+ if (!validSuffix)
+ return;
+ }
Event event;
event.invokeid = _invokeId;
+
switch (action) {
- case FW::Actions::Existing:
+ case DirectoryWatch::EXISTING:
event.name = "file.existing";
break;
- case FW::Actions::Add:
+ case DirectoryWatch::ADDED:
event.name = "file.added";
break;
- case FW::Actions::Delete:
+ case DirectoryWatch::DELETED:
event.name = "file.deleted";
break;
- case FW::Actions::Modified:
+ case DirectoryWatch::MODIFIED:
event.name = "file.modified";
break;
default:
break;
}
- // basename is the filename with suffix
- std::string basename;
- size_t lastSep;
- if ((lastSep = path.find_last_of(PATH_SEPERATOR)) != std::string::npos) {
- lastSep++;
- basename = path.substr(lastSep, path.length() - lastSep);
- event.data.compound["file"].compound["name"] = Data(basename, Data::VERBATIM);
- }
-
- // return if this is a hidden file
- if (boost::algorithm::starts_with(basename, ".") && !_reportHidden)
- return;
-
- struct stat fileStat;
- if (action != FW::Actions::Delete) {
- if (stat(path.c_str(), &fileStat) != 0) {
- LOG(ERROR) << "Error with stat on directory entry " << path << ": " << strerror(errno);
- return;
- } else {
- event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime);
- event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime);
- event.data.compound["file"].compound["atime"] = toStr(fileStat.st_atime);
- event.data.compound["file"].compound["size"] = toStr(fileStat.st_size);
- }
- }
-
- // extension is the suffix and strippedName the basename without the suffix
- size_t lastDot;
- if ((lastDot = basename.find_last_of(".")) != std::string::npos) {
- std::string extension = basename.substr(lastDot + 1);
- event.data.compound["file"].compound["extension"] = Data(extension, Data::VERBATIM);
- std::string strippedName = basename.substr(0, lastDot);
- event.data.compound["file"].compound["strippedName"] = Data(strippedName, Data::VERBATIM);
- }
-
- // relpath is the path to the file relative to the dir
- if (boost::algorithm::starts_with(filename, dir)) {
- std::string relPath = filename.substr(dir.length());
- event.data.compound["file"].compound["relPath"] = Data(relPath, Data::VERBATIM);
-
- // relDir is the relpath without the basename
- if ((lastSep = relPath.find_last_of(PATH_SEPERATOR)) != std::string::npos) {
- lastSep++;
- std::string relDir = relPath.substr(0, lastSep);
- event.data.compound["file"].compound["relDir"] = Data(relDir, Data::VERBATIM);
- }
+ if (action != DirectoryWatch::DELETED) {
+ event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime);
+ event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime);
+ event.data.compound["file"].compound["atime"] = toStr(fileStat.st_atime);
+ event.data.compound["file"].compound["size"] = toStr(fileStat.st_size);
}
+ event.data.compound["file"].compound["name"] = Data(basename, Data::VERBATIM);
+ event.data.compound["file"].compound["extension"] = Data(extension, Data::VERBATIM);
+ event.data.compound["file"].compound["strippedName"] = Data(strippedName, Data::VERBATIM);
+ event.data.compound["file"].compound["relPath"] = Data(relPath, Data::VERBATIM);
+ event.data.compound["file"].compound["relDir"] = Data(relDir, Data::VERBATIM);
event.data.compound["file"].compound["path"] = Data(path, Data::VERBATIM);
event.data.compound["file"].compound["dir"] = Data(dir, Data::VERBATIM);
returnEvent(event);
}
-bool DirMonInvoker::filter(const std::string filename) {
- return true;
+void DirectoryWatch::reportAsDeleted() {
+ std::map<std::string, struct stat>::iterator fileIter = _knownEntries.begin();
+ while(fileIter != _knownEntries.end()) {
+ if (fileIter->second.st_mode & S_IFDIR) {
+ _knownDirs[fileIter->first]->reportAsDeleted();
+ delete _knownDirs[fileIter->first];
+ _knownDirs.erase(fileIter->first);
+ } else {
+ _monitors_t::iterator monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ (*monIter)->handleChanges(DELETED, _dir, _relDir + PATH_SEPERATOR + fileIter->first, fileIter->second);
+ monIter++;
+ }
+ }
+ _knownEntries.erase(fileIter->first);
+ fileIter++;
+ }
+ assert(_knownDirs.size() == 0);
+ assert(_knownEntries.size() == 0);
}
-void DirMonInvoker::reportExistingIn(const std::string dir, FW::WatchID watchid) {
-#ifndef WIN32
- DIR *dp;
- dp = opendir(dir.c_str());
- if (dp == NULL) {
- LOG(ERROR) << "Error opening directory " << dir << ": " << strerror(errno);
+void DirectoryWatch::updateEntries(bool reportAsExisting) {
+ _monitors_t::iterator monIter;
+ if (_dir[_dir.length() - 1] == PATH_SEPERATOR)
+ _dir = _dir.substr(0, _dir.length() - 1);
+
+ // stat directory for modification date
+ struct stat dirStat;
+ if (stat((_dir + _relDir).c_str(), &dirStat) != 0) {
+ LOG(ERROR) << "Error with stat on directory " << _dir << ": " << strerror(errno);
return;
}
- // iterate all entries and see what changed
- struct dirent* entry;
- while((entry = readdir(dp))) {
- std::string dname = entry->d_name;
+
+ if ((unsigned)dirStat.st_mtime >= (unsigned)_lastChecked) {
+ // there are changes in the directory
+ std::set<std::string> currEntries;
+
+#ifndef WIN32
+ DIR *dp;
+ dp = opendir((_dir + _relDir).c_str());
+ if (dp == NULL) {
+ LOG(ERROR) << "Error opening directory " << _dir + _relDir << ": " << strerror(errno);
+ return;
+ }
+ // iterate all entries and see what changed
+ struct dirent* entry;
+ while((entry = readdir(dp))) {
+ std::string dname = entry->d_name;
#else
- WIN32_FIND_DATA ffd;
- HANDLE hFind = INVALID_HANDLE_VALUE;
- TCHAR szDir[MAX_PATH];
- StringCchCopy(szDir, MAX_PATH, dir.c_str());
- StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
-
- hFind = FindFirstFile(szDir, &ffd);
- do {
- std::string dname = ffd.cFileName;
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ TCHAR szDir[MAX_PATH];
+ StringCchCopy(szDir, MAX_PATH, _dir.c_str());
+ StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
+
+ hFind = FindFirstFile(szDir, &ffd);
+ do {
+ string dname = ffd.cFileName;
#endif
- if (boost::iequals(dname, ".") || boost::iequals(dname, ".."))
- continue;
+ // see if the file was changed
+ char* filename;
+ asprintf(&filename, "%s/%s", (_dir + _relDir).c_str(), dname.c_str());
- char* filename = (char*)malloc(dir.size() + dname.size() + 2);
- sprintf(filename, "%s/%s", dir.c_str(), dname.c_str());
+ struct stat fileStat;
+ if (stat(filename, &fileStat) != 0) {
+ LOG(ERROR) << "Error with stat on directory entry: " << filename << ": " << strerror(errno);
+ free(filename);
+ continue;
+ }
- struct stat fileStat;
- if (stat(filename, &fileStat) != 0) {
- LOG(ERROR) << "Error with stat on directory entry " << filename << ": " << strerror(errno);
- free(filename);
- continue;
- }
+ if (fileStat.st_mode & S_IFDIR) {
+ if (boost::equals(dname, ".") || boost::equals(dname, "..")) {
+ free(filename);
+ continue; // do not report . or ..
+ }
+ }
- if (fileStat.st_mode & S_IFDIR) {
- if (_recurse) {
- reportExistingIn(filename, watchid);
+ currEntries.insert(dname);
+
+ if (_knownEntries.find(dname) != _knownEntries.end()) {
+ // we have seen this entry before
+ struct stat oldStat = _knownEntries[dname];
+ if (oldStat.st_mtime < fileStat.st_mtime) {
+ monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ (*monIter)->handleChanges(MODIFIED, _dir, _relDir + PATH_SEPERATOR + dname, fileStat);
+ monIter++;
+ }
+ }
} else {
- free(filename);
- continue;
+ // we have not yet seen this entry
+ if (fileStat.st_mode & S_IFDIR) {
+ _knownDirs[dname] = new DirectoryWatch(_dir, _relDir + PATH_SEPERATOR + dname);
+ monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ _knownDirs[dname]->addMonitor(*monIter);
+ monIter++;
+ }
+ } else {
+ monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ if (reportAsExisting) {
+ (*monIter)->handleChanges(EXISTING, _dir, _relDir + PATH_SEPERATOR + dname, fileStat);
+ } else {
+ (*monIter)->handleChanges(ADDED, _dir, _relDir + PATH_SEPERATOR + dname, fileStat);
+ }
+ monIter++;
+ }
+ }
}
- }
- if (!filter(dname)) {
free(filename);
- continue;
+ _knownEntries[dname] = fileStat; // gets copied on insertion
+#ifndef WIN32
}
-
- handleFileAction(watchid, dir, filename, FW::Actions::Existing);
+ closedir(dp);
+#else
+ }
+ while (FindNextFile(hFind, &ffd) != 0);
+ FindClose(hFind);
+#endif
+ // are there any known entries we have not seen this time around?
+ std::map<std::string, struct stat>::iterator fileIter = _knownEntries.begin();
+ while(fileIter != _knownEntries.end()) {
+ if (currEntries.find(fileIter->first) == currEntries.end()) {
+ // we used to know this file
+ if (fileIter->second.st_mode & S_IFDIR) {
+ if (_recurse) {
+ _knownDirs[fileIter->first]->reportAsDeleted();
+ delete _knownDirs[fileIter->first];
+ _knownDirs.erase(fileIter->first);
+ }
+ } else {
+ monIter = _monitors.begin();
+ while(monIter != _monitors.end()) {
+ (*monIter)->handleChanges(DELETED, _dir, _relDir + PATH_SEPERATOR + fileIter->first, fileIter->second);
+ monIter++;
+ }
+ }
+ _knownEntries.erase(fileIter->first);
+ }
+ fileIter++;
+ }
+ // remember when we last checked the directory for modifications
#ifndef WIN32
- }
- closedir(dp);
+ time(&_lastChecked);
#else
- }
- while (FindNextFile(hFind, &ffd) != 0);
- FindClose(hFind);
+ // TODO: this will fail with sub-millisecond updates to the directory
+ _lastChecked = dirStat.st_mtime + 1;
#endif
-
+ // update all directories
+ }
+ if (_recurse) {
+ std::map<std::string, DirectoryWatch*>::iterator dirIter = _knownDirs.begin();
+ while(dirIter != _knownDirs.end()) {
+ dirIter->second->updateEntries();
+ dirIter++;
+ }
+ }
}
} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
index 04e670d..3fd9258 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.h
@@ -2,8 +2,8 @@
#define DIRMONINVOKER_H_W09J90F0
#include <uscxml/Interpreter.h>
-#include "FileWatcher/FileWatcher.h"
#include <map>
+#include <sys/stat.h>
#ifdef BUILD_AS_PLUGINS
#include "uscxml/plugins/Plugins.h"
@@ -11,7 +11,48 @@
namespace uscxml {
-class DirMonInvoker : public InvokerImpl, public FW::FileWatchListener {
+class DirectoryWatchMonitor;
+
+class DirectoryWatch {
+public:
+ enum Action {
+ ADDED = 1,
+ MODIFIED = 2,
+ DELETED = 4,
+ EXISTING = 8
+ };
+
+ DirectoryWatch(const std::string& dir, bool recurse = false) : _dir(dir), _recurse(recurse), _lastChecked(0) {}
+
+ void addMonitor(DirectoryWatchMonitor* monitor) {
+ _monitors.insert(monitor);
+ }
+ void removeMonitor(DirectoryWatchMonitor* monitor) {
+ _monitors.erase(monitor);
+ }
+ void updateEntries(bool reportAsExisting = false);
+ void reportAsDeleted();
+
+protected:
+ DirectoryWatch(const std::string& dir, const std::string& relDir) : _dir(dir), _relDir(relDir), _recurse(true), _lastChecked(0) {}
+
+ std::string _dir;
+ std::string _relDir;
+
+ bool _recurse;
+ std::map<std::string, struct stat> _knownEntries;
+ std::map<std::string, DirectoryWatch*> _knownDirs;
+ std::set<DirectoryWatchMonitor*> _monitors;
+ typedef std::set<DirectoryWatchMonitor*> _monitors_t;
+ time_t _lastChecked;
+};
+
+class DirectoryWatchMonitor {
+public:
+ virtual void handleChanges(DirectoryWatch::Action action, const std::string dir, const std::string file, struct stat fileStat) = 0;
+};
+
+class DirMonInvoker : public InvokerImpl, public DirectoryWatchMonitor {
public:
DirMonInvoker();
virtual ~DirMonInvoker();
@@ -30,10 +71,7 @@ public:
virtual void cancel(const std::string sendId);
virtual void invoke(const InvokeRequest& req);
- void handleFileAction(FW::WatchID watchid, const FW::String& dir, const FW::String& filename, FW::Action action);
- void reportExisting();
- void reportExistingIn(const std::string dir, FW::WatchID watchid);
- virtual bool filter(const std::string filename);
+ virtual void handleChanges(DirectoryWatch::Action action, const std::string dir, const std::string file, struct stat fileStat);
static void run(void* instance);
@@ -41,12 +79,15 @@ protected:
bool _reportExisting;
bool _reportHidden;
bool _recurse;
- std::set<std::string> _suffixes;
+
+ std::string _dir;
+ std::set<std::string> _suffixes;
bool _isRunning;
tthread::thread* _thread;
- FW::FileWatcher _fileWatcher;
- std::multimap<std::string, FW::WatchID> _watchIds;
+ tthread::recursive_mutex _mutex;
+
+ DirectoryWatch* _watcher;
};
#ifdef BUILD_AS_PLUGINS
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp
index e1634b0..a47d635 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.cpp
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
+#include <iostream>
// this is more suited:
// https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/FSEvents_ProgGuide/UsingtheFSEventsFramework/UsingtheFSEventsFramework.html
@@ -71,18 +72,20 @@ struct WatchStruct {
WatchID mWatchID;
String mDirName;
FileWatchListener* mListener;
+ FileWatcherOSX* mWatcher;
+ bool mRecursive;
// index 0 is always the directory
KEvent mChangeList[MAX_CHANGE_EVENT_SIZE];
size_t mChangeListCount;
- WatchStruct(WatchID watchid, const String& dirname, FileWatchListener* listener)
- : mWatchID(watchid), mDirName(dirname), mListener(listener) {
+ WatchStruct(WatchID watchid, const String& dirname, FileWatchListener* listener, FileWatcherOSX* watcher, bool recursive = false)
+ : mWatchID(watchid), mDirName(dirname), mListener(listener), mWatcher(watcher), mRecursive(recursive) {
mChangeListCount = 0;
addAll();
}
- void addFile(const String& name, bool imitEvents = true) {
+ void addFile(const String& name, bool emitEvents = true) {
//fprintf(stderr, "ADDED: %s\n", name.c_str());
// create entry
@@ -104,18 +107,18 @@ struct WatchStruct {
// set the event data at the end of the list
EV_SET(&mChangeList[mChangeListCount], fd, EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_ONESHOT,
- NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB,
+ NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
0, (void*)entry);
// qsort
qsort(mChangeList + 1, mChangeListCount, sizeof(KEvent), comparator);
// handle action
- if(imitEvents)
+ if(emitEvents)
handleAction(name, Actions::Add);
}
- void removeFile(const String& name, bool imitEvents = true) {
+ void removeFile(const String& name, bool emitEvents = true) {
// bsearch
KEvent target;
EntryStruct tempEntry(name.c_str(), 0);
@@ -140,7 +143,7 @@ struct WatchStruct {
qsort(mChangeList + 1, mChangeListCount, sizeof(KEvent), comparator);
// handle action
- if(imitEvents)
+ if(emitEvents)
handleAction(name, Actions::Delete);
}
@@ -207,7 +210,7 @@ struct WatchStruct {
int fd = open(mDirName.c_str(), O_RDONLY);
EV_SET(&mChangeList[0], fd, EVFILT_VNODE,
EV_ADD | EV_ENABLE | EV_ONESHOT,
- NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB,
+ NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME,
0, 0);
//fprintf(stderr, "ADDED: %s\n", mDirName.c_str());
@@ -222,11 +225,13 @@ struct WatchStruct {
while((entry = readdir(dir)) != NULL) {
String fname = (mDirName + "/" + String(entry->d_name));
stat(fname.c_str(), &attrib);
- if(S_ISREG(attrib.st_mode))
+ if(S_ISREG(attrib.st_mode)) {
addFile(fname, false);
- //else
- // fprintf(stderr, "NOT ADDED: %s (%d)\n", fname.c_str(), attrib.st_mode);
-
+ } else if(S_IFDIR && mRecursive && entry->d_name[0] != '.') {
+ mWatcher->addWatch(fname, mListener, mRecursive);
+ } else {
+ fprintf(stderr, "NOT ADDED: %s (%d)\n", fname.c_str(), attrib.st_mode);
+ }
}//end while
closedir(dir);
@@ -263,19 +268,33 @@ void FileWatcherOSX::update() {
if(nev == -1)
perror("kevent");
else {
+ if (event.fflags & NOTE_DELETE) {
+ fprintf(stderr, "NOTE_DELETE ");
+ }
+ if (event.fflags & NOTE_EXTEND) {
+ fprintf(stderr, "NOTE_EXTEND ");
+ }
+ if (event.fflags & NOTE_WRITE) {
+ fprintf(stderr, "NOTE_WRITE ");
+ }
+ if (event.fflags & NOTE_ATTRIB) {
+ fprintf(stderr, "NOTE_ATTRIB ");
+ }
+ if (event.fflags & NOTE_RENAME) {
+ fprintf(stderr, "NOTE_RENAME ");
+ }
+
EntryStruct* entry = 0;
if((entry = (EntryStruct*)event.udata) != 0) {
- //fprintf(stderr, "File: %s -- ", (char*)entry->mFilename);
+ fprintf(stderr, " to %s -- \n", (char*)entry->mFilename);
if(event.fflags & NOTE_DELETE) {
- //fprintf(stderr, "File deleted\n");
//watch->handleAction(entry->mFilename, Action::Delete);
watch->removeFile(entry->mFilename);
}
if(event.fflags & NOTE_EXTEND ||
event.fflags & NOTE_WRITE ||
event.fflags & NOTE_ATTRIB) {
- //fprintf(stderr, "modified\n");
//watch->rescan();
struct stat attrib;
stat(entry->mFilename, &attrib);
@@ -283,7 +302,7 @@ void FileWatcherOSX::update() {
watch->handleAction(entry->mFilename, FW::Actions::Modified);
}
} else {
- //fprintf(stderr, "Dir: %s -- rescanning\n", watch->mDirName.c_str());
+ fprintf(stderr, " in %s -- rescanning\n", watch->mDirName.c_str());
watch->rescan();
}
}
@@ -295,7 +314,7 @@ void FileWatcherOSX::update() {
FileWatcherOSX::FileWatcherOSX() {
mDescriptor = kqueue();
mTimeOut.tv_sec = 0;
- mTimeOut.tv_nsec = 2000000;
+ mTimeOut.tv_nsec = 20000000;
}
//--------
@@ -322,9 +341,12 @@ WatchID FileWatcherOSX::addWatch(const String& directory, FileWatchListener* wat
0, (void*)"testing");
*/
- WatchStruct* watch = new WatchStruct(++mLastWatchID, directory, watcher);
- mWatches.insert(std::make_pair(mLastWatchID, watch));
- return mLastWatchID;
+ std::cout << "Adding watch for " << directory << std::endl;
+
+ WatchID currWatch = ++mLastWatchID;
+ WatchStruct* watch = new WatchStruct(currWatch, directory, watcher, this, recursive);
+ mWatches.insert(std::make_pair(currWatch, watch));
+ return currWatch;
}
//--------
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h b/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h
index 39f411c..92e3957 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/FileWatcher/FileWatcherOSX.h
@@ -54,7 +54,7 @@ public:
/// Add a directory watch
/// @exception FileNotFoundException Thrown when the requested directory does not exist
- WatchID addWatch(const String& directory, FileWatchListener* watcher, bool recursive);
+ WatchID addWatch(const String& directory, FileWatchListener* watcher, bool recursive = false);
/// Remove a directory watch. This is a brute force lazy search O(nlogn).
void removeWatch(const String& directory);
@@ -78,6 +78,7 @@ private:
/// WatchID allocator
int mLastWatchID;
+ friend class WatchStruct;
};//end FileWatcherOSX
};//namespace FW
diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp
index ea249e4..2fa2877 100644
--- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp
+++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp
@@ -5,10 +5,12 @@
#include <osg/MatrixTransform>
#include <osg/Node>
#include <osg/Group>
+#include <osg/ComputeBoundsVisitor>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>
#include <osgGA/TrackballManipulator>
+#include <osgGA/AnimationPathManipulator>
#include <osg/ShapeDrawable>
#include <boost/lexical_cast.hpp>
@@ -91,6 +93,20 @@ void OSGConverter::send(const SendRequest& req) {
}
}
+ boost::algorithm::replace_all(actualReq.params.find("dest")->second, "//", "/");
+ boost::algorithm::replace_all(actualReq.params.find("dest")->second, "\\\\", "\\");
+
+ if (actualReq.params.find("autorotate") == actualReq.params.end()) {
+ if (actualReq.params.find("autorotateexpr") != actualReq.params.end()) {
+ if (_interpreter->getDataModel()) {
+ actualReq.params.insert(std::make_pair("autorotate", _interpreter->getDataModel().evalAsString(actualReq.params.find("autorotateexpr")->second)));
+ } else {
+ LOG(ERROR) << "SendRequests for osginvoker ncludes autorotateexpr but no datamodel is specified";
+ return;
+ }
+ }
+ }
+
if (actualReq.params.find("format") == actualReq.params.end()) {
// no explicit format
if (actualReq.params.find("formatexpr") != actualReq.params.end() && _interpreter->getDataModel()) {
@@ -111,12 +127,26 @@ void OSGConverter::send(const SendRequest& req) {
}
}
- EVAL_PARAM_EXPR(actualReq.params, "heightexpr", "height");
- EVAL_PARAM_EXPR(actualReq.params, "widthexpr", "width");
- EVAL_PARAM_EXPR(actualReq.params, "pitchexpr", "pitch");
- EVAL_PARAM_EXPR(actualReq.params, "rollexpr", "roll");
- EVAL_PARAM_EXPR(actualReq.params, "yawexpr", "yaw");
- EVAL_PARAM_EXPR(actualReq.params, "zoomexpr", "zoom");
+// assert(osgDB::Registry::instance()->getReaderWriterForExtension("png"));
+// osgDB::Registry::ReaderWriterList formatList = osgDB::Registry::instance()->getReaderWriterList();
+// for (int i = 0; i < formatList.size(); i++) {
+// std::map<std::string, std::string> funcDesc = formatList[i]->supportedProtocols();
+// std::map<std::string, std::string>::iterator funcDescIter = funcDesc.begin();
+// while(funcDescIter != funcDesc.end()) {
+// std::cout << funcDescIter->first << ": " << funcDescIter->second << std::endl;
+// funcDescIter++;
+// }
+// }
+
+ EVAL_PARAM_EXPR(actualReq.params, "heightexpr", "height");
+ EVAL_PARAM_EXPR(actualReq.params, "widthexpr", "width");
+ EVAL_PARAM_EXPR(actualReq.params, "pitchexpr", "pitch");
+ EVAL_PARAM_EXPR(actualReq.params, "rollexpr", "roll");
+ EVAL_PARAM_EXPR(actualReq.params, "yawexpr", "yaw");
+ EVAL_PARAM_EXPR(actualReq.params, "zoomexpr", "zoom");
+ EVAL_PARAM_EXPR(actualReq.params, "xexpr", "x");
+ EVAL_PARAM_EXPR(actualReq.params, "yexpr", "y");
+ EVAL_PARAM_EXPR(actualReq.params, "zexpr", "z");
// process(actualReq);
_workQueue.push(actualReq);
@@ -150,13 +180,13 @@ void OSGConverter::run(void* instance) {
}
void OSGConverter::process(const SendRequest& req) {
-
+
// std::cout << req;
-
- int width = 640;
+
+ int width = 640;
int height = 480;
- CAST_PARAM(req.params, width, "width", int);
- CAST_PARAM(req.params, height, "height", int);
+ CAST_PARAM(req.params, width, "width", int);
+ CAST_PARAM(req.params, height, "height", int);
assert(req.params.find("source") != req.params.end());
assert(req.params.find("dest") != req.params.end());
@@ -166,80 +196,131 @@ void OSGConverter::process(const SendRequest& req) {
std::string dest = req.params.find("dest")->second;
std::string format = req.params.find("format")->second;
- osg::ref_ptr<osg::Node> sceneGraph = setupGraph(source);
+ bool autoRotate = true;
+ if (req.params.find("autorotate") != req.params.end()) {
+ if (boost::iequals(req.params.find("autorotate")->second, "off") ||
+ boost::iequals(req.params.find("autorotate")->second, "0") ||
+ boost::iequals(req.params.find("autorotate")->second, "false")) {
+ autoRotate = false;
+ }
+ }
+
+ osg::ref_ptr<osg::Node> model = setupGraph(source, autoRotate);
+ if (model->asGroup()->getNumChildren() == 0) {
+ reportFailure(req);
+ return;
+ }
+
+ osg::ref_ptr<osg::Group> sceneGraph = new osg::Group();
+ sceneGraph->addChild(model);
osgDB::ReaderWriter::WriteResult result;
if (osgDB::Registry::instance()->getReaderWriterForExtension(format) != NULL) {
// write as another 3D file
result = osgDB::Registry::instance()->writeNode(*sceneGraph, dest, osgDB::Registry::instance()->getOptions());
+ if (result.success()) {
+ // we can know about success right here
+ reportSuccess(req);
+ return;
+ }
}
- if (result.error()) {
- // make a screenshot
- osgViewer::ScreenCaptureHandler::CaptureOperation* cOp = new NameRespectingWriteToFile(dest,
- format,
- osgViewer::ScreenCaptureHandler::WriteToFile::OVERWRITE
- );
-
- osgViewer::ScreenCaptureHandler* captureHandler = new osgViewer::ScreenCaptureHandler(cOp, -1);
-
- osgViewer::Viewer viewer;
- viewer.setSceneData(sceneGraph);
- viewer.setCameraManipulator(new osgGA::TrackballManipulator());
- viewer.addEventHandler(captureHandler);
- captureHandler->startCapture();
-
- osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
- osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(ds);
- traits->width = width;
- traits->height = height;
- traits->pbuffer = true;
- osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
-
- if (!gc.valid()) {
- LOG(ERROR) << "Cannot create GraphicsContext!";
- return;
- }
-
-
- GLenum pbuffer = gc->getTraits()->doubleBuffer ? GL_BACK : GL_FRONT;
-
- viewer.getCamera()->setGraphicsContext(gc.get());
- viewer.getCamera()->setViewport(new osg::Viewport(0,0,traits->width,traits->height));
- viewer.getCamera()->setDrawBuffer(pbuffer);
- viewer.getCamera()->setReadBuffer(pbuffer);
-
- // set background color
- viewer.getCamera()->setClearColor(osg::Vec4f(1.0f,1.0f,1.0f,1.0f));
- viewer.getCamera()->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-// viewer.getCamera()->setViewMatrix(requestToCamPose(req));
-
- viewer.home();
- ((osg::MatrixTransform*)sceneGraph.get())->setMatrix(requestToModelPose(req));
-
- // perform one viewer iteration
- viewer.realize();
- viewer.frame();
+ /**
+ * If we failed to interpret the extension as another 3D file, try to make a screenshot.
+ */
+
+ ((osg::MatrixTransform*)model.get())->setMatrix(requestToModelPose(req));
+ osg::BoundingSphere bs = model->getBound();
+
+// osg::ref_ptr<osg::MatrixTransform> scale = new osg::MatrixTransform();
+// scale->setMatrix(osg::Matrix::scale(bs.radius() / 5, bs.radius() / 5, bs.radius() / 5));
+// scale->addChild(getOrigin());
+// sceneGraph->addChild(scale);
+
+ osgViewer::ScreenCaptureHandler::CaptureOperation* cOp = new NameRespectingWriteToFile(
+ dest,
+ format,
+ osgViewer::ScreenCaptureHandler::WriteToFile::OVERWRITE,
+ req, this);
+
+ osgViewer::ScreenCaptureHandler* captureHandler = new osgViewer::ScreenCaptureHandler(cOp, -1);
+
+ osgViewer::Viewer viewer;
+ viewer.setSceneData(sceneGraph);
+ viewer.setCameraManipulator(new osgGA::TrackballManipulator());
+ viewer.addEventHandler(captureHandler);
+ captureHandler->startCapture();
+
+ osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
+ osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(ds);
+ traits->width = width;
+ traits->height = height;
+ traits->pbuffer = true;
+ osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
+
+ if (!gc.valid()) {
+ LOG(ERROR) << "Cannot create GraphicsContext!";
+ return;
}
+
+ GLenum pbuffer = gc->getTraits()->doubleBuffer ? GL_BACK : GL_FRONT;
+
+ viewer.getCamera()->setGraphicsContext(gc.get());
+ viewer.getCamera()->setViewport(new osg::Viewport(0,0,traits->width,traits->height));
+ viewer.getCamera()->setDrawBuffer(pbuffer);
+ viewer.getCamera()->setReadBuffer(pbuffer);
+
+ // set background color
+ viewer.getCamera()->setClearColor(osg::Vec4f(1.0f,1.0f,1.0f,1.0f));
+ viewer.getCamera()->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ viewer.getCameraManipulator()->setByMatrix(osg::Matrix::lookAt(osg::Vec3d(0,0,bs.radius() * -4), // eye
+ (osg::Vec3d)bs.center(), // center
+ osg::Vec3d(0,1,0))); // up
+
+// viewer.home();
+
+ // perform one viewer iteration
+ viewer.realize();
+ viewer.frame();
+}
+
+void OSGConverter::reportSuccess(const SendRequest& req) {
+ Event event(req);
+ if (event.name.length() == 0)
+ event.name = "convert";
+ event.name += ".success";
+ returnEvent(event);
}
-osg::Matrix OSGConverter::requestToModelPose(const SendRequest& req) {
- double pitch = 0;
- double roll = 0;
- double yaw = 0;
- double zoom = 1;
- CAST_PARAM(req.params, pitch, "pitch", double);
- CAST_PARAM(req.params, roll, "roll", double);
- CAST_PARAM(req.params, yaw, "yaw", double);
- CAST_PARAM(req.params, zoom, "zoom", double);
-
- osg::Matrix m = osg::Matrix::scale(zoom, zoom, zoom) * eulerToMatrix(pitch, roll, yaw);
-
+void OSGConverter::reportFailure(const SendRequest& req) {
+ Event event(req);
+ if (event.name.length() == 0)
+ event.name = "convert";
+ event.name += ".failure";
+ returnEvent(event);
+}
+
+osg::Matrix OSGConverter::requestToModelPose(const SendRequest& req) {
+ double pitch = 0;
+ double roll = 0;
+ double yaw = 0;
+ double zoom = 1;
+ double x = 0;
+ double y = 0;
+ double z = 0;
+ CAST_PARAM(req.params, pitch, "pitch", double);
+ CAST_PARAM(req.params, roll, "roll", double);
+ CAST_PARAM(req.params, yaw, "yaw", double);
+ CAST_PARAM(req.params, zoom, "zoom", double);
+ CAST_PARAM(req.params, x, "x", double);
+ CAST_PARAM(req.params, y, "y", double);
+ CAST_PARAM(req.params, z, "z", double);
+
+ osg::Matrix m = osg::Matrix::scale(zoom, zoom, zoom) * eulerToMatrix(pitch, roll, yaw) * osg::Matrix::translate(-1 * x, -1 * y, -1 * z);
#if 0
- dumpMatrix(m);
+ dumpMatrix(m);
#endif
- return m;
+ return m;
}
osg::Matrix OSGConverter::requestToCamPose(const SendRequest& req) {
@@ -247,17 +328,18 @@ osg::Matrix OSGConverter::requestToCamPose(const SendRequest& req) {
// CAST_PARAM(req.params, zoom, "zoom", double);
// osg::Matrix scale = osg::Matrix::scale(zoom, zoom, zoom);
// return scale;
- osg::Matrix identity;
- identity.makeIdentity();
- return identity;
+ osg::Matrix identity;
+ identity.makeIdentity();
+ return identity;
}
-osg::ref_ptr<osg::Node> OSGConverter::setupGraph(const std::string filename) {
+osg::ref_ptr<osg::Node> OSGConverter::setupGraph(const std::string filename, bool autoRotate) {
/**
* root (model pose)
- * - modelCenter (center model)
- * - model (actual model)
+ * - rotate (autoRotate to face largest side)
+ * - modelCenter (center model)
+ * - model (actual model)
*/
long now = tthread::chrono::system_clock::now();
@@ -275,7 +357,7 @@ osg::ref_ptr<osg::Node> OSGConverter::setupGraph(const std::string filename) {
}
_models[filename] = std::make_pair(now, model);
}
- _models[filename].first = now;
+ _models[filename].first = now;
#if 1
// remove old models from cache
@@ -291,25 +373,66 @@ osg::ref_ptr<osg::Node> OSGConverter::setupGraph(const std::string filename) {
#endif
}
-
- osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform();
+ osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform();
+ osg::ref_ptr<osg::MatrixTransform> rotate = new osg::MatrixTransform();
osg::ref_ptr<osg::Node> model = _models[filename].second;
// translation matrix to move model into center
osg::ref_ptr<osg::MatrixTransform> modelCenter = new osg::MatrixTransform();
modelCenter->addChild(model);
+ rotate->addChild(modelCenter);
// move bounding sphere center into origin
osg::BoundingSphere bs = model->getBound();
modelCenter->setMatrix(osg::Matrix::translate(bs.center() *= -1));
- // add to model pose matrix
- root->addChild(modelCenter);
-
+ // get bounding box
+ osg::ComputeBoundsVisitor cbv;
+ osg::BoundingBox& bb(cbv.getBoundingBox());
+ modelCenter->accept(cbv);
+
+ if (autoRotate) {
+ double depth = bb.zMax() - bb.zMin();
+ double width = bb.xMax() - bb.xMin();
+ double height = bb.yMax() - bb.yMin();
+
+ double frontArea = width * height;
+ double sideArea = depth * height;
+ double topArea = depth * width;
+
+ // rotate by multiples of 90deg to face largest area
+ if (frontArea < sideArea || frontArea < topArea) {
+ if (sideArea < topArea) {
+ // top needs to come to front -> rotate on x
+ rotate->setMatrix(osg::Matrix::rotate(M_PI_2, osg::Vec3f(1.0,0,0)));
+ } else {
+ // side needs to come to front
+ rotate->setMatrix(osg::Matrix::rotate(M_PI_2, osg::Vec3f(0,1.0,0)));
+ }
+ }
+ }
+
+ // add rotation to root
+ root->addChild(rotate);
return root;
}
+osg::ref_ptr<osg::Node> OSGConverter::getOrigin() {
+ osg::Geode* geode = new osg::Geode();
+// osg::StateSet* stateset = new osg::StateSet();
+// stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
+// geode->setStateSet(stateset);
+
+ geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),1)));
+ geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(10.0f,0.0f,0.0f),0.5)));
+ geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f,10.0f,0.0f),2)));
+ geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f,0.0f,10.0f),4)));
+ // geode->addDrawable(new osg::ShapeDrawable(new osg::Cone(osg::Vec3(4.0f,0.0f,0.0f),radius,height),hints));
+
+ return geode;
+}
+
osg::Matrix OSGConverter::eulerToMatrix(double pitch, double roll, double yaw) {
// see http://www.flipcode.com/documents/matrfaq.html#Q36
osg::Matrix m;
@@ -337,7 +460,7 @@ osg::Matrix OSGConverter::eulerToMatrix(double pitch, double roll, double yaw) {
m(0,3) = m(1,3) = m(2,3) = m(3,0) = m(3,1) = m(3,2) = 0;
m(3,3) = 1;
-
+
return m;
}
@@ -370,16 +493,21 @@ void OSGConverter::matrixToEuler(const osg::Matrix& m, double& pitch, double& ro
}
void OSGConverter::dumpMatrix(const osg::Matrix& m) {
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- std::cout << ", " << m(i, j);
- }
- std::cout << std::endl;
- }
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ std::cout << ", " << m(i, j);
+ }
+ std::cout << std::endl;
+ }
}
-
+
void OSGConverter::NameRespectingWriteToFile::operator()(const osg::Image& image, const unsigned int context_id) {
- osgDB::writeImageFile(image, _filename);
+ bool success = osgDB::writeImageFile(image, _filename);
+ if (success) {
+ _converter->reportSuccess(_req);
+ } else {
+ _converter->reportFailure(_req);
+ }
}
} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h
index 67b0da6..f493e73 100644
--- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h
+++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h
@@ -31,10 +31,13 @@ public:
virtual void cancel(const std::string sendId);
virtual void invoke(const InvokeRequest& req);
+ void reportSuccess(const SendRequest& req);
+ void reportFailure(const SendRequest& req);
+
osg::Matrix requestToModelPose(const SendRequest& req);
osg::Matrix requestToCamPose(const SendRequest& req);
- static void dumpMatrix(const osg::Matrix& m);
+ static void dumpMatrix(const osg::Matrix& m);
static osg::Matrix eulerToMatrix(double pitch, double roll, double yaw);
static void matrixToEuler(const osg::Matrix& m, double& pitch, double& roll, double& yaw);
@@ -43,14 +46,20 @@ protected:
public:
NameRespectingWriteToFile(const std::string& filename,
const std::string& extension,
- SavePolicy savePolicy) : osgViewer::ScreenCaptureHandler::WriteToFile(filename, extension, savePolicy) {
+ SavePolicy savePolicy,
+ const SendRequest& req,
+ OSGConverter* converter) : osgViewer::ScreenCaptureHandler::WriteToFile(filename, extension, savePolicy),
+ _req(req), _converter(converter) {
}
virtual void operator()(const osg::Image& image, const unsigned int context_id);
+ SendRequest _req;
+ OSGConverter* _converter;
};
uscxml::concurrency::BlockingQueue<SendRequest> _workQueue;
- osg::ref_ptr<osg::Node> setupGraph(const std::string filename);
+ osg::ref_ptr<osg::Node> setupGraph(const std::string filename, bool autoRotate = false);
+ osg::ref_ptr<osg::Node> getOrigin();
std::map<std::string, std::pair<long, osg::ref_ptr<osg::Node> > > _models;
tthread::recursive_mutex _cacheMutex;
diff --git a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp
index 16947a7..6371a43 100644
--- a/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp
+++ b/src/uscxml/plugins/invoker/heartbeat/HeartbeatInvoker.cpp
@@ -41,7 +41,7 @@ void HeartbeatInvoker::cancel(const std::string sendId) {
}
void HeartbeatInvoker::invoke(const InvokeRequest& req) {
- _invokeId = req.invokeid;
+ _invokeId = req.invokeid;
_event.invokeid = _invokeId;
std::string intervalStr;
double interval = 0;