25#include <unordered_map>
28#include <simgear/debug/logstream.hxx>
29#include <simgear/props/props.hxx>
30#include <simgear/structure/commands.hxx>
32#include <simgear/props/props_io.hxx>
56 type = cur->getType();
58 case simgear::props::INT:
62 case simgear::props::BOOL:
66 case simgear::props::FLOAT:
67 case simgear::props::DOUBLE:
71 case simgear::props::STRING:
72 case simgear::props::UNSPECIFIED:
76 case simgear::props::NONE:
80 SG_LOG(SG_NETWORK, SG_DEV_ALERT,
"MirrorPropTree PropertyValue : implement me!" <<
type);
87 if (other.
type !=
type)
return false;
89 case simgear::props::INT:
90 case simgear::props::BOOL:
93 case simgear::props::FLOAT:
94 case simgear::props::DOUBLE:
97 case simgear::props::STRING:
98 case simgear::props::UNSPECIFIED:
101 case simgear::props::NONE:
123 path(node->getPath()),
141 previousValues.resize(2);
150 auto it = idHash.find(node);
151 if (it == idHash.end()) {
155 assert(previousValues.size() > it->second);
157 if (!previousValues[it->second].equals(node, newVal)) {
158 previousValues[it->second] = newVal;
164 void childAdded(SGPropertyNode* parent, SGPropertyNode* child)
override
173#if defined (MIRROR_DEBUG)
174 SG_LOG(SG_NETWORK, SG_INFO,
"looking for RR:" << r.
path);
176 auto rrIt = std::find(recentlyRemoved.begin(), recentlyRemoved.end(), r);
177 if (rrIt != recentlyRemoved.end()) {
178#if defined (MIRROR_DEBUG)
179 SG_LOG(SG_NETWORK, SG_INFO,
"recycling node:" << node->getPath());
181 const auto id = rrIt->id;
185 idHash.insert(std::make_pair(node,
id));
191 if (!previousValues[
id].equals(node, newVal)) {
192 previousValues[id] = newVal;
194#if defined (MIRROR_DEBUG)
195 SG_LOG(SG_NETWORK, SG_INFO,
"\tand will actually change" << node->getPath());
199 recentlyRemoved.erase(rrIt);
202#if defined (MIRROR_DEBUG)
203 SG_LOG(SG_NETWORK, SG_INFO,
"new node:" << node->getPath());
207 for (; child < node->nChildren(); ++child) {
212 void childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
override
217 auto it = idHash.find(child);
218 if (it != idHash.end()) {
224 recentlyRemoved.emplace_back(child, it->second);
225#if defined (MIRROR_DEBUG)
226 SG_LOG(SG_NETWORK, SG_INFO,
"adding RR:" << recentlyRemoved.back().path);
229#if defined (MIRROR_DEBUG)
230 SG_LOG(SG_NETWORK, SG_INFO,
"saw remove of:" << child->getPath());
236#if defined (MIRROR_DEBUG)
237 SG_LOG(SG_NETWORK, SG_INFO,
"register subtree:" << node->getPath());
243 for (; child < node->nChildren(); ++child) {
254 auto it = idHash.find(prop);
255 if (it == idHash.end()) {
256 it = idHash.insert(it, std::make_pair(prop, nextPropertyId++));
264#if defined (MIRROR_DEBUG)
272 cJSON* result = cJSON_CreateObject();
274 cJSON * newNodesArray = cJSON_CreateArray();
279 cJSON* arrayTail =
nullptr;
283 cJSON* newPropData = cJSON_CreateObject();
284 cJSON_AddItemToObject(newPropData,
"path", cJSON_CreateString(prop->getPath(
true).c_str()));
286 cJSON_AddItemToObject(newPropData,
"index", cJSON_CreateNumber(prop->getIndex()));
287 cJSON_AddItemToObject(newPropData,
"position", cJSON_CreateNumber(prop->getPosition()));
288 cJSON_AddItemToObject(newPropData,
"id", cJSON_CreateNumber(
idForProperty(prop)));
289 if (prop->getType() != simgear::props::NONE) {
294 arrayTail->next = newPropData;
295 newPropData->prev = arrayTail;
296 arrayTail = newPropData;
298 cJSON_AddItemToArray(newNodesArray, newPropData);
299 arrayTail = newPropData;
304 cJSON_AddItemToObject(result,
"created", newNodesArray);
309 cJSON * deletedNodesArray = cJSON_CreateArray();
311 cJSON_AddItemToArray(deletedNodesArray, cJSON_CreateNumber(propId));
313 cJSON_AddItemToObject(result,
"removed", deletedNodesArray);
318 cJSON * changedNodesArray = cJSON_CreateArray();
321 cJSON* tail =
nullptr;
324 cJSON* propData = cJSON_CreateArray();
325 cJSON_AddItemToArray(propData, cJSON_CreateNumber(
idForProperty(prop)));
330 tail->next = propData;
331 propData->prev = tail;
334 cJSON_AddItemToArray(changedNodesArray, propData);
340 cJSON_AddItemToObject(result,
"changed", changedNodesArray);
342#if defined (MIRROR_DEBUG)
343 SG_LOG(SG_NETWORK, SG_INFO,
"making JSON data took:" << st.elapsedMSec() <<
" for " << newSize <<
"/" << changedSize <<
"/" << removedSize);
345 recentlyRemoved.clear();
356 std::unordered_map<SGPropertyNode*, PropertyId> idHash;
357 std::vector<PropertyValue> previousValues;
362 std::vector<RemovedNode> recentlyRemoved;
369 cJSON * value = cJSON_GetObjectItem(json,
"value");
370 if ( NULL != value ) {
371 if (nodes.size() > 1) {
372 SG_LOG(SG_NETWORK, SG_WARN,
"httpd: WS set: insufficent values for nodes:" << nodes.size());
376 SGPropertyNode_ptr n =
fgGetNode(nodes.front());
378 SG_LOG(SG_NETWORK, SG_WARN,
"httpd: set '" << nodes.front() <<
"' not found");
386 cJSON * values = cJSON_GetObjectItem(json,
"values");
387 if ( ( NULL == values ) || (
static_cast<size_t>(cJSON_GetArraySize(values)) != nodes.size()) ) {
388 SG_LOG(SG_NETWORK, SG_WARN,
"httpd: WS set: mismatched nodes/values sizes:" << nodes.size());
392 string_list::const_iterator it;
394 for (it = nodes.begin(); it != nodes.end(); ++it, ++
i) {
397 SG_LOG(SG_NETWORK, SG_WARN,
"httpd: get '" << *it <<
"' not found");
407 cJSON*
name = cJSON_GetObjectItem(json,
"fgcommand");
408 if ((NULL ==
name )|| (NULL ==
name->valuestring)) {
409 SG_LOG(SG_NETWORK, SG_WARN,
"httpd: exec: no fgcommand name");
413 SGPropertyNode_ptr arg(
new SGPropertyNode);
423 _minSendInterval(100)
435 _subtreeRoot->removeChangeListener(_listener.get());
439void MirrorPropertyTreeWebsocket::checkNodeExists()
441 _subtreeRoot =
globals->get_props()->getNode(_rootPath,
false);
443 _subtreeRoot->addChangeListener(_listener.get());
444 _listener->registerSubtree(_subtreeRoot);
445 _lastSendTime = SGTimeStamp::now();
458 if (request.
Content.empty())
return;
471 cJSON * json = cJSON_Parse(request.
Content.c_str());
474 cJSON * j = cJSON_GetObjectItem(json,
"command");
475 if ( NULL != j && NULL != j->valuestring) {
481 j = cJSON_GetObjectItem(json,
"node");
482 if ( NULL != j && NULL != j->valuestring) {
483 nodeNames.push_back(simgear::strutils::strip(
string(j->valuestring)));
486 cJSON * nodes = cJSON_GetObjectItem(json,
"nodes");
487 if ( NULL != nodes) {
488 for (
int i = 0;
i < cJSON_GetArraySize(nodes);
i++) {
489 cJSON * node = cJSON_GetArrayItem(nodes,
i);
490 if ( NULL == node)
continue;
491 if ( NULL == node->valuestring)
continue;
492 nodeNames.push_back(simgear::strutils::strip(
string(node->valuestring)));
497 handleGetCommand(nodeNames, writer);
500 }
else if (
command ==
"exec") {
503 string_list::const_iterator it;
504 for (it = nodeNames.begin(); it != nodeNames.end(); ++it) {
505 _watchedNodes.handleCommand(
command, *it, _propertyChangeObserver);
523 if (!_listener->haveChangesToSend()) {
527 if (_lastSendTime.elapsedMSec() < _minSendInterval) {
532 _lastSendTime.stamp();
534 cJSON * json = _listener->makeJSONData();
535 char * jsonString = cJSON_PrintUnformatted( json );
538 cJSON_Delete( json );
SGCommandMgr * get_commands()
static const char * getPropertyTypeString(simgear::props::Type type)
static cJSON * valueToJson(SGPropertyNode_ptr n)
static void addChildrenToProp(cJSON *json, SGPropertyNode_ptr base)
MirrorPropertyTreeWebsocket(const std::string &path)
void poll(WebsocketWriter &writer) override
friend class MirrorTreeListener
~MirrorPropertyTreeWebsocket() override
void handleRequest(const HTTPRequest &request, WebsocketWriter &writer) override
std::set< SGPropertyNode * > newNodes
void childRemoved(SGPropertyNode *parent, SGPropertyNode *child) override
bool haveChangesToSend() const
std::set< SGPropertyNode * > changedNodes
void childAdded(SGPropertyNode *parent, SGPropertyNode *child) override
void registerSubtree(SGPropertyNode *node)
virtual ~MirrorTreeListener()
PropertyId idForProperty(SGPropertyNode *prop)
std::set< PropertyId > removedNodes
void recursiveAdd(SGPropertyNode *node)
void valueChanged(SGPropertyNode *node) override
int writeText(const char *data, size_t len)
std::vector< std::string > string_list
static void setPropertyFromJson(SGPropertyNode_ptr prop, cJSON *json)
static void handleSetCommand(const string_list &nodes, cJSON *json, WebsocketWriter &writer)
static void handleExecCommand(cJSON *json)
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
SGCommandMgr::command_t command
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
simgear::props::Type type
bool equals(SGPropertyNode *node, const PropertyValue &other) const
PropertyValue(SGPropertyNode *cur=nullptr)
RemovedNode(SGPropertyNode *node, unsigned int aId)
bool operator==(const RemovedNode &other) const