Generalize XML record/replay base classes.

This commit is contained in:
sawinglogz 2020-06-21 14:19:46 -04:00
parent a651e1405d
commit 2d2e44fd36

View File

@ -7,6 +7,7 @@
* for more details. */ * for more details. */
#include "deviceconnection.h" #include "deviceconnection.h"
#include "version.h"
#include <QtSerialPort/QSerialPortInfo> #include <QtSerialPort/QSerialPortInfo>
#include <QFile> #include <QFile>
#include <QBuffer> #include <QBuffer>
@ -26,34 +27,40 @@ static QString hex(int i)
class XmlRecorder class XmlRecorder
{ {
public: public:
XmlRecorder(class QFile * file); static const QString TAG;
XmlRecorder(QString & string);
~XmlRecorder(); XmlRecorder(class QFile * file, const QString & tag = XmlRecorder::TAG);
XmlRecorder(QString & string, const QString & tag = XmlRecorder::TAG);
virtual ~XmlRecorder();
inline QXmlStreamWriter & xml() { return *m_xml; } inline QXmlStreamWriter & xml() { return *m_xml; }
inline void lock() { m_mutex.lock(); } inline void lock() { m_mutex.lock(); }
inline void unlock() { m_mutex.unlock(); } inline void unlock() { m_mutex.unlock(); }
protected: protected:
const QString m_tag;
QFile* m_file; // nullptr for non-file recordings QFile* m_file; // nullptr for non-file recordings
QXmlStreamWriter* m_xml; QXmlStreamWriter* m_xml;
QMutex m_mutex; QMutex m_mutex;
void prologue(); virtual void prologue();
void epilogue(); virtual void epilogue();
}; };
const QString XmlRecorder::TAG = "xmlreplay";
class XmlReplayEvent; class XmlReplayEvent;
class XmlReplay class XmlReplay
{ {
public: public:
XmlReplay(class QFile * file); XmlReplay(class QFile * file, const QString & tag = XmlRecorder::TAG);
XmlReplay(QXmlStreamReader & xml); XmlReplay(QXmlStreamReader & xml, const QString & tag = XmlRecorder::TAG);
~XmlReplay(); virtual ~XmlReplay();
template<class T> inline T* getNextEvent(const QString & id = ""); template<class T> inline T* getNextEvent(const QString & id = "");
protected: protected:
void deserialize(QXmlStreamReader & xml); void deserialize(QXmlStreamReader & xml);
void deserializeEvents(QXmlStreamReader & xml); void deserializeEvents(QXmlStreamReader & xml);
const QString m_tag;
QHash<QString,QHash<QString,QList<XmlReplayEvent*>>> m_eventIndex; QHash<QString,QHash<QString,QList<XmlReplayEvent*>>> m_eventIndex;
QHash<QString,QHash<QString,int>> m_indexPosition; QHash<QString,QHash<QString,int>> m_indexPosition;
@ -212,14 +219,14 @@ protected:
XmlReplay* m_replay; XmlReplay* m_replay;
}; };
XmlRecorder::XmlRecorder(QFile* stream) XmlRecorder::XmlRecorder(QFile* stream, const QString & tag)
: m_file(stream), m_xml(new QXmlStreamWriter(stream)) : m_tag(tag), m_file(stream), m_xml(new QXmlStreamWriter(stream))
{ {
prologue(); prologue();
} }
XmlRecorder::XmlRecorder(QString & string) XmlRecorder::XmlRecorder(QString & string, const QString & tag)
: m_file(nullptr), m_xml(new QXmlStreamWriter(&string)) : m_tag(tag), m_file(nullptr), m_xml(new QXmlStreamWriter(&string))
{ {
prologue(); prologue();
} }
@ -235,28 +242,24 @@ void XmlRecorder::prologue()
Q_ASSERT(m_xml); Q_ASSERT(m_xml);
m_xml->setAutoFormatting(true); m_xml->setAutoFormatting(true);
m_xml->setAutoFormattingIndent(2); m_xml->setAutoFormattingIndent(2);
m_xml->writeStartElement(m_tag);
m_xml->writeStartElement("xmlreplay");
m_xml->writeStartElement("events");
} }
void XmlRecorder::epilogue() void XmlRecorder::epilogue()
{ {
Q_ASSERT(m_xml); Q_ASSERT(m_xml);
m_xml->writeEndElement(); // close events m_xml->writeEndElement(); // close enclosing tag
// TODO: write out any inline connections
m_xml->writeEndElement(); // close xmlreplay
} }
XmlReplay::XmlReplay(QFile* file) XmlReplay::XmlReplay(QFile* file, const QString & tag)
: m_pendingSignal(nullptr) : m_tag(tag), m_pendingSignal(nullptr)
{ {
QXmlStreamReader xml(file); QXmlStreamReader xml(file);
deserialize(xml); deserialize(xml);
} }
XmlReplay::XmlReplay(QXmlStreamReader & xml) XmlReplay::XmlReplay(QXmlStreamReader & xml, const QString & tag)
: m_pendingSignal(nullptr) : m_tag(tag), m_pendingSignal(nullptr)
{ {
deserialize(xml); deserialize(xml);
} }
@ -271,16 +274,11 @@ XmlReplay::~XmlReplay()
void XmlReplay::deserialize(QXmlStreamReader & xml) void XmlReplay::deserialize(QXmlStreamReader & xml)
{ {
if (xml.readNextStartElement()) { if (xml.readNextStartElement()) {
if (xml.name() == "xmlreplay") { if (xml.name() == m_tag) {
while (xml.readNextStartElement()) { deserializeEvents(xml);
if (xml.name() == "events") { } else {
deserializeEvents(xml); qWarning() << "unexpected payload in replay XML:" << xml.name();
// else TODO: inline connections xml.skipCurrentElement();
} else {
qWarning() << "unexpected payload in replay XML:" << xml.name();
xml.skipCurrentElement();
}
}
} }
} }
} }
@ -516,6 +514,29 @@ template<> const bool XmlReplayBase<type>::registered = XmlReplayEvent::register
// MARK: - // MARK: -
// MARK: Device connection manager // MARK: Device connection manager
class DeviceRecorder : public XmlRecorder
{
virtual void prologue()
{
XmlRecorder::prologue();
m_xml->writeAttribute("oscar", getVersion().toString());
}
public:
static const QString TAG;
DeviceRecorder(class QFile * file) : XmlRecorder(file, DeviceRecorder::TAG) {}
DeviceRecorder(QString & string) : XmlRecorder(string, DeviceRecorder::TAG) {}
};
const QString DeviceRecorder::TAG = "devicereplay";
class DeviceReplay : public XmlReplay
{
public:
DeviceReplay(class QFile * file) : XmlReplay(file, DeviceRecorder::TAG) {}
DeviceReplay(QXmlStreamReader & xml) : XmlReplay(xml, DeviceRecorder::TAG) {}
};
inline DeviceConnectionManager & DeviceConnectionManager::getInstance() inline DeviceConnectionManager & DeviceConnectionManager::getInstance()
{ {
static DeviceConnectionManager instance; static DeviceConnectionManager instance;
@ -533,7 +554,7 @@ void DeviceConnectionManager::record(QFile* stream)
delete m_record; delete m_record;
} }
if (stream) { if (stream) {
m_record = new XmlRecorder(stream); m_record = new DeviceRecorder(stream);
} else { } else {
// nullptr turns off recording // nullptr turns off recording
m_record = nullptr; m_record = nullptr;
@ -545,7 +566,7 @@ void DeviceConnectionManager::record(QString & string)
if (m_record) { if (m_record) {
delete m_record; delete m_record;
} }
m_record = new XmlRecorder(string); m_record = new DeviceRecorder(string);
} }
void DeviceConnectionManager::replay(const QString & string) void DeviceConnectionManager::replay(const QString & string)
@ -555,7 +576,7 @@ void DeviceConnectionManager::replay(const QString & string)
if (m_replay) { if (m_replay) {
delete m_replay; delete m_replay;
} }
m_replay = new XmlReplay(xml); m_replay = new DeviceReplay(xml);
} }
void DeviceConnectionManager::replay(QFile* file) void DeviceConnectionManager::replay(QFile* file)
@ -565,7 +586,7 @@ void DeviceConnectionManager::replay(QFile* file)
delete m_replay; delete m_replay;
} }
if (file) { if (file) {
m_replay = new XmlReplay(file); m_replay = new DeviceReplay(file);
} else { } else {
// nullptr turns off replay // nullptr turns off replay
m_replay = nullptr; m_replay = nullptr;
@ -791,6 +812,24 @@ bool SerialPortInfo::operator==(const SerialPortInfo & other) const
// MARK: - // MARK: -
// MARK: Device connection base class // MARK: Device connection base class
class ConnectionRecorder : public XmlRecorder
{
public:
static const QString TAG;
ConnectionRecorder(class QFile * file) : XmlRecorder(file, ConnectionRecorder::TAG) {}
ConnectionRecorder(QString & string) : XmlRecorder(string, ConnectionRecorder::TAG) {}
};
const QString ConnectionRecorder::TAG = "connection";
class ConnectionReplay : public XmlReplay
{
public:
ConnectionReplay(class QFile * file) : XmlReplay(file, ConnectionRecorder::TAG) {}
ConnectionReplay(QXmlStreamReader & xml) : XmlReplay(xml, ConnectionRecorder::TAG) {}
};
DeviceConnection::DeviceConnection(const QString & name, XmlRecorder* record, XmlReplay* replay) DeviceConnection::DeviceConnection(const QString & name, XmlRecorder* record, XmlReplay* replay)
: m_name(name), m_record(record), m_replay(replay), m_opened(false) : m_name(name), m_record(record), m_replay(replay), m_opened(false)
{ {