added circuit level attributes for JSON output, corrected sorting of messages in result of MessageMap::findAll()
This commit is contained in:
+4
-25
@@ -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);
|
||||
|
||||
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();) {
|
||||
Message* message = *it++;
|
||||
symbol_t dstAddress = message->getDstAddress();
|
||||
@@ -1643,34 +1644,12 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
|
||||
}
|
||||
lastCircuit = message->getCircuit();
|
||||
result << "\n \"" << lastCircuit << "\": {";
|
||||
// TODO add circuit specific values
|
||||
first = true;
|
||||
}
|
||||
if (first) {
|
||||
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) << "\"";
|
||||
if (full && m_messages->decodeCircuit(lastCircuit, result, verbosity)) { // add circuit specific values
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
result << ",\n \"passive\": " << (message->isPassive() ? "true" : "false");
|
||||
result << ",\n \"write\": " << (message->isWrite() ? "true" : "false");
|
||||
result << "\n }";
|
||||
message->decode(result, verbosity, !first);
|
||||
}
|
||||
|
||||
if (lastCircuit.length() > 0) {
|
||||
|
||||
+86
-27
@@ -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,
|
||||
const bool isWrite, const map<string, string>& attributes,
|
||||
@@ -1767,7 +1794,8 @@ result_t MessageMap::add(Message* message, bool storeByName) {
|
||||
}
|
||||
string name = message->getName();
|
||||
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) {
|
||||
map<string, vector<Message*> >::iterator nameIt = m_messagesByName.find(nameKey);
|
||||
if (nameIt != m_messagesByName.end()) {
|
||||
@@ -1778,7 +1806,7 @@ result_t MessageMap::add(Message* message, bool storeByName) {
|
||||
}
|
||||
}
|
||||
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);
|
||||
if (nameIt == m_messagesByName.end()) {
|
||||
// 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;
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (type.empty()) {
|
||||
errorDescription = "invalid default definition";
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
string defaultCircuit = defaults["circuit"];
|
||||
if (type.empty()) {
|
||||
if (defaultCircuit.empty()) {
|
||||
errorDescription = "invalid default definition";
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
// circuit level additional attributes
|
||||
}
|
||||
string defaultSuffix = defaults["suffix"];
|
||||
defaults.erase("suffix");
|
||||
for (auto entry : row) {
|
||||
@@ -1956,6 +1987,16 @@ result_t MessageMap::addDefaultFromFile(map<string, string>& row, vector< map<st
|
||||
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;
|
||||
vector< map<string, string> > subDefaults = subRows; // ensure to have a copy
|
||||
getSubDefaults()[type] = subDefaults;
|
||||
@@ -2362,16 +2403,17 @@ Message* MessageMap::find(const string& circuit, const string& name, const strin
|
||||
FileReader::tolower(lcircuit);
|
||||
string lname = name;
|
||||
FileReader::tolower(lname);
|
||||
string suffix = FIELD_SEPARATOR + lname + (isPassive ? "P" : (isWrite ? "W" : "R"));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
string key;
|
||||
string nameKey;
|
||||
if (i == 0) {
|
||||
key = string(isPassive ? "P" : (isWrite ? "W" : "R")) + lcircuit + FIELD_SEPARATOR + lname;
|
||||
} else if (lcircuit.length() == 0) {
|
||||
key = string(isPassive ? "-P" : (isWrite ? "-W" : "-R")) + lname; // second try: without circuit
|
||||
nameKey = lcircuit + suffix;
|
||||
} else if (lcircuit.empty()) {
|
||||
nameKey = suffix; // second try: without circuit
|
||||
} else {
|
||||
continue; // not allowed without circuit
|
||||
}
|
||||
auto it = m_messagesByName.find(key);
|
||||
auto it = m_messagesByName.find(nameKey);
|
||||
if (it != m_messagesByName.end()) {
|
||||
Message* message = getFirstAvailable(it->second);
|
||||
if (message && message->hasLevel(levels)) {
|
||||
@@ -2395,7 +2437,7 @@ deque<Message*> MessageMap::findAll(const string& circuit, const string& name, c
|
||||
bool checkLevel = levels != "*";
|
||||
bool checkName = lname.length() > 0;
|
||||
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;
|
||||
}
|
||||
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() {
|
||||
m_loadedFiles.clear();
|
||||
m_loadedFileInfos.clear();
|
||||
@@ -2553,26 +2608,26 @@ void MessageMap::clear() {
|
||||
m_pollMessages.pop();
|
||||
}
|
||||
// free message instances by name
|
||||
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) {
|
||||
vector<Message*> nameMessages = it->second;
|
||||
if (it->first[0] != '-') { // avoid double free: instances stored multiple times have a key starting with "-"
|
||||
for (vector<Message*>::iterator nit = nameMessages.begin(); nit != nameMessages.end(); nit++) {
|
||||
Message* message = *nit;
|
||||
map<uint64_t, vector<Message*> >::iterator keyIt = m_messagesByKey.find(message->getKey());
|
||||
if (keyIt != m_messagesByKey.end()) {
|
||||
vector<Message*>* keyMessages = &keyIt->second;
|
||||
if (!keyMessages->empty()) {
|
||||
for (vector<Message*>::iterator kit = keyMessages->begin(); kit != keyMessages->end(); kit++) {
|
||||
if (*kit == message) {
|
||||
keyMessages->erase(kit--);
|
||||
}
|
||||
for (auto it : m_messagesByName) {
|
||||
vector<Message*> nameMessages = it.second;
|
||||
if (it.first[0] == FIELD_SEPARATOR) { // avoid double free: instances stored multiple times have a special key
|
||||
continue;
|
||||
}
|
||||
for (Message* message : it.second) {
|
||||
map<uint64_t, vector<Message*> >::iterator keyIt = m_messagesByKey.find(message->getKey());
|
||||
if (keyIt != m_messagesByKey.end()) {
|
||||
vector<Message*>* keyMessages = &keyIt->second;
|
||||
if (!keyMessages->empty()) {
|
||||
for (vector<Message*>::iterator kit = keyMessages->begin(); kit != keyMessages->end(); kit++) {
|
||||
if (*kit == message) {
|
||||
keyMessages->erase(kit--);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete message;
|
||||
}
|
||||
delete message;
|
||||
}
|
||||
nameMessages.clear();
|
||||
it.second.clear();
|
||||
}
|
||||
// free remaining message instances by key
|
||||
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_conditions.clear();
|
||||
m_instructions.clear();
|
||||
for (auto& it : m_circuitData) {
|
||||
delete it.second;
|
||||
}
|
||||
m_circuitData.clear();
|
||||
m_maxIdLength = m_maxBroadcastIdLength = 0;
|
||||
m_additionalScanMessages = false;
|
||||
}
|
||||
|
||||
+22
-1
@@ -597,6 +597,15 @@ class Message : public AttributedItem {
|
||||
*/
|
||||
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:
|
||||
/** the optional circuit name. */
|
||||
@@ -1449,6 +1458,15 @@ class MessageMap : public MappedFileReader {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -1542,7 +1560,7 @@ class MessageMap : public MappedFileReader {
|
||||
/** the number of distinct passive @a Message instances stored in @a m_messagesByKey. */
|
||||
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;
|
||||
|
||||
/** the known @a Message instances by key. */
|
||||
@@ -1556,6 +1574,9 @@ class MessageMap : public MappedFileReader {
|
||||
|
||||
/** the list of @a Instruction instances by filename. */
|
||||
map<string, vector<Instruction*> > m_instructions;
|
||||
|
||||
/** additional attributes by circuit name. */
|
||||
map<string, AttributedItem*> m_circuitData;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
|
||||
Reference in New Issue
Block a user