added circuit level attributes for JSON output, corrected sorting of messages in result of MessageMap::findAll()

This commit is contained in:
john30
2017-04-16 15:03:29 +02:00
parent 61c3aeddf9
commit b36efd4086
3 changed files with 112 additions and 53 deletions
+3 -24
View File
@@ -1610,6 +1610,7 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
deque<Message *> messages = m_messages->findAll(circuit, name, getUserLevels(user), exact, true, false, true); deque<Message *> messages = m_messages->findAll(circuit, name, getUserLevels(user), exact, true, false, true);
bool first = true; bool first = true;
verbosity |= (numeric ? OF_NUMERIC : 0) | OF_JSON | (full ? OF_ALL_ATTRS : 0);
for (deque<Message*>::iterator it = messages.begin(); it != messages.end();) { for (deque<Message*>::iterator it = messages.begin(); it != messages.end();) {
Message* message = *it++; Message* message = *it++;
symbol_t dstAddress = message->getDstAddress(); symbol_t dstAddress = message->getDstAddress();
@@ -1643,34 +1644,12 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
} }
lastCircuit = message->getCircuit(); lastCircuit = message->getCircuit();
result << "\n \"" << lastCircuit << "\": {"; result << "\n \"" << lastCircuit << "\": {";
// TODO add circuit specific values
first = true; first = true;
} if (full && m_messages->decodeCircuit(lastCircuit, result, verbosity)) { // add circuit specific values
if (first) {
first = false; first = false;
} else {
result << ",";
}
result << "\n \"" << message->getName() << "\": {";
result << "\n \"lastup\": " << setw(0) << dec << static_cast<unsigned>(lastup);
if (lastup != 0) {
result << ",\n \"zz\": \"" << setfill('0') << setw(2) << hex << static_cast<unsigned>(dstAddress) << "\"";
size_t pos = (size_t) result.tellp();
result << ",\n \"fields\": {";
result_t dret = message->decodeLastData(
result, verbosity | (numeric ? OF_NUMERIC : 0) | OF_JSON | (full ? OF_ALL_ATTRS : 0));
if (dret == RESULT_OK) {
result << "\n }";
} else {
string prefix = result.str().substr(0, pos);
result.str("");
result.clear(); // remove written fields
result << prefix << ",\n \"decodeerror\": \"" << getResultCode(dret) << "\"";
} }
} }
result << ",\n \"passive\": " << (message->isPassive() ? "true" : "false"); message->decode(result, verbosity, !first);
result << ",\n \"write\": " << (message->isWrite() ? "true" : "false");
result << "\n }";
} }
if (lastCircuit.length() > 0) { if (lastCircuit.length() > 0) {
+75 -16
View File
@@ -1004,6 +1004,33 @@ void Message::dumpField(ostream& output, size_t fieldId, bool withConditions) co
} }
} }
void Message::decode(ostringstream& output, OutputFormat outputFormat, bool leadingSeparator,
vector<string>* fields) const {
if (leadingSeparator) {
output << ",";
}
output << "\n \"" << getName() << "\": {";
output << "\n \"lastup\": " << setw(0) << dec << static_cast<unsigned>(getLastUpdateTime());
if (getLastUpdateTime() != 0) {
output << ",\n \"zz\": \"" << setfill('0') << setw(2) << hex << static_cast<unsigned>(getDstAddress()) << "\"";
appendAttributes(output, OF_JSON | outputFormat);
size_t pos = (size_t) output.tellp();
output << ",\n \"fields\": {";
result_t dret = decodeLastData(output, outputFormat);
if (dret == RESULT_OK) {
output << "\n }";
} else {
string prefix = output.str().substr(0, pos);
output.str("");
output.clear(); // remove written fields
output << prefix << ",\n \"decodeerror\": \"" << getResultCode(dret) << "\"";
}
}
output << ",\n \"passive\": " << (isPassive() ? "true" : "false");
output << ",\n \"write\": " << (isWrite() ? "true" : "false");
output << "\n }";
}
ChainedMessage::ChainedMessage(const string circuit, const string level, const string name, ChainedMessage::ChainedMessage(const string circuit, const string level, const string name,
const bool isWrite, const map<string, string>& attributes, const bool isWrite, const map<string, string>& attributes,
@@ -1767,7 +1794,8 @@ result_t MessageMap::add(Message* message, bool storeByName) {
} }
string name = message->getName(); string name = message->getName();
FileReader::tolower(name); FileReader::tolower(name);
string nameKey = string(isPassive ? "P" : (isWrite ? "W" : "R")) + circuit + FIELD_SEPARATOR + name; string suffix = FIELD_SEPARATOR + name + (isPassive ? "P" : (isWrite ? "W" : "R"));
string nameKey = circuit + suffix;
if (!m_addAll) { if (!m_addAll) {
map<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey); map<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey);
if (nameIt != m_messagesByName.end()) { if (nameIt != m_messagesByName.end()) {
@@ -1778,7 +1806,7 @@ result_t MessageMap::add(Message* message, bool storeByName) {
} }
} }
m_messagesByName[nameKey].push_back(message); m_messagesByName[nameKey].push_back(message);
nameKey = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + name; // also store without circuit nameKey = suffix; // also store without circuit
map<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey); map<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey);
if (nameIt == m_messagesByName.end()) { if (nameIt == m_messagesByName.end()) {
// always store first message without circuit (in order of circuit name) // always store first message without circuit (in order of circuit name)
@@ -1926,11 +1954,14 @@ result_t MessageMap::addDefaultFromFile(map<string, string>& row, vector< map<st
m_conditions[key] = condition; m_conditions[key] = condition;
return RESULT_OK; return RESULT_OK;
} }
string defaultCircuit = defaults["circuit"];
if (type.empty()) { if (type.empty()) {
if (defaultCircuit.empty()) {
errorDescription = "invalid default definition"; errorDescription = "invalid default definition";
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
string defaultCircuit = defaults["circuit"]; // circuit level additional attributes
}
string defaultSuffix = defaults["suffix"]; string defaultSuffix = defaults["suffix"];
defaults.erase("suffix"); defaults.erase("suffix");
for (auto entry : row) { for (auto entry : row) {
@@ -1956,6 +1987,16 @@ result_t MessageMap::addDefaultFromFile(map<string, string>& row, vector< map<st
defaults[entry.first] = value; defaults[entry.first] = value;
} }
} }
if (type.empty()) {
string circuit = defaults["circuit"];
defaults.erase("circuit");
string name = defaults["name"];
defaults.erase("name");
if (!name.empty() || !defaults.empty()) {
m_circuitData[circuit] = new AttributedItem(name, defaults);
}
return RESULT_OK;
}
getDefaults()[type] = defaults; getDefaults()[type] = defaults;
vector< map<string, string> > subDefaults = subRows; // ensure to have a copy vector< map<string, string> > subDefaults = subRows; // ensure to have a copy
getSubDefaults()[type] = subDefaults; getSubDefaults()[type] = subDefaults;
@@ -2362,16 +2403,17 @@ Message* MessageMap::find(const string& circuit, const string& name, const strin
FileReader::tolower(lcircuit); FileReader::tolower(lcircuit);
string lname = name; string lname = name;
FileReader::tolower(lname); FileReader::tolower(lname);
string suffix = FIELD_SEPARATOR + lname + (isPassive ? "P" : (isWrite ? "W" : "R"));
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
string key; string nameKey;
if (i == 0) { if (i == 0) {
key = string(isPassive ? "P" : (isWrite ? "W" : "R")) + lcircuit + FIELD_SEPARATOR + lname; nameKey = lcircuit + suffix;
} else if (lcircuit.length() == 0) { } else if (lcircuit.empty()) {
key = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + lname; // second try: without circuit nameKey = suffix; // second try: without circuit
} else { } else {
continue; // not allowed without circuit continue; // not allowed without circuit
} }
auto it = m_messagesByName.find(key); auto it = m_messagesByName.find(nameKey);
if (it != m_messagesByName.end()) { if (it != m_messagesByName.end()) {
Message* message = getFirstAvailable(it->second); Message* message = getFirstAvailable(it->second);
if (message && message->hasLevel(levels)) { if (message && message->hasLevel(levels)) {
@@ -2395,7 +2437,7 @@ deque<Message*> MessageMap::findAll(const string& circuit, const string& name, c
bool checkLevel = levels != "*"; bool checkLevel = levels != "*";
bool checkName = lname.length() > 0; bool checkName = lname.length() > 0;
for (auto it : m_messagesByName) { for (auto it : m_messagesByName) {
if (it.first[0] == '-') { // avoid duplicates: instances stored multiple times have a key starting with "-" if (it.first[0] == FIELD_SEPARATOR) { // avoid duplicates: instances stored multiple times have a special key
continue; continue;
} }
for (auto message : it.second) { for (auto message : it.second) {
@@ -2544,6 +2586,19 @@ void MessageMap::addPollMessage(Message* message, bool toFront) {
} }
} }
bool MessageMap::decodeCircuit(const string circuit, ostringstream& output, OutputFormat outputFormat) const {
auto it = m_circuitData.find(circuit);
if (it == m_circuitData.end()) {
return false;
}
if (outputFormat & OF_JSON) {
output << "\"name\": \"" << it->second->getName() << "\"";
} else {
output << it->second->getName() << "=";
}
return it->second->appendAttributes(output, outputFormat);
}
void MessageMap::clear() { void MessageMap::clear() {
m_loadedFiles.clear(); m_loadedFiles.clear();
m_loadedFileInfos.clear(); m_loadedFileInfos.clear();
@@ -2553,11 +2608,12 @@ void MessageMap::clear() {
m_pollMessages.pop(); m_pollMessages.pop();
} }
// free message instances by name // free message instances by name
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) { for (auto it : m_messagesByName) {
vector<Message*> nameMessages = it->second; vector<Message*> nameMessages = it.second;
if (it->first[0] != '-') { // avoid double free: instances stored multiple times have a key starting with "-" if (it.first[0] == FIELD_SEPARATOR) { // avoid double free: instances stored multiple times have a special key
for (vector<Message*>::iterator nit = nameMessages.begin(); nit != nameMessages.end(); nit++) { continue;
Message* message = *nit; }
for (Message* message : it.second) {
map<uint64_t, vector<Message*> >::iterator keyIt = m_messagesByKey.find(message->getKey()); map<uint64_t, vector<Message*> >::iterator keyIt = m_messagesByKey.find(message->getKey());
if (keyIt != m_messagesByKey.end()) { if (keyIt != m_messagesByKey.end()) {
vector<Message*>* keyMessages = &keyIt->second; vector<Message*>* keyMessages = &keyIt->second;
@@ -2571,8 +2627,7 @@ void MessageMap::clear() {
} }
delete message; delete message;
} }
} it.second.clear();
nameMessages.clear();
} }
// free remaining message instances by key // free remaining message instances by key
for (map<uint64_t, vector<Message*> >::iterator it = m_messagesByKey.begin(); it != m_messagesByKey.end(); it++) { for (map<uint64_t, vector<Message*> >::iterator it = m_messagesByKey.begin(); it != m_messagesByKey.end(); it++) {
@@ -2605,6 +2660,10 @@ void MessageMap::clear() {
m_messagesByKey.clear(); m_messagesByKey.clear();
m_conditions.clear(); m_conditions.clear();
m_instructions.clear(); m_instructions.clear();
for (auto& it : m_circuitData) {
delete it.second;
}
m_circuitData.clear();
m_maxIdLength = m_maxBroadcastIdLength = 0; m_maxIdLength = m_maxBroadcastIdLength = 0;
m_additionalScanMessages = false; m_additionalScanMessages = false;
} }
+22 -1
View File
@@ -597,6 +597,15 @@ class Message : public AttributedItem {
*/ */
virtual void dumpField(ostream& output, size_t fieldId, bool withConditions = false) const; virtual void dumpField(ostream& output, size_t fieldId, bool withConditions = false) const;
/**
* Decode the message from the last stored data.
* @param output the @a ostringstream to append the decoded value(s) to.
* @param outputFormat the @a OutputFormat options to use.
* @param leadingSeparator whether to prepend a separator before the first value.
* @param fields the list of message and/or data field fields to write, or NULL for all.
*/
virtual void decode(ostringstream& output, OutputFormat outputFormat = 0, bool leadingSeparator = false,
vector<string>* fields = NULL) const;
protected: protected:
/** the optional circuit name. */ /** the optional circuit name. */
@@ -1449,6 +1458,15 @@ class MessageMap : public MappedFileReader {
*/ */
void addPollMessage(Message* message, bool toFront = false); void addPollMessage(Message* message, bool toFront = false);
/**
* Decode circuit specific data.
* @param circuit the name of the circuit.
* @param output the @a ostringstream to append the decoded value(s) to.
* @param outputFormat the @a OutputFormat options to use.
* @return true if data was added, false otherwise.
*/
bool decodeCircuit(const string circuit, ostringstream& output, OutputFormat outputFormat) const;
/** /**
* Removes all @a Message instances. * Removes all @a Message instances.
*/ */
@@ -1542,7 +1560,7 @@ class MessageMap : public MappedFileReader {
/** the number of distinct passive @a Message instances stored in @a m_messagesByKey. */ /** the number of distinct passive @a Message instances stored in @a m_messagesByKey. */
size_t m_passiveMessageCount; size_t m_passiveMessageCount;
/** the known @a Message instances by lowercase circuit and name. */ /** the known @a Message instances by lowercase circuit (optional), name, and type. */
map<string, vector<Message*> > m_messagesByName; map<string, vector<Message*> > m_messagesByName;
/** the known @a Message instances by key. */ /** the known @a Message instances by key. */
@@ -1556,6 +1574,9 @@ class MessageMap : public MappedFileReader {
/** the list of @a Instruction instances by filename. */ /** the list of @a Instruction instances by filename. */
map<string, vector<Instruction*> > m_instructions; map<string, vector<Instruction*> > m_instructions;
/** additional attributes by circuit name. */
map<string, AttributedItem*> m_circuitData;
}; };
} // namespace ebusd } // namespace ebusd