diff options
Diffstat (limited to 'src/uscxml/plugins')
11 files changed, 311 insertions, 50 deletions
diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index 8feb73a..47ec21d 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -24,10 +24,37 @@ bool connect(pluma::Host& host) { JSCDataModel::JSCDataModel() { } +#if 0 +typedef struct { + int version; /* current (and only) version is 0 */ + JSClassAttributes attributes; + + const char* className; + JSClassRef parentClass; + + const JSStaticValue* staticValues; + const JSStaticFunction* staticFunctions; + + JSObjectInitializeCallback initialize; + JSObjectFinalizeCallback finalize; + JSObjectHasPropertyCallback hasProperty; + JSObjectGetPropertyCallback getProperty; + JSObjectSetPropertyCallback setProperty; + JSObjectDeletePropertyCallback deleteProperty; + JSObjectGetPropertyNamesCallback getPropertyNames; + JSObjectCallAsFunctionCallback callAsFunction; + JSObjectCallAsConstructorCallback callAsConstructor; + JSObjectHasInstanceCallback hasInstance; + JSObjectConvertToTypeCallback convertToType; +} JSClassDefinition; +#endif + // functions need to be objects to hold private data in JSC JSClassDefinition JSCDataModel::jsInClassDef = { 0, 0, "In", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, jsIn, 0, 0, 0 }; JSClassDefinition JSCDataModel::jsPrintClassDef = { 0, 0, "print", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, jsPrint, 0, 0, 0 }; +JSClassDefinition JSCDataModel::jsIOProcessorsClassDef = { 0, 0, "ioProcessors", 0, 0, 0, 0, 0, jsIOProcessorHasProp, jsIOProcessorGetProp, 0, 0, jsIOProcessorListProps, 0, 0, 0, 0 }; + boost::shared_ptr<DataModelImpl> JSCDataModel::create(InterpreterImpl* interpreter) { boost::shared_ptr<JSCDataModel> dm = boost::shared_ptr<JSCDataModel>(new JSCDataModel()); @@ -51,15 +78,33 @@ boost::shared_ptr<DataModelImpl> JSCDataModel::create(InterpreterImpl* interpret JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), printName, jsPrint, kJSPropertyAttributeNone, NULL); JSStringRelease(inName); - dm->eval("_ioprocessors = {};"); + JSClassRef jsIOProcClassRef = JSClassCreate(&jsIOProcessorsClassDef); + JSObjectRef jsIOProc = JSObjectMake(dm->_ctx, jsIOProcClassRef, dm.get()); + JSStringRef ioProcName = JSStringCreateWithUTF8CString("_ioprocessors"); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), ioProcName, jsIOProc, kJSPropertyAttributeNone, NULL); + JSStringRelease(ioProcName); + + JSStringRef nameName = JSStringCreateWithUTF8CString("_name"); + JSStringRef name = JSStringCreateWithUTF8CString(dm->_interpreter->getName().c_str()); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), nameName, JSValueMakeString(dm->_ctx, name), kJSPropertyAttributeNone, NULL); + JSStringRelease(nameName); + JSStringRelease(name); + + JSStringRef sessionIdName = JSStringCreateWithUTF8CString("_sessionid"); + JSStringRef sessionId = JSStringCreateWithUTF8CString(dm->_interpreter->getSessionId().c_str()); + JSObjectSetProperty(dm->_ctx, JSContextGetGlobalObject(dm->_ctx), sessionIdName, JSValueMakeString(dm->_ctx, sessionId), kJSPropertyAttributeNone, NULL); + JSStringRelease(sessionIdName); + JSStringRelease(sessionId); Arabica::DOM::JSCDocument::JSCDocumentPrivate* privData = new Arabica::DOM::JSCDocument::JSCDocumentPrivate(); - privData->nativeObj = new Arabica::DOM::Document<std::string>(interpreter->getDocument()); - privData->dom = dm->_dom; + if (interpreter) { + privData->nativeObj = new Arabica::DOM::Document<std::string>(interpreter->getDocument()); + privData->dom = dm->_dom; - JSObjectRef documentObject = JSObjectMake(dm->_ctx, Arabica::DOM::JSCDocument::getTmpl(), privData); - JSObjectRef globalObject = JSContextGetGlobalObject(dm->_ctx); - JSObjectSetProperty(dm->_ctx, globalObject, JSStringCreateWithUTF8CString("document"), documentObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL); + JSObjectRef documentObject = JSObjectMake(dm->_ctx, Arabica::DOM::JSCDocument::getTmpl(), privData); + JSObjectRef globalObject = JSContextGetGlobalObject(dm->_ctx); + JSObjectSetProperty(dm->_ctx, globalObject, JSStringCreateWithUTF8CString("document"), documentObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, NULL); + } dm->eval("_invokers = {};"); dm->eval("_x = {};"); @@ -202,10 +247,9 @@ Data JSCDataModel::getValueAsData(const JSValueRef value) { JSValueRef exception = NULL; switch(JSValueGetType(_ctx, value)) { case kJSTypeUndefined: - LOG(ERROR) << "IsUndefined is unimplemented"; - break; case kJSTypeNull: - LOG(ERROR) << "IsNull is unimplemented"; + data.atom = "null"; + data.type = Data::INTERPRETED; break; case kJSTypeBoolean: data.atom = (JSValueToBoolean(_ctx, value) ? "true" : "false"); @@ -225,6 +269,7 @@ Data JSCDataModel::getValueAsData(const JSValueRef value) { JSStringGetUTF8CString(stringValue, buf, maxSize); data.atom = std::string(buf); + data.type = Data::VERBATIM; JSStringRelease(stringValue); free(buf); break; @@ -488,4 +533,43 @@ JSValueRef JSCDataModel::jsIn(JSContextRef ctx, JSObjectRef function, JSObjectRe } +bool JSCDataModel::jsIOProcessorHasProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) { + JSCDataModel* INSTANCE = (JSCDataModel*)JSObjectGetPrivate(object); + std::map<std::string, IOProcessor> ioProcessors = INSTANCE->_interpreter->getIOProcessors(); + + size_t maxSize = JSStringGetMaximumUTF8CStringSize(propertyName); + char buffer[maxSize]; + JSStringGetUTF8CString(propertyName, buffer, maxSize); + std::string prop(buffer); + + return ioProcessors.find(prop) != ioProcessors.end(); +} + +JSValueRef JSCDataModel::jsIOProcessorGetProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { + JSCDataModel* INSTANCE = (JSCDataModel*)JSObjectGetPrivate(object); + std::map<std::string, IOProcessor> ioProcessors = INSTANCE->_interpreter->getIOProcessors(); + + size_t maxSize = JSStringGetMaximumUTF8CStringSize(propertyName); + char buffer[maxSize]; + JSStringGetUTF8CString(propertyName, buffer, maxSize); + std::string prop(buffer); + + if (ioProcessors.find(prop) != ioProcessors.end()) { + return INSTANCE->getDataAsValue(ioProcessors.find(prop)->second.getDataModelVariables()); + } + return JSValueMakeUndefined(ctx); +} + +void JSCDataModel::jsIOProcessorListProps(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) { + JSCDataModel* INSTANCE = (JSCDataModel*)JSObjectGetPrivate(object); + std::map<std::string, IOProcessor> ioProcessors = INSTANCE->_interpreter->getIOProcessors(); + + std::map<std::string, IOProcessor>::const_iterator ioProcIter = ioProcessors.begin(); + while(ioProcIter != ioProcessors.end()) { + JSStringRef ioProcName = JSStringCreateWithUTF8CString(ioProcIter->first.c_str()); + JSPropertyNameAccumulatorAddName(propertyNames, ioProcName); + ioProcIter++; + } +} + }
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h index 28a313e..36765c2 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.h @@ -66,6 +66,11 @@ protected: static JSClassDefinition jsPrintClassDef; static JSValueRef jsPrint(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); + static JSClassDefinition jsIOProcessorsClassDef; + static bool jsIOProcessorHasProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName); + static JSValueRef jsIOProcessorGetProp(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception); + static void jsIOProcessorListProps(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames); + JSValueRef getDocumentAsValue(const Arabica::DOM::Document<std::string>& doc); JSValueRef getDataAsValue(const Data& data); Data getValueAsData(const JSValueRef value); diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index c92274c..2e37b29 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -264,13 +264,17 @@ void SWIDataModel::eval(const std::string& expr) { } bool SWIDataModel::evalAsBool(const std::string& expr) { - PlCompound compound(expr.c_str()); - PlTermv termv(compound.arity()); - for (int i = 0; i < compound.arity(); i++) { - termv[i] = compound[i + 1]; + try { + PlCompound compound(expr.c_str()); + PlTermv termv(compound.arity()); + for (int i = 0; i < compound.arity(); i++) { + termv[i] = compound[i + 1]; + } + PlQuery query(compound.name(), termv); + return query.next_solution() > 0; + } catch(...) { + return false; } - PlQuery query(compound.name(), termv); - return query.next_solution() > 0; } std::string SWIDataModel::evalAsString(const std::string& expr) { diff --git a/src/uscxml/plugins/invoker/CMakeLists.txt b/src/uscxml/plugins/invoker/CMakeLists.txt index 34d8918..e836275 100644 --- a/src/uscxml/plugins/invoker/CMakeLists.txt +++ b/src/uscxml/plugins/invoker/CMakeLists.txt @@ -32,6 +32,25 @@ else() list (APPEND USCXML_FILES ${DIRMON_INVOKER}) endif() + +# Location invoker to watch for proximity to GPS coordinates + +file(GLOB_RECURSE LOCATION_INVOKER + location/*.cpp + location/*.h +) +source_group("Invoker\\location" FILES ${LOCATION_INVOKER}) +if (BUILD_AS_PLUGINS) + add_library( + invoker_location SHARED + ${LOCATION_INVOKER}) + target_link_libraries(invoker_location uscxml) + set_target_properties(invoker_location PROPERTIES FOLDER "Plugin Invoker") +else() + list (APPEND USCXML_FILES ${LOCATION_INVOKER}) +endif() + + # System invoker to open a native command file(GLOB_RECURSE XHTML_INVOKER diff --git a/src/uscxml/plugins/invoker/location/LocationInvoker.cpp b/src/uscxml/plugins/invoker/location/LocationInvoker.cpp new file mode 100644 index 0000000..9aeb6b4 --- /dev/null +++ b/src/uscxml/plugins/invoker/location/LocationInvoker.cpp @@ -0,0 +1,44 @@ +#include "LocationInvoker.h" +#include <glog/logging.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new LocationInvokerProvider() ); + return true; +} +#endif + +LocationInvoker::LocationInvoker() { +} + +LocationInvoker::~LocationInvoker() { +}; + +boost::shared_ptr<InvokerImpl> LocationInvoker::create(InterpreterImpl* interpreter) { + boost::shared_ptr<LocationInvoker> invoker = boost::shared_ptr<LocationInvoker>(new LocationInvoker()); + invoker->_interpreter = interpreter; + return invoker; +} + +Data LocationInvoker::getDataModelVariables() { + Data data; + return data; +} + +void LocationInvoker::send(const SendRequest& req) { +} + +void LocationInvoker::cancel(const std::string sendId) { +} + +void LocationInvoker::invoke(const InvokeRequest& req) { +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/invoker/location/LocationInvoker.h b/src/uscxml/plugins/invoker/location/LocationInvoker.h new file mode 100644 index 0000000..2eb4833 --- /dev/null +++ b/src/uscxml/plugins/invoker/location/LocationInvoker.h @@ -0,0 +1,40 @@ +#ifndef LOCATIONINVOKER_H_W09J90F0 +#define LOCATIONINVOKER_H_W09J90F0 + +#include <uscxml/Interpreter.h> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { + +class LocationInvoker : public InvokerImpl { +public: + LocationInvoker(); + virtual ~LocationInvoker(); + virtual boost::shared_ptr<InvokerImpl> create(InterpreterImpl* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("location"); + names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#location"); + return names; + } + + virtual Data getDataModelVariables(); + virtual void send(const SendRequest& req); + virtual void cancel(const std::string sendId); + virtual void invoke(const InvokeRequest& req); + +protected: +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(LocationInvoker, InvokerImpl); +#endif + +} + + +#endif /* end of include guard: LOCATIONINVOKER_H_W09J90F0 */ diff --git a/src/uscxml/plugins/invoker/miles/SpatialAudio.cpp b/src/uscxml/plugins/invoker/miles/SpatialAudio.cpp index 3826ebb..298b15f 100644 --- a/src/uscxml/plugins/invoker/miles/SpatialAudio.cpp +++ b/src/uscxml/plugins/invoker/miles/SpatialAudio.cpp @@ -28,11 +28,11 @@ SpatialAudio::SpatialAudio() { _pos[0] = _pos[1] = _pos[2] = 0.0; _listener = new float[3]; _listener[0] = _listener[1] = _listener[2] = 0.0; + _maxPos = new float[3]; + _maxPos[0] = _maxPos[1] = _maxPos[2] = 1.0; miles_init(); - } - SpatialAudio::~SpatialAudio() { }; @@ -53,8 +53,8 @@ void SpatialAudio::send(const SendRequest& req) { _audioDev = miles_audio_device_open(MILES_AUDIO_IO_OPENAL, _audioDevIndex, 0, 22050, 2, 1, 1024, false); if (_audioDev != NULL) { _audioDevOpen = true; - float rolloffFactor = 0.2; - miles_audio_device_control(MILES_AUDIO_IO_OPENAL, _audioDev, MILES_AUDIO_DEVICE_CTRL_SET_ROLLOFF_FACTOR, &rolloffFactor); +// float rolloffFactor = 1.0; +// miles_audio_device_control(MILES_AUDIO_IO_OPENAL, _audioDev, MILES_AUDIO_DEVICE_CTRL_SET_ROLLOFF_FACTOR, &rolloffFactor); } } @@ -70,24 +70,30 @@ void SpatialAudio::send(const SendRequest& req) { miles_audio_device_control(MILES_AUDIO_IO_OPENAL, _audioDev, MILES_AUDIO_DEVICE_CTRL_SET_POSITION, _pos); + char* buffer = (char*)malloc(_audioDev->chunk_size); // skip wav header _dataStream.seekg(44); - + while(_dataStream.readsome(buffer, _audioDev->chunk_size) != 0) { - miles_audio_device_write(MILES_AUDIO_IO_OPENAL, _audioDev, buffer, _audioDev->chunk_size); + int written = 0; + while(written < _audioDev->chunk_size) { + written += miles_audio_device_write(MILES_AUDIO_IO_OPENAL, _audioDev, buffer + written, _audioDev->chunk_size - written); + tthread::this_thread::sleep_for(tthread::chrono::milliseconds(10)); + } } + _dataStream.seekg(0); free(buffer); } } else if (boost::iequals(req.name, "move.listener")) { if (_audioDevOpen) { getPosFromParams(req.params, _listener); - std::cout << "Listener: "; - for (int i = 0; i < 3; i++) { - std::cout << _listener[i] << " "; - } - std::cout << std::endl; +// std::cout << "Listener: "; +// for (int i = 0; i < 3; i++) { +// std::cout << _listener[i] << " "; +// } +// std::cout << std::endl; miles_audio_device_control(MILES_AUDIO_IO_OPENAL, _audioDev, MILES_AUDIO_DEVICE_CTRL_SET_LISTENER_POS, _listener); @@ -119,6 +125,17 @@ void SpatialAudio::invoke(const InvokeRequest& req) { getPosFromParams(req.params, _pos); + std::multimap<std::string, std::string>::const_iterator paramIter = req.params.begin(); + while(paramIter != req.params.end()) { + if (boost::iequals(paramIter->first, "maxX")) + _maxPos[0] = strTo<float>(paramIter->second); + if (boost::iequals(paramIter->first, "maxY")) + _maxPos[1] = strTo<float>(paramIter->second); + if (boost::iequals(paramIter->first, "maxZ")) + _maxPos[2] = strTo<float>(paramIter->second); + paramIter++; + } + struct miles_audio_device_description *devices; int ndevs; @@ -170,6 +187,10 @@ void SpatialAudio::getPosFromParams(const std::multimap<std::string, std::string } catch (boost::bad_lexical_cast& e) { LOG(ERROR) << "Cannot interpret circle as float value in params: " << e.what(); } + + position[0] = position[0] / _maxPos[0]; + position[1] = position[1] / _maxPos[1]; + position[2] = position[2] / _maxPos[2]; // std::cout << _pos[0] << ":" << _pos[1] << ":" << _pos[2] << std::endl; } diff --git a/src/uscxml/plugins/invoker/miles/SpatialAudio.h b/src/uscxml/plugins/invoker/miles/SpatialAudio.h index 082d796..59ecfdb 100644 --- a/src/uscxml/plugins/invoker/miles/SpatialAudio.h +++ b/src/uscxml/plugins/invoker/miles/SpatialAudio.h @@ -45,6 +45,7 @@ protected: float* _pos; float* _listener; + float* _maxPos; bool _audioDevOpen; int _audioDevIndex; struct miles_audio_device* _audioDev; diff --git a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp index 2b3377e..081842f 100644 --- a/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp +++ b/src/uscxml/plugins/invoker/umundo/UmundoInvoker.cpp @@ -247,7 +247,11 @@ void UmundoInvoker::receive(void* object, umundo::Message* msg) { // get meta fields into event std::map<std::string, std::string>::const_iterator metaIter = msg->getMeta().begin(); while(metaIter != msg->getMeta().end()) { - event.data.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM); + if (isNumeric(metaIter->second.c_str(), 10)) { + event.data.compound[metaIter->first] = Data(metaIter->second, Data::INTERPRETED); + } else { + event.data.compound[metaIter->first] = Data(metaIter->second, Data::VERBATIM); + } metaIter++; } @@ -309,9 +313,13 @@ std::multimap<std::string, std::pair<std::string, boost::weak_ptr<umundo::Node> boost::shared_ptr<umundo::Node> UmundoInvoker::getNode(InterpreterImpl* interpreter, const std::string& domain) { std::pair<_nodes_t::iterator, _nodes_t::iterator> range = _nodes.equal_range(interpreter->getName()); for (_nodes_t::iterator it = range.first; it != range.second; it++) { - if (it->second.first.compare(domain) == 0) - return it->second.second.lock(); + if (it->second.first.compare(domain) == 0) { + boost::shared_ptr<umundo::Node> node = it->second.second.lock(); + if (node) + return node; + } } + // create a new node boost::shared_ptr<umundo::Node> node = boost::shared_ptr<umundo::Node>(new umundo::Node(domain)); std::pair<std::string, std::pair<std::string, boost::weak_ptr<umundo::Node> > > pair = std::make_pair(interpreter->getName(), std::make_pair(domain, node)); _nodes.insert(pair); diff --git a/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp b/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp index a71d21a..a18be8e 100644 --- a/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/vxml/VoiceXMLInvoker.cpp @@ -48,10 +48,20 @@ Data VoiceXMLInvoker::getDataModelVariables() { void VoiceXMLInvoker::send(const SendRequest& req) { StartRequest start; std::stringstream domSS; +// if (req.dom) { +// // hack until jVoiceXML supports XML +// std::cout << req.dom; +// Arabica::DOM::NodeList<std::string> prompts = req.dom.getElementsByTagName("vxml:prompt"); +// for (int i = 0; i < prompts.getLength(); i++) { +// if (prompts.item(i).hasChildNodes()) { +// domSS << prompts.item(i).getFirstChild().getNodeValue() << "."; +// } +// } +// } domSS << req.getFirstDOMElement(); start.content = domSS.str(); - - start.contentURL.href = "http://localhost/~sradomski/hello.vxml"; + _interpreter->getDataModel().replaceExpressions(start.content); + start.requestId = "asdf"; start.source = "asdf"; start.target = "umundo://mmi/jvoicexml"; diff --git a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp index 0c7ef08..4e2c01a 100644 --- a/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/xhtml/XHTMLInvoker.cpp @@ -7,9 +7,12 @@ #include <Pluma/Connector.hpp> #endif -#if defined(__APPLE__) and defined(TARGET_OS_MAC) -#include <CoreFoundation/CFBundle.h> -#include <ApplicationServices/ApplicationServices.h> +#if __APPLE__ +# if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +# else +# include <CoreFoundation/CFBundle.h> +# include <ApplicationServices/ApplicationServices.h> +# endif #endif namespace uscxml { @@ -41,6 +44,7 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { // these are the XHR requests if (boost::iequals(req.data["header"]["X-Requested-With"].atom, "XMLHttpRequest")) { if (boost::iequals(req.data["type"].atom, "get")) { + // the long-polling GET if (_longPoll) { evhttp_send_error(_longPoll.curlReq, 204, NULL); _longPoll.curlReq = NULL; @@ -52,9 +56,12 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { } return true; } else { + // a POST request Event ev(req); if (ev.data["header"]["X-SCXML-Name"]) { ev.name = ev.data["header"]["X-SCXML-Name"].atom; + } else { + ev.name = req.data["type"].atom; } ev.origin = _invokeId; ev.initContent(req.data["content"].atom); @@ -62,6 +69,9 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { // content is already on ev.raw ev.data.compound["Connection"].compound.erase("content"); + HTTPServer::Reply reply(req); + HTTPServer::reply(reply); + returnEvent(ev); return true; } @@ -70,17 +80,9 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { // initial request for a document if (!req.data["query"] && // no query parameters boost::iequals(req.data["type"].atom, "get") && // request type is GET - (boost::icontains(req.data["header"]["Accept"].atom, "text/html") || // accepts html or - boost::contains(req.data["header"]["User-Agent"].atom, "MSIE")) && // is the internet explorer req.content.length() == 0) { // no content HTTPServer::Reply reply(req); - URL templateURL("templates/xhtml-invoker.html"); - templateURL.toAbsolute(_interpreter->getBaseURI()); - templateURL.download(true); - std::string templateContent = templateURL.getInContent(); - boost::replace_all(templateContent, "${scxml.server}", _url); - boost::replace_all(templateContent, "${scxml.invokeId}", _invokeId); std::string content; std::stringstream ss; @@ -90,15 +92,25 @@ bool XHTMLInvoker::httpRecvRequest(const HTTPServer::Request& req) { } else if(_invokeReq.data) { ss << _invokeReq.data; content = ss.str(); - } else { + } else if (_invokeReq.content.length() > 0){ content = _invokeReq.content; + } else { + URL templateURL("templates/xhtml-invoker.html"); + templateURL.toAbsolute(_interpreter->getBaseURI()); + templateURL.download(true); + content = templateURL.getInContent(); } - boost::replace_all(templateContent, "${scxml.content}", content); - reply.content = templateContent; - reply.headers["Content-Type"] = "text/html"; + + _interpreter->getDataModel().replaceExpressions(content); + reply.content = content; + + // application/xhtml+xml + reply.headers["Content-Type"] = "text/html; charset=utf-8"; +// reply.headers["Content-Type"] = "application/xhtml+xml; charset=utf-8"; // aggressive caching in IE will return all XHR get requests instantenously with the template otherwise reply.headers["Cache-Control"] = "no-cache"; +// reply.headers["Cache-Control"] = "max-age=3600"; HTTPServer::reply(reply); @@ -122,17 +134,27 @@ Data XHTMLInvoker::getDataModelVariables() { void XHTMLInvoker::send(const SendRequest& req) { tthread::lock_guard<tthread::recursive_mutex> lock(_mutex); + SendRequest reqCopy(req); + _interpreter->getDataModel().replaceExpressions(reqCopy.content); + Data json = Data::fromJSON(reqCopy.content); + if (json) { + reqCopy.data = json; + } + if (!_longPoll) { - _outQueue.push_back(req); + _outQueue.push_back(reqCopy); return; } - reply(req, _longPoll); + reply(reqCopy, _longPoll); _longPoll.curlReq = NULL; } void XHTMLInvoker::reply(const SendRequest& req, const HTTPServer::Request& longPoll) { HTTPServer::Reply reply(longPoll); + // is there JSON in the content? + std::string content = req.content; + if (req.dom) { std::stringstream ss; Arabica::DOM::Node<std::string> content = req.dom.getDocumentElement(); @@ -164,8 +186,10 @@ void XHTMLInvoker::cancel(const std::string sendId) { void XHTMLInvoker::invoke(const InvokeRequest& req) { _invokeReq = req; - HTTPServer::registerServlet(_interpreter->getName() + "/xhtml/" + req.invokeid, this); -#if defined(__APPLE__) and defined(TARGET_OS_MAC) + HTTPServer::registerServlet(_interpreter->getName() + "/xhtml/" + req.invokeid + ".html", this); +#if __APPLE__ +# if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR +# else // see http://stackoverflow.com/questions/4177744/c-osx-open-default-browser CFURLRef url = CFURLCreateWithBytes ( NULL, // allocator @@ -177,6 +201,7 @@ void XHTMLInvoker::invoke(const InvokeRequest& req) { LSOpenCFURLRef(url,0); CFRelease(url); return; +# endif #endif #ifdef _WIN32 // see http://support.microsoft.com/kb/224816 |