commit
96ed163ab0
@ -27,12 +27,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#include "portstatswindow.h"
|
||||
#include "portswindow.h"
|
||||
#include "preferences.h"
|
||||
#include "sessionfileformat.h"
|
||||
#include "settings.h"
|
||||
#include "ui_about.h"
|
||||
#include "updater.h"
|
||||
|
||||
#include "fileformat.pb.h"
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include <QProgressDialog>
|
||||
|
||||
extern const char* version;
|
||||
extern const char* revision;
|
||||
@ -75,7 +81,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
|
||||
setupUi(this);
|
||||
|
||||
menuFile->insertActions(menuFile->actions().at(0), portsWindow->actions());
|
||||
menuFile->insertActions(menuFile->actions().at(3), portsWindow->actions());
|
||||
|
||||
statsDock->setWidget(statsWindow);
|
||||
addDockWidget(Qt::BottomDockWidgetArea, statsDock);
|
||||
@ -133,6 +139,102 @@ MainWindow::~MainWindow()
|
||||
delete localServer_;
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOpenSession_triggered()
|
||||
{
|
||||
qDebug("Open Session Action");
|
||||
|
||||
static QString dirName;
|
||||
QString fileName;
|
||||
QStringList fileTypes = SessionFileFormat::supportedFileTypes(
|
||||
SessionFileFormat::kOpenFile);
|
||||
QString fileType;
|
||||
QString errorStr;
|
||||
bool ret;
|
||||
|
||||
if (portsWindow->portGroupCount()) {
|
||||
if (QMessageBox::question(this,
|
||||
tr("Open Session"),
|
||||
tr("Existing session will be lost. Proceed?"),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No) == QMessageBox::No)
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if (fileTypes.size())
|
||||
fileType = fileTypes.at(0);
|
||||
|
||||
fileName = QFileDialog::getOpenFileName(this, tr("Open Session"),
|
||||
dirName, fileTypes.join(";;"), &fileType);
|
||||
if (fileName.isEmpty())
|
||||
goto _exit;
|
||||
|
||||
ret = openSession(fileName, errorStr);
|
||||
if (!ret || !errorStr.isEmpty()) {
|
||||
QMessageBox msgBox(this);
|
||||
QStringList str = errorStr.split("\n\n\n\n");
|
||||
|
||||
msgBox.setIcon(ret ? QMessageBox::Warning : QMessageBox::Critical);
|
||||
msgBox.setWindowTitle(qApp->applicationName());
|
||||
msgBox.setText(str.at(0));
|
||||
if (str.size() > 1)
|
||||
msgBox.setDetailedText(str.at(1));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
|
||||
msgBox.exec();
|
||||
}
|
||||
dirName = QFileInfo(fileName).absolutePath();
|
||||
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSaveSession_triggered()
|
||||
{
|
||||
qDebug("Save Session Action");
|
||||
|
||||
static QString fileName;
|
||||
QStringList fileTypes = SessionFileFormat::supportedFileTypes(
|
||||
SessionFileFormat::kSaveFile);
|
||||
QString fileType;
|
||||
QString errorStr;
|
||||
QFileDialog::Options options;
|
||||
|
||||
if (portsWindow->reservedPortCount()) {
|
||||
QString myself = appSettings->value(kUserKey, kUserDefaultValue)
|
||||
.toString();
|
||||
if (QMessageBox::question(this,
|
||||
tr("Save Session"),
|
||||
QString("Some ports are reserved!\n\nOnly ports reserved by %1 will be saved. Proceed?").arg(myself),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No) == QMessageBox::No)
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
// On Mac OS with Native Dialog, getSaveFileName() ignores fileType.
|
||||
// Although currently there's only one supported file type, we may
|
||||
// have more in the future
|
||||
#if defined(Q_OS_MAC)
|
||||
options |= QFileDialog::DontUseNativeDialog;
|
||||
#endif
|
||||
|
||||
if (fileTypes.size())
|
||||
fileType = fileTypes.at(0);
|
||||
|
||||
fileName = QFileDialog::getSaveFileName(this, tr("Save Session"),
|
||||
fileName, fileTypes.join(";;"), &fileType, options);
|
||||
if (fileName.isEmpty())
|
||||
goto _exit;
|
||||
|
||||
if (!saveSession(fileName, fileType, errorStr))
|
||||
QMessageBox::critical(this, qApp->applicationName(), errorStr);
|
||||
else if (!errorStr.isEmpty())
|
||||
QMessageBox::warning(this, qApp->applicationName(), errorStr);
|
||||
|
||||
fileName = QFileInfo(fileName).absolutePath();
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MainWindow::on_actionPreferences_triggered()
|
||||
{
|
||||
Preferences *preferences = new Preferences();
|
||||
@ -172,3 +274,120 @@ void MainWindow::onNewVersion(QString newVersion)
|
||||
statusBar()->showMessage(QString("New Ostinato version %1 available. "
|
||||
"Visit http://ostinato.org to download").arg(newVersion));
|
||||
}
|
||||
|
||||
//! Returns true on success (or user cancel) and false on failure
|
||||
bool MainWindow::openSession(QString fileName, QString &error)
|
||||
{
|
||||
bool ret = false;
|
||||
QDialog *optDialog;
|
||||
QProgressDialog progress("Opening Session", "Cancel", 0, 0, this);
|
||||
OstProto::SessionContent session;
|
||||
SessionFileFormat *fmt = SessionFileFormat::fileFormatFromFile(fileName);
|
||||
|
||||
if (fmt == NULL) {
|
||||
error = tr("Unknown session file format");
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if ((optDialog = fmt->openOptionsDialog()))
|
||||
{
|
||||
int ret;
|
||||
optDialog->setParent(this, Qt::Dialog);
|
||||
ret = optDialog->exec();
|
||||
optDialog->setParent(0, Qt::Dialog);
|
||||
if (ret == QDialog::Rejected)
|
||||
goto _user_opt_cancel;
|
||||
}
|
||||
|
||||
progress.setAutoReset(false);
|
||||
progress.setAutoClose(false);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.show();
|
||||
|
||||
setDisabled(true);
|
||||
progress.setEnabled(true); // to override the mainWindow disable
|
||||
|
||||
connect(fmt, SIGNAL(status(QString)),&progress,SLOT(setLabelText(QString)));
|
||||
connect(fmt, SIGNAL(target(int)), &progress, SLOT(setMaximum(int)));
|
||||
connect(fmt, SIGNAL(progress(int)), &progress, SLOT(setValue(int)));
|
||||
connect(&progress, SIGNAL(canceled()), fmt, SLOT(cancel()));
|
||||
|
||||
fmt->openAsync(fileName, session, error);
|
||||
qDebug("after open async");
|
||||
|
||||
while (!fmt->isFinished())
|
||||
qApp->processEvents();
|
||||
qDebug("wait over for async operation");
|
||||
|
||||
if (!fmt->result())
|
||||
goto _fail;
|
||||
|
||||
// process any remaining events posted from the thread
|
||||
for (int i = 0; i < 10; i++)
|
||||
qApp->processEvents();
|
||||
|
||||
// XXX: user can't cancel operation from here on!
|
||||
progress.close();
|
||||
|
||||
portsWindow->openSession(&session, error);
|
||||
|
||||
_user_opt_cancel:
|
||||
ret = true;
|
||||
|
||||
_fail:
|
||||
progress.close();
|
||||
setEnabled(true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool MainWindow::saveSession(QString fileName, QString fileType, QString &error)
|
||||
{
|
||||
bool ret = false;
|
||||
QProgressDialog progress("Saving Session", "Cancel", 0, 0, this);
|
||||
SessionFileFormat *fmt = SessionFileFormat::fileFormatFromType(fileType);
|
||||
OstProto::SessionContent session;
|
||||
|
||||
if (fmt == NULL)
|
||||
goto _fail;
|
||||
|
||||
progress.setAutoReset(false);
|
||||
progress.setAutoClose(false);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.show();
|
||||
|
||||
setDisabled(true);
|
||||
progress.setEnabled(true); // to override the mainWindow disable
|
||||
|
||||
// Fill in session
|
||||
ret = portsWindow->saveSession(&session, error, &progress);
|
||||
if (!ret)
|
||||
goto _user_cancel;
|
||||
|
||||
connect(fmt, SIGNAL(status(QString)),&progress,SLOT(setLabelText(QString)));
|
||||
connect(fmt, SIGNAL(target(int)), &progress, SLOT(setMaximum(int)));
|
||||
connect(fmt, SIGNAL(progress(int)), &progress, SLOT(setValue(int)));
|
||||
connect(&progress, SIGNAL(canceled()), fmt, SLOT(cancel()));
|
||||
|
||||
fmt->saveAsync(session, fileName, error);
|
||||
qDebug("after save async");
|
||||
|
||||
while (!fmt->isFinished())
|
||||
qApp->processEvents();
|
||||
qDebug("wait over for async operation");
|
||||
|
||||
ret = fmt->result();
|
||||
goto _exit;
|
||||
|
||||
_user_cancel:
|
||||
goto _exit;
|
||||
|
||||
_fail:
|
||||
error = QString("Unsupported File Type - %1").arg(fileType);
|
||||
goto _exit;
|
||||
|
||||
_exit:
|
||||
progress.close();
|
||||
setEnabled(true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,9 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
bool openSession(QString fileName, QString &error);
|
||||
bool saveSession(QString fileName, QString fileType, QString &error);
|
||||
|
||||
QProcess *localServer_;
|
||||
PortsWindow *portsWindow;
|
||||
PortStatsWindow *statsWindow;
|
||||
@ -48,6 +51,8 @@ public:
|
||||
~MainWindow();
|
||||
|
||||
public slots:
|
||||
void on_actionOpenSession_triggered();
|
||||
void on_actionSaveSession_triggered();
|
||||
void on_actionPreferences_triggered();
|
||||
void on_actionViewRestoreDefaults_triggered();
|
||||
void on_actionHelpAbout_triggered();
|
||||
|
@ -21,6 +21,8 @@
|
||||
<property name="title" >
|
||||
<string>&File</string>
|
||||
</property>
|
||||
<addaction name="actionOpenSession" />
|
||||
<addaction name="actionSaveSession" />
|
||||
<addaction name="separator" />
|
||||
<addaction name="actionPreferences" />
|
||||
<addaction name="actionFileExit" />
|
||||
@ -89,6 +91,16 @@
|
||||
<string>Restore &Defaults</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpenSession" >
|
||||
<property name="text" >
|
||||
<string>Open Session ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSaveSession" >
|
||||
<property name="text" >
|
||||
<string>Save Session ...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="ostinato.qrc" />
|
||||
|
@ -19,8 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
#include "emulation.h"
|
||||
#include "streamfileformat.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
@ -66,6 +66,11 @@ Port::~Port()
|
||||
delete mStreams.takeFirst();
|
||||
}
|
||||
|
||||
void Port::protoDataCopyInto(OstProto::Port *data)
|
||||
{
|
||||
data->CopyFrom(d);
|
||||
}
|
||||
|
||||
void Port::updatePortConfig(OstProto::Port *port)
|
||||
{
|
||||
bool recalc = false;
|
||||
@ -76,6 +81,10 @@ void Port::updatePortConfig(OstProto::Port *port)
|
||||
|
||||
d.MergeFrom(*port);
|
||||
|
||||
// Setup a user-friendly alias for Win32 ports
|
||||
if (name().startsWith("\\Device\\NPF_"))
|
||||
setAlias(QString("if%1").arg(id()));
|
||||
|
||||
if (recalc)
|
||||
recalculateAverageRates();
|
||||
}
|
||||
@ -449,6 +458,40 @@ void Port::getModifiedDeviceGroupsSinceLastSync(
|
||||
->CopyFrom(*deviceGroupById(id));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Finds the user modifiable fields in 'config' that are different from
|
||||
* the current configuration on the port and modifes 'config' such that
|
||||
* only those fields are set and returns true. If 'config' is same as
|
||||
* current port config, 'config' is unmodified and false is returned
|
||||
*/
|
||||
bool Port::modifiablePortConfig(OstProto::Port &config) const
|
||||
{
|
||||
bool change = false;
|
||||
OstProto::Port modCfg;
|
||||
|
||||
if (config.is_exclusive_control() != d.is_exclusive_control()) {
|
||||
modCfg.set_is_exclusive_control(config.is_exclusive_control());
|
||||
change = true;
|
||||
}
|
||||
if (config.transmit_mode() != d.transmit_mode()) {
|
||||
modCfg.set_transmit_mode(config.transmit_mode());
|
||||
change = true;
|
||||
}
|
||||
if (config.user_name() != d.user_name()) {
|
||||
modCfg.set_user_name(config.user_name());
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (change) {
|
||||
modCfg.mutable_port_id()->set_id(id());
|
||||
config.CopyFrom(modCfg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Port::when_syncComplete()
|
||||
{
|
||||
//reorderStreamsByOrdinals();
|
||||
@ -510,10 +553,12 @@ bool Port::openStreams(QString fileName, bool append, QString &error)
|
||||
QDialog *optDialog;
|
||||
QProgressDialog progress("Opening Streams", "Cancel", 0, 0, mainWindow);
|
||||
OstProto::StreamConfigList streams;
|
||||
AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromFile(fileName);
|
||||
StreamFileFormat *fmt = StreamFileFormat::fileFormatFromFile(fileName);
|
||||
|
||||
if (fmt == NULL)
|
||||
if (fmt == NULL) {
|
||||
error = tr("Unknown streams file format");
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if ((optDialog = fmt->openOptionsDialog()))
|
||||
{
|
||||
@ -538,12 +583,12 @@ bool Port::openStreams(QString fileName, bool append, QString &error)
|
||||
connect(fmt, SIGNAL(progress(int)), &progress, SLOT(setValue(int)));
|
||||
connect(&progress, SIGNAL(canceled()), fmt, SLOT(cancel()));
|
||||
|
||||
fmt->openStreamsOffline(fileName, streams, error);
|
||||
qDebug("after open offline");
|
||||
fmt->openAsync(fileName, streams, error);
|
||||
qDebug("after open async");
|
||||
|
||||
while (!fmt->isFinished())
|
||||
qApp->processEvents();
|
||||
qDebug("wait over for offline operation");
|
||||
qDebug("wait over for async operation");
|
||||
|
||||
if (!fmt->result())
|
||||
goto _fail;
|
||||
@ -597,7 +642,7 @@ bool Port::saveStreams(QString fileName, QString fileType, QString &error)
|
||||
{
|
||||
bool ret = false;
|
||||
QProgressDialog progress("Saving Streams", "Cancel", 0, 0, mainWindow);
|
||||
AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromType(fileType);
|
||||
StreamFileFormat *fmt = StreamFileFormat::fileFormatFromType(fileType);
|
||||
OstProto::StreamConfigList streams;
|
||||
|
||||
if (fmt == NULL)
|
||||
@ -631,12 +676,12 @@ bool Port::saveStreams(QString fileName, QString fileType, QString &error)
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
fmt->saveStreamsOffline(streams, fileName, error);
|
||||
qDebug("after save offline");
|
||||
fmt->saveAsync(streams, fileName, error);
|
||||
qDebug("after save async");
|
||||
|
||||
while (!fmt->isFinished())
|
||||
qApp->processEvents();
|
||||
qDebug("wait over for offline operation");
|
||||
qDebug("wait over for async operation");
|
||||
|
||||
ret = fmt->result();
|
||||
goto _exit;
|
||||
|
@ -79,7 +79,8 @@ public:
|
||||
~Port();
|
||||
|
||||
quint32 portGroupId() const { return mPortGroupId; }
|
||||
const QString& userAlias() const { return mUserAlias; }
|
||||
const QString userAlias() const
|
||||
{ return mUserAlias.isEmpty() ? name() : mUserAlias; }
|
||||
|
||||
quint32 id() const
|
||||
{ return d.port_id().id(); }
|
||||
@ -103,7 +104,7 @@ public:
|
||||
{ return avgBitsPerSec_; }
|
||||
|
||||
//void setAdminEnable(AdminStatus status) { mAdminStatus = status; }
|
||||
void setAlias(QString &alias) { mUserAlias = alias; }
|
||||
void setAlias(QString alias) { mUserAlias = alias; }
|
||||
//void setExclusive(bool flag);
|
||||
|
||||
int numStreams() { return mStreams.size(); }
|
||||
@ -126,6 +127,8 @@ public:
|
||||
return capFile_;
|
||||
}
|
||||
|
||||
void protoDataCopyInto(OstProto::Port *data);
|
||||
|
||||
// FIXME(MED): naming inconsistency - PortConfig/Stream; also retVal
|
||||
void updatePortConfig(OstProto::Port *port);
|
||||
|
||||
@ -153,6 +156,8 @@ public:
|
||||
void getModifiedDeviceGroupsSinceLastSync(
|
||||
OstProto::DeviceGroupConfigList &streamConfigList);
|
||||
|
||||
bool modifiablePortConfig(OstProto::Port &config) const;
|
||||
|
||||
void when_syncComplete();
|
||||
|
||||
void setAveragePacketRate(double packetsPerSec);
|
||||
|
@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#include "settings.h"
|
||||
|
||||
#include "emulproto.pb.h"
|
||||
#include "fileformat.pb.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCursor>
|
||||
@ -50,6 +51,8 @@ PortGroup::PortGroup(QString serverName, quint16 port)
|
||||
statsController = new PbRpcController(portIdList_, portStatsList_);
|
||||
isGetStatsPending_ = false;
|
||||
|
||||
atConnectConfig_ = NULL;
|
||||
|
||||
compat = kUnknown;
|
||||
|
||||
reconnect = false;
|
||||
@ -91,8 +94,39 @@ PortGroup::~PortGroup()
|
||||
delete serviceStub;
|
||||
delete rpcChannel;
|
||||
delete statsController;
|
||||
delete atConnectConfig_;
|
||||
}
|
||||
|
||||
void PortGroup::setConfigAtConnect(const OstProto::PortGroupContent *config)
|
||||
{
|
||||
if (!config) {
|
||||
delete atConnectConfig_;
|
||||
atConnectConfig_ = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!atConnectConfig_)
|
||||
atConnectConfig_ = new OstProto::PortGroupContent;
|
||||
atConnectConfig_->CopyFrom(*config);
|
||||
}
|
||||
|
||||
int PortGroup::numReservedPorts() const
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < mPorts.size(); i++)
|
||||
{
|
||||
if (!mPorts[i]->userName().isEmpty())
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
const QString PortGroup::serverFullName() const
|
||||
{
|
||||
return serverPort() == DEFAULT_SERVER_PORT ?
|
||||
serverName() : QString("%1:%2").arg(serverName()).arg(serverPort());
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// Slots
|
||||
@ -189,6 +223,7 @@ void PortGroup::on_rpcChannel_disconnected()
|
||||
|
||||
while (!mPorts.isEmpty())
|
||||
delete mPorts.takeFirst();
|
||||
atConnectPortConfig_.clear();
|
||||
|
||||
emit portListChanged(mPortGroupId);
|
||||
emit portGroupDataChanged(mPortGroupId);
|
||||
@ -306,6 +341,7 @@ void PortGroup::processPortIdList(PbRpcController *controller)
|
||||
this, SIGNAL(portGroupDataChanged(int, int)));
|
||||
qDebug("before port append\n");
|
||||
mPorts.append(p);
|
||||
atConnectPortConfig_.append(NULL); // will be filled later
|
||||
}
|
||||
|
||||
emit portListChanged(mPortGroupId);
|
||||
@ -368,10 +404,52 @@ void PortGroup::processPortConfigList(PbRpcController *controller)
|
||||
emit portListChanged(mPortGroupId);
|
||||
|
||||
if (numPorts() > 0) {
|
||||
// XXX: The open session code (atConnectConfig_ related) assumes
|
||||
// the following two RPCs are invoked in the below order
|
||||
// Any change here without coressponding change in that code
|
||||
// will break stuff
|
||||
getDeviceGroupIdList();
|
||||
getStreamIdList();
|
||||
}
|
||||
|
||||
// Now that we have the port details, let's identify which ports
|
||||
// need to be re-configured based on atConnectConfig_
|
||||
if (atConnectConfig_ && numPorts() > 0)
|
||||
{
|
||||
QString myself = appSettings->value(kUserKey, kUserDefaultValue)
|
||||
.toString();
|
||||
for (int i = 0; i < atConnectConfig_->ports_size(); i++)
|
||||
{
|
||||
const OstProto::PortContent *pc = &atConnectConfig_->ports(i);
|
||||
for (int j = 0; j < mPorts.size(); j++)
|
||||
{
|
||||
Port *port = mPorts[j];
|
||||
|
||||
if (port->name() == pc->port_config().name().c_str())
|
||||
{
|
||||
if (!port->userName().isEmpty() // rsvd?
|
||||
&& port->userName() != myself) // by someone else?
|
||||
{
|
||||
QString warning =
|
||||
QString("%1 - %2: %3 is reserved by %4.\n\n"
|
||||
"Port will not be reconfigured.")
|
||||
.arg(serverFullName())
|
||||
.arg(j)
|
||||
.arg(port->userAlias())
|
||||
.arg(port->userName());
|
||||
QMessageBox::warning(NULL, tr("Open Session"), warning);
|
||||
qWarning(qPrintable(warning));
|
||||
continue;
|
||||
}
|
||||
atConnectPortConfig_[j] = pc;
|
||||
qDebug("port %d will be reconfigured", j);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_error_exit:
|
||||
delete controller;
|
||||
}
|
||||
@ -657,10 +735,10 @@ void PortGroup::modifyPort(int portIndex, OstProto::Port portConfig)
|
||||
|
||||
PbRpcController *controller = new PbRpcController(portConfigList, ack);
|
||||
serviceStub->modifyPort(controller, portConfigList, ack,
|
||||
NewCallback(this, &PortGroup::processModifyPortAck, controller));
|
||||
NewCallback(this, &PortGroup::processModifyPortAck, true, controller));
|
||||
}
|
||||
|
||||
void PortGroup::processModifyPortAck(PbRpcController *controller)
|
||||
void PortGroup::processModifyPortAck(bool restoreUi,PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
@ -670,8 +748,10 @@ void PortGroup::processModifyPortAck(PbRpcController *controller)
|
||||
qPrintable(controller->ErrorString()));
|
||||
}
|
||||
|
||||
mainWindow->setEnabled(true);
|
||||
QApplication::restoreOverrideCursor();
|
||||
if (restoreUi) {
|
||||
mainWindow->setEnabled(true);
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
delete controller;
|
||||
}
|
||||
|
||||
@ -725,6 +805,8 @@ void PortGroup::processStreamIdList(int portIndex, PbRpcController *controller)
|
||||
{
|
||||
OstProto::StreamIdList *streamIdList
|
||||
= static_cast<OstProto::StreamIdList*>(controller->response());
|
||||
const OstProto::PortContent *newPortContent
|
||||
= atConnectPortConfig_.at(portIndex);
|
||||
|
||||
qDebug("In %s (portIndex = %d)", __FUNCTION__, portIndex);
|
||||
|
||||
@ -744,51 +826,192 @@ void PortGroup::processStreamIdList(int portIndex, PbRpcController *controller)
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
for(int i = 0; i < streamIdList->stream_id_size(); i++)
|
||||
if (newPortContent)
|
||||
{
|
||||
uint streamId;
|
||||
// This port needs to configured with new content - to do this
|
||||
// we'll insert the following RPC sequence at this point and once
|
||||
// this sequence is over, return to the regular RPC sequence by
|
||||
// re-requesting getStreamId()
|
||||
// * delete (existing) deviceGroups
|
||||
// (already done by processDeviceIdList)
|
||||
// * delete (existing) streams
|
||||
// * modify port
|
||||
// * add (new) deviceGroup ids
|
||||
// * modify (new) deviceGroups
|
||||
// * add (new) stream ids
|
||||
// * modify (new) streams
|
||||
// XXX: This assumes getDeviceGroupIdList() was invoked before
|
||||
// getStreamIdList() - if the order changes this code will break!
|
||||
|
||||
streamId = streamIdList->stream_id(i).id();
|
||||
mPorts[portIndex]->insertStream(streamId);
|
||||
// XXX: same name as input param, but shouldn't cause any problem
|
||||
PbRpcController *controller;
|
||||
quint32 portId = mPorts[portIndex]->id();
|
||||
QString myself = appSettings->value(kUserKey, kUserDefaultValue)
|
||||
.toString();
|
||||
|
||||
// delete all existing streams
|
||||
if (streamIdList->stream_id_size())
|
||||
{
|
||||
OstProto::StreamIdList *streamIdList2 = new OstProto::StreamIdList;
|
||||
streamIdList2->CopyFrom(*streamIdList);
|
||||
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(streamIdList2, ack);
|
||||
|
||||
serviceStub->deleteStream(controller, streamIdList2, ack,
|
||||
NewCallback(this, &PortGroup::processDeleteStreamAck,
|
||||
controller));
|
||||
}
|
||||
|
||||
OstProto::Port portCfg = newPortContent->port_config();
|
||||
if (mPorts[portIndex]->modifiablePortConfig(portCfg))
|
||||
{
|
||||
OstProto::PortConfigList *portConfigList =
|
||||
new OstProto::PortConfigList;
|
||||
OstProto::Port *port = portConfigList->add_port();
|
||||
port->CopyFrom(portCfg);
|
||||
if (port->has_user_name())
|
||||
port->set_user_name(qPrintable(myself)); // overwrite
|
||||
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(portConfigList, ack);
|
||||
|
||||
serviceStub->modifyPort(controller, portConfigList, ack,
|
||||
NewCallback(this, &PortGroup::processModifyPortAck,
|
||||
false, controller));
|
||||
}
|
||||
|
||||
// add/modify deviceGroups
|
||||
if (newPortContent->device_groups_size())
|
||||
{
|
||||
OstProto::DeviceGroupIdList *deviceGroupIdList
|
||||
= new OstProto::DeviceGroupIdList;
|
||||
OstProto::DeviceGroupConfigList *deviceGroupConfigList
|
||||
= new OstProto::DeviceGroupConfigList;
|
||||
deviceGroupIdList->mutable_port_id()->set_id(portId);
|
||||
deviceGroupConfigList->mutable_port_id()->set_id(portId);
|
||||
for (int i = 0; i < newPortContent->device_groups_size(); i++)
|
||||
{
|
||||
const OstProto::DeviceGroup &dg
|
||||
= newPortContent->device_groups(i);
|
||||
deviceGroupIdList->add_device_group_id()->set_id(
|
||||
dg.device_group_id().id());
|
||||
deviceGroupConfigList->add_device_group()->CopyFrom(dg);
|
||||
}
|
||||
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(deviceGroupIdList, ack);
|
||||
|
||||
serviceStub->addDeviceGroup(controller, deviceGroupIdList, ack,
|
||||
NewCallback(this, &PortGroup::processAddDeviceGroupAck,
|
||||
controller));
|
||||
|
||||
ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(deviceGroupConfigList, ack);
|
||||
|
||||
serviceStub->modifyDeviceGroup(controller,
|
||||
deviceGroupConfigList, ack,
|
||||
NewCallback(this, &PortGroup::processModifyDeviceGroupAck,
|
||||
portIndex, controller));
|
||||
}
|
||||
|
||||
// add/modify streams
|
||||
if (newPortContent->streams_size())
|
||||
{
|
||||
OstProto::StreamIdList *streamIdList = new OstProto::StreamIdList;
|
||||
OstProto::StreamConfigList *streamConfigList =
|
||||
new OstProto::StreamConfigList;
|
||||
streamIdList->mutable_port_id()->set_id(portId);
|
||||
streamConfigList->mutable_port_id()->set_id(portId);
|
||||
for (int i = 0; i < newPortContent->streams_size(); i++)
|
||||
{
|
||||
const OstProto::Stream &s = newPortContent->streams(i);
|
||||
streamIdList->add_stream_id()->set_id(s.stream_id().id());
|
||||
streamConfigList->add_stream()->CopyFrom(s);
|
||||
}
|
||||
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(streamIdList, ack);
|
||||
|
||||
serviceStub->addStream(controller, streamIdList, ack,
|
||||
NewCallback(this, &PortGroup::processAddStreamAck,
|
||||
controller));
|
||||
|
||||
ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(streamConfigList, ack);
|
||||
|
||||
serviceStub->modifyStream(controller, streamConfigList, ack,
|
||||
NewCallback(this, &PortGroup::processModifyStreamAck,
|
||||
portIndex, controller));
|
||||
}
|
||||
|
||||
// delete newPortConfig
|
||||
atConnectPortConfig_[portIndex] = NULL;
|
||||
|
||||
// return to normal sequence re-starting from
|
||||
// getDeviceGroupIdList() and getStreamIdList()
|
||||
OstProto::PortId *portId2 = new OstProto::PortId;
|
||||
portId2->set_id(portId);
|
||||
|
||||
OstProto::DeviceGroupIdList *devGrpIdList
|
||||
= new OstProto::DeviceGroupIdList;
|
||||
controller = new PbRpcController(portId2, devGrpIdList);
|
||||
|
||||
serviceStub->getDeviceGroupIdList(controller, portId2, devGrpIdList,
|
||||
NewCallback(this, &PortGroup::processDeviceGroupIdList,
|
||||
portIndex, controller));
|
||||
|
||||
portId2 = new OstProto::PortId;
|
||||
portId2->set_id(portId);
|
||||
OstProto::StreamIdList *streamIdList = new OstProto::StreamIdList;
|
||||
controller = new PbRpcController(portId2, streamIdList);
|
||||
|
||||
serviceStub->getStreamIdList(controller, portId2, streamIdList,
|
||||
NewCallback(this, &PortGroup::processStreamIdList,
|
||||
portIndex, controller));
|
||||
}
|
||||
|
||||
// Are we done for all ports?
|
||||
if (numPorts() && portIndex >= (numPorts()-1))
|
||||
else
|
||||
{
|
||||
// FIXME(HI): some way to reset streammodel
|
||||
getStreamConfigList();
|
||||
for(int i = 0; i < streamIdList->stream_id_size(); i++)
|
||||
{
|
||||
uint streamId;
|
||||
|
||||
streamId = streamIdList->stream_id(i).id();
|
||||
mPorts[portIndex]->insertStream(streamId);
|
||||
}
|
||||
|
||||
mPorts[portIndex]->when_syncComplete();
|
||||
|
||||
getStreamConfigList(portIndex);
|
||||
}
|
||||
|
||||
_exit:
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::getStreamConfigList()
|
||||
void PortGroup::getStreamConfigList(int portIndex)
|
||||
{
|
||||
qDebug("requesting stream config list ...");
|
||||
if (mPorts[portIndex]->numStreams() == 0)
|
||||
return;
|
||||
|
||||
for (int portIndex = 0; portIndex < numPorts(); portIndex++)
|
||||
qDebug("requesting stream config list (port %d)...", portIndex);
|
||||
|
||||
OstProto::StreamIdList *streamIdList = new OstProto::StreamIdList;
|
||||
OstProto::StreamConfigList *streamConfigList
|
||||
= new OstProto::StreamConfigList;
|
||||
PbRpcController *controller = new PbRpcController(
|
||||
streamIdList, streamConfigList);
|
||||
|
||||
streamIdList->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
for (int j = 0; j < mPorts[portIndex]->numStreams(); j++)
|
||||
{
|
||||
if (mPorts[portIndex]->numStreams() == 0)
|
||||
continue;
|
||||
|
||||
OstProto::StreamIdList *streamIdList = new OstProto::StreamIdList;
|
||||
OstProto::StreamConfigList *streamConfigList
|
||||
= new OstProto::StreamConfigList;
|
||||
PbRpcController *controller = new PbRpcController(
|
||||
streamIdList, streamConfigList);
|
||||
|
||||
streamIdList->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
for (int j = 0; j < mPorts[portIndex]->numStreams(); j++)
|
||||
{
|
||||
OstProto::StreamId *s = streamIdList->add_stream_id();
|
||||
s->set_id(mPorts[portIndex]->streamByIndex(j)->id());
|
||||
}
|
||||
|
||||
serviceStub->getStreamConfig(controller, streamIdList, streamConfigList,
|
||||
NewCallback(this, &PortGroup::processStreamConfigList,
|
||||
portIndex, controller));
|
||||
OstProto::StreamId *s = streamIdList->add_stream_id();
|
||||
s->set_id(mPorts[portIndex]->streamByIndex(j)->id());
|
||||
}
|
||||
|
||||
serviceStub->getStreamConfig(controller, streamIdList, streamConfigList,
|
||||
NewCallback(this, &PortGroup::processStreamConfigList,
|
||||
portIndex, controller));
|
||||
}
|
||||
|
||||
void PortGroup::processStreamConfigList(int portIndex,
|
||||
@ -866,6 +1089,8 @@ void PortGroup::processDeviceGroupIdList(
|
||||
|
||||
DeviceGroupIdList *devGrpIdList = static_cast<DeviceGroupIdList*>(
|
||||
controller->response());
|
||||
const OstProto::PortContent *newPortContent = atConnectPortConfig_.at(
|
||||
portIndex);
|
||||
|
||||
qDebug("In %s (portIndex = %d)", __FUNCTION__, portIndex);
|
||||
|
||||
@ -885,55 +1110,70 @@ void PortGroup::processDeviceGroupIdList(
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
for(int i = 0; i < devGrpIdList->device_group_id_size(); i++)
|
||||
if (newPortContent)
|
||||
{
|
||||
uint devGrpId;
|
||||
// We delete all existing deviceGroups
|
||||
// Remaining stuff is done in processStreamIdList() - see notes there
|
||||
if (devGrpIdList->device_group_id_size())
|
||||
{
|
||||
OstProto::DeviceGroupIdList *devGrpIdList2
|
||||
= new OstProto::DeviceGroupIdList;
|
||||
devGrpIdList2->CopyFrom(*devGrpIdList);
|
||||
|
||||
devGrpId = devGrpIdList->device_group_id(i).id();
|
||||
mPorts[portIndex]->insertDeviceGroup(devGrpId);
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
PbRpcController *controller
|
||||
= new PbRpcController(devGrpIdList2, ack);
|
||||
|
||||
serviceStub->deleteDeviceGroup(controller, devGrpIdList2, ack,
|
||||
NewCallback(this, &PortGroup::processDeleteDeviceGroupAck,
|
||||
controller));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < devGrpIdList->device_group_id_size(); i++)
|
||||
{
|
||||
uint devGrpId;
|
||||
|
||||
mPorts[portIndex]->when_syncComplete();
|
||||
devGrpId = devGrpIdList->device_group_id(i).id();
|
||||
mPorts[portIndex]->insertDeviceGroup(devGrpId);
|
||||
}
|
||||
|
||||
// Are we done for all ports?
|
||||
if (numPorts() && portIndex >= (numPorts()-1))
|
||||
getDeviceGroupConfigList();
|
||||
getDeviceGroupConfigList(portIndex);
|
||||
}
|
||||
|
||||
_exit:
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::getDeviceGroupConfigList()
|
||||
void PortGroup::getDeviceGroupConfigList(int portIndex)
|
||||
{
|
||||
using OstProto::DeviceGroupId;
|
||||
using OstProto::DeviceGroupIdList;
|
||||
using OstProto::DeviceGroupConfigList;
|
||||
|
||||
qDebug("requesting device group config list ...");
|
||||
if (mPorts[portIndex]->numDeviceGroups() == 0)
|
||||
return;
|
||||
|
||||
for (int portIndex = 0; portIndex < numPorts(); portIndex++)
|
||||
qDebug("requesting device group config list (port %d) ...", portIndex);
|
||||
|
||||
DeviceGroupIdList *devGrpIdList = new DeviceGroupIdList;
|
||||
DeviceGroupConfigList *devGrpCfgList = new DeviceGroupConfigList;
|
||||
PbRpcController *controller = new PbRpcController(
|
||||
devGrpIdList, devGrpCfgList);
|
||||
|
||||
devGrpIdList->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
for (int j = 0; j < mPorts[portIndex]->numDeviceGroups(); j++)
|
||||
{
|
||||
if (mPorts[portIndex]->numDeviceGroups() == 0)
|
||||
continue;
|
||||
|
||||
DeviceGroupIdList *devGrpIdList = new DeviceGroupIdList;
|
||||
DeviceGroupConfigList *devGrpCfgList = new DeviceGroupConfigList;
|
||||
PbRpcController *controller = new PbRpcController(
|
||||
devGrpIdList, devGrpCfgList);
|
||||
|
||||
devGrpIdList->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
for (int j = 0; j < mPorts[portIndex]->numDeviceGroups(); j++)
|
||||
{
|
||||
DeviceGroupId *dgid = devGrpIdList->add_device_group_id();
|
||||
dgid->set_id(mPorts[portIndex]->deviceGroupByIndex(j)
|
||||
->device_group_id().id());
|
||||
}
|
||||
|
||||
serviceStub->getDeviceGroupConfig(controller,
|
||||
devGrpIdList, devGrpCfgList,
|
||||
NewCallback(this, &PortGroup::processDeviceGroupConfigList,
|
||||
portIndex, controller));
|
||||
DeviceGroupId *dgid = devGrpIdList->add_device_group_id();
|
||||
dgid->set_id(mPorts[portIndex]->deviceGroupByIndex(j)
|
||||
->device_group_id().id());
|
||||
}
|
||||
|
||||
serviceStub->getDeviceGroupConfig(controller,
|
||||
devGrpIdList, devGrpCfgList,
|
||||
NewCallback(this, &PortGroup::processDeviceGroupConfigList,
|
||||
portIndex, controller));
|
||||
}
|
||||
|
||||
void PortGroup::processDeviceGroupConfigList(int portIndex,
|
||||
|
@ -36,6 +36,11 @@ LOW
|
||||
|
||||
#define DEFAULT_SERVER_PORT 7878
|
||||
|
||||
namespace OstProto {
|
||||
class PortContent;
|
||||
class PortGroupContent;
|
||||
}
|
||||
|
||||
class QFile;
|
||||
class QTimer;
|
||||
|
||||
@ -62,6 +67,9 @@ private:
|
||||
OstProto::PortIdList *portIdList_;
|
||||
OstProto::PortStatsList *portStatsList_;
|
||||
|
||||
OstProto::PortGroupContent *atConnectConfig_;
|
||||
QList<const OstProto::PortContent*> atConnectPortConfig_;
|
||||
|
||||
public: // FIXME(HIGH): member access
|
||||
QList<Port*> mPorts;
|
||||
|
||||
@ -82,7 +90,10 @@ public:
|
||||
}
|
||||
void disconnectFromHost() { reconnect = false; rpcChannel->tearDown(); }
|
||||
|
||||
void setConfigAtConnect(const OstProto::PortGroupContent *config);
|
||||
|
||||
int numPorts() const { return mPorts.size(); }
|
||||
int numReservedPorts() const;
|
||||
quint32 id() const { return mPortGroupId; }
|
||||
|
||||
const QString& userAlias() const { return mUserAlias; }
|
||||
@ -92,6 +103,7 @@ public:
|
||||
{ return rpcChannel->serverName(); }
|
||||
quint16 serverPort() const
|
||||
{ return rpcChannel->serverPort(); }
|
||||
const QString serverFullName() const;
|
||||
QAbstractSocket::SocketState state() const {
|
||||
if (compat == kIncompatible)
|
||||
return QAbstractSocket::SocketState(-1);
|
||||
@ -114,19 +126,19 @@ public:
|
||||
void processDeviceNeighbors(int portIndex, PbRpcController *controller);
|
||||
|
||||
void modifyPort(int portId, OstProto::Port portConfig);
|
||||
void processModifyPortAck(PbRpcController *controller);
|
||||
void processModifyPortAck(bool restoreUi, PbRpcController *controller);
|
||||
void processUpdatedPortConfig(PbRpcController *controller);
|
||||
|
||||
void getStreamIdList();
|
||||
void processStreamIdList(int portIndex, PbRpcController *controller);
|
||||
void getStreamConfigList();
|
||||
void getStreamConfigList(int portIndex);
|
||||
void processStreamConfigList(int portIndex, PbRpcController *controller);
|
||||
|
||||
void processModifyStreamAck(OstProto::Ack *ack);
|
||||
|
||||
void getDeviceGroupIdList();
|
||||
void processDeviceGroupIdList(int portIndex, PbRpcController *controller);
|
||||
void getDeviceGroupConfigList();
|
||||
void getDeviceGroupConfigList(int portIndex);
|
||||
void processDeviceGroupConfigList(
|
||||
int portIndex,
|
||||
PbRpcController *controller);
|
||||
|
@ -126,6 +126,23 @@ void PortGroupList::removePortGroup(PortGroup &portGroup)
|
||||
mPortStatsModel.when_portListChanged();
|
||||
}
|
||||
|
||||
void PortGroupList::removeAllPortGroups()
|
||||
{
|
||||
if (mPortGroups.isEmpty())
|
||||
return;
|
||||
|
||||
do {
|
||||
PortGroup *pg = mPortGroups.at(0);
|
||||
mPortGroupListModel.portGroupAboutToBeRemoved(pg);
|
||||
mPortGroups.removeFirst();
|
||||
delete pg;
|
||||
} while (!mPortGroups.isEmpty());
|
||||
mPortGroupListModel.portGroupRemoved();
|
||||
|
||||
mPortGroupListModel.when_portListChanged();
|
||||
mPortStatsModel.when_portListChanged();
|
||||
}
|
||||
|
||||
//....................
|
||||
// Private Methods
|
||||
//....................
|
||||
|
@ -72,6 +72,7 @@ public:
|
||||
|
||||
void addPortGroup(PortGroup &portGroup);
|
||||
void removePortGroup(PortGroup &portGroup);
|
||||
void removeAllPortGroups();
|
||||
|
||||
private:
|
||||
int indexOfPortGroup(quint32 portGroupId);
|
||||
|
@ -179,7 +179,7 @@ QVariant PortModel::data(const QModelIndex &index, int role) const
|
||||
|
||||
return QString("Port %1: %2 %3(%4)")
|
||||
.arg(port->id())
|
||||
.arg(port->name())
|
||||
.arg(port->userAlias())
|
||||
.arg(rsvdBy)
|
||||
.arg(port->description());
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ private:
|
||||
QIcon portIconFactory[kLinkStatesCount][kExclusiveStatesCount];
|
||||
|
||||
private slots:
|
||||
// FIXME: these are invoked from outside - how come they are "private"?
|
||||
void when_portGroupDataChanged(int portGroupId, int portId);
|
||||
|
||||
void portGroupAboutToBeAppended();
|
||||
|
@ -19,19 +19,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#include "portswindow.h"
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
#include "deviceswidget.h"
|
||||
#include "portconfigdialog.h"
|
||||
#include "settings.h"
|
||||
#include "streamconfigdialog.h"
|
||||
#include "streamfileformat.h"
|
||||
#include "streamlistdelegate.h"
|
||||
|
||||
#include "fileformat.pb.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QInputDialog>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
extern QMainWindow *mainWindow;
|
||||
|
||||
PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
|
||||
: QWidget(parent), proxyPortModel(NULL)
|
||||
{
|
||||
@ -168,6 +173,116 @@ PortsWindow::~PortsWindow()
|
||||
delete proxyPortModel;
|
||||
}
|
||||
|
||||
int PortsWindow::portGroupCount()
|
||||
{
|
||||
return plm->numPortGroups();
|
||||
}
|
||||
|
||||
int PortsWindow::reservedPortCount()
|
||||
{
|
||||
int count = 0;
|
||||
int n = portGroupCount();
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
count += plm->portGroupByIndex(i).numReservedPorts();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//! Always return true
|
||||
bool PortsWindow::openSession(
|
||||
const OstProto::SessionContent *session,
|
||||
QString &error)
|
||||
{
|
||||
QProgressDialog progress("Opening Session", NULL,
|
||||
0, session->port_groups_size(), mainWindow);
|
||||
progress.show();
|
||||
progress.setEnabled(true); // since parent (mainWindow) is disabled
|
||||
|
||||
plm->removeAllPortGroups();
|
||||
|
||||
for (int i = 0; i < session->port_groups_size(); i++) {
|
||||
const OstProto::PortGroupContent &pgc = session->port_groups(i);
|
||||
PortGroup *pg = new PortGroup(QString::fromStdString(
|
||||
pgc.server_name()),
|
||||
quint16(pgc.server_port()));
|
||||
pg->setConfigAtConnect(&pgc);
|
||||
plm->addPortGroup(*pg);
|
||||
progress.setValue(i+1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Prepare content to be saved for a session
|
||||
*
|
||||
* If port reservation is in use, saves only 'my' reserved ports
|
||||
*
|
||||
* Returns false, if user cancels op; true, otherwise
|
||||
*/
|
||||
bool PortsWindow::saveSession(
|
||||
OstProto::SessionContent *session, // OUT param
|
||||
QString &error,
|
||||
QProgressDialog *progress)
|
||||
{
|
||||
int n = portGroupCount();
|
||||
QString myself;
|
||||
|
||||
if (progress) {
|
||||
progress->setLabelText("Preparing Ports and PortGroups ...");
|
||||
progress->setRange(0, n);
|
||||
}
|
||||
|
||||
if (reservedPortCount())
|
||||
myself = appSettings->value(kUserKey, kUserDefaultValue).toString();
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
PortGroup &pg = plm->portGroupByIndex(i);
|
||||
OstProto::PortGroupContent *pgc = session->add_port_groups();
|
||||
|
||||
pgc->set_server_name(pg.serverName().toStdString());
|
||||
pgc->set_server_port(pg.serverPort());
|
||||
|
||||
for (int j = 0; j < pg.numPorts(); j++)
|
||||
{
|
||||
if (myself != pg.mPorts.at(j)->userName())
|
||||
continue;
|
||||
|
||||
OstProto::PortContent *pc = pgc->add_ports();
|
||||
OstProto::Port *p = pc->mutable_port_config();
|
||||
|
||||
// XXX: We save the entire OstProto::Port even though some
|
||||
// fields may be ephemeral; while opening we use only relevant
|
||||
// fields
|
||||
pg.mPorts.at(j)->protoDataCopyInto(p);
|
||||
|
||||
for (int k = 0; k < pg.mPorts.at(j)->numStreams(); k++)
|
||||
{
|
||||
OstProto::Stream *s = pc->add_streams();
|
||||
pg.mPorts.at(j)->streamByIndex(k)->protoDataCopyInto(*s);
|
||||
}
|
||||
|
||||
for (int k = 0; k < pg.mPorts.at(j)->numDeviceGroups(); k++)
|
||||
{
|
||||
OstProto::DeviceGroup *dg = pc->add_device_groups();
|
||||
dg->CopyFrom(*(pg.mPorts.at(j)->deviceGroupByIndex(k)));
|
||||
}
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
if (progress->wasCanceled())
|
||||
return false;
|
||||
progress->setValue(i);
|
||||
}
|
||||
if (i % 2 == 0)
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PortsWindow::showMyReservedPortsOnly(bool enabled)
|
||||
{
|
||||
if (!proxyPortModel)
|
||||
@ -697,6 +812,9 @@ void PortsWindow::on_actionOpen_Streams_triggered()
|
||||
{
|
||||
qDebug("Open Streams Action");
|
||||
|
||||
QStringList fileTypes = StreamFileFormat::supportedFileTypes(
|
||||
StreamFileFormat::kOpenFile);
|
||||
QString fileType;
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
static QString dirName;
|
||||
QString fileName;
|
||||
@ -709,7 +827,11 @@ void PortsWindow::on_actionOpen_Streams_triggered()
|
||||
|
||||
Q_ASSERT(plm->isPort(current));
|
||||
|
||||
fileName = QFileDialog::getOpenFileName(this, tr("Open Streams"), dirName);
|
||||
if (fileTypes.size())
|
||||
fileType = fileTypes.at(0);
|
||||
|
||||
fileName = QFileDialog::getOpenFileName(this, tr("Open Streams"),
|
||||
dirName, fileTypes.join(";;"), &fileType);
|
||||
if (fileName.isEmpty())
|
||||
goto _exit;
|
||||
|
||||
@ -763,7 +885,8 @@ void PortsWindow::on_actionSave_Streams_triggered()
|
||||
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
static QString fileName;
|
||||
QStringList fileTypes = AbstractFileFormat::supportedFileTypes();
|
||||
QStringList fileTypes = StreamFileFormat::supportedFileTypes(
|
||||
StreamFileFormat::kSaveFile);
|
||||
QString fileType;
|
||||
QString errorStr;
|
||||
QFileDialog::Options options;
|
||||
|
@ -26,8 +26,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#include "portgrouplist.h"
|
||||
|
||||
class QAbstractItemDelegate;
|
||||
class QProgressDialog;
|
||||
class QSortFilterProxyModel;
|
||||
|
||||
namespace OstProto {
|
||||
class SessionContent;
|
||||
}
|
||||
|
||||
class PortsWindow : public QWidget, private Ui::PortsWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -39,6 +44,15 @@ public:
|
||||
PortsWindow(PortGroupList *pgl, QWidget *parent = 0);
|
||||
~PortsWindow();
|
||||
|
||||
int portGroupCount();
|
||||
int reservedPortCount();
|
||||
|
||||
bool openSession(const OstProto::SessionContent *session,
|
||||
QString &error);
|
||||
bool saveSession(OstProto::SessionContent *session,
|
||||
QString &error,
|
||||
QProgressDialog *progress = NULL);
|
||||
|
||||
signals:
|
||||
void currentPortChanged(const QModelIndex ¤t,
|
||||
const QModelIndex &previous);
|
||||
|
@ -24,6 +24,7 @@ package OstProto;
|
||||
enum FileType {
|
||||
kReservedFileType = 0;
|
||||
kStreamsFileType = 1;
|
||||
kSessionFileType = 10;
|
||||
}
|
||||
|
||||
message FileMetaData {
|
||||
@ -36,8 +37,30 @@ message FileMetaData {
|
||||
required string generator_revision = 7;
|
||||
}
|
||||
|
||||
message PortContent {
|
||||
optional Port port_config = 1;
|
||||
repeated Stream streams = 2;
|
||||
repeated DeviceGroup device_groups = 3;
|
||||
}
|
||||
|
||||
message PortGroupContent {
|
||||
optional string server_name = 1;
|
||||
optional uint32 server_port = 2;
|
||||
|
||||
repeated PortContent ports = 15;
|
||||
}
|
||||
|
||||
message SessionContent {
|
||||
repeated PortGroupContent port_groups = 1;
|
||||
}
|
||||
|
||||
message FileContentMatter {
|
||||
optional StreamConfigList streams = 1;
|
||||
// TODO: optional DeviceGroupConfigList device_groups = 2;
|
||||
// TODO: optional PortContent port = 3;
|
||||
// FIXME: (single) portgroup? is there a usecase for this?
|
||||
|
||||
optional SessionContent session = 10;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
Copyright (C) 2010, 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "fileformat.h"
|
||||
#include "nativefileformat.h"
|
||||
|
||||
#include "crc32c.h"
|
||||
|
||||
@ -25,15 +25,29 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#include <QFile>
|
||||
#include <QVariant>
|
||||
|
||||
#include <string>
|
||||
#define tr(str) QObject::tr(str)
|
||||
|
||||
const std::string FileFormat::kFileMagicValue = "\xa7\xb7OSTINATO";
|
||||
const std::string NativeFileFormat::kFileMagicValue = "\xa7\xb7OSTINATO";
|
||||
|
||||
FileFormat fileFormat;
|
||||
static const int kBaseHex = 16;
|
||||
|
||||
const int kBaseHex = 16;
|
||||
static QString fileTypeStr(OstProto::FileType fileType)
|
||||
{
|
||||
switch (fileType) {
|
||||
case OstProto::kReservedFileType:
|
||||
return QString("Reserved");
|
||||
case OstProto::kStreamsFileType:
|
||||
return QString("Streams");
|
||||
case OstProto::kSessionFileType:
|
||||
return QString("Streams");
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
FileFormat::FileFormat()
|
||||
return QString("Unknown");
|
||||
}
|
||||
|
||||
NativeFileFormat::NativeFileFormat()
|
||||
{
|
||||
/*
|
||||
* We don't have any "real" work to do here in the constructor.
|
||||
@ -54,20 +68,18 @@ FileFormat::FileFormat()
|
||||
Q_ASSERT(cksum.ByteSize() == kFileChecksumSize);
|
||||
}
|
||||
|
||||
FileFormat::~FileFormat()
|
||||
{
|
||||
}
|
||||
|
||||
bool FileFormat::openStreams(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error)
|
||||
bool NativeFileFormat::open(
|
||||
const QString fileName,
|
||||
OstProto::FileType fileType,
|
||||
OstProto::FileMeta &meta,
|
||||
OstProto::FileContent &content,
|
||||
QString &error)
|
||||
{
|
||||
QFile file(fileName);
|
||||
QByteArray buf;
|
||||
int size, contentOffset, contentSize;
|
||||
quint32 calcCksum;
|
||||
OstProto::FileMagic magic;
|
||||
OstProto::FileMeta meta;
|
||||
OstProto::FileContent content;
|
||||
OstProto::FileChecksum cksum, zeroCksum;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
@ -95,7 +107,7 @@ bool FileFormat::openStreams(const QString fileName,
|
||||
|
||||
// Parse and verify magic
|
||||
if (!magic.ParseFromArray(
|
||||
(void*)(buf.constData() + kFileMagicOffset),
|
||||
(void*)(buf.constData() + kFileMagicOffset),
|
||||
kFileMagicSize))
|
||||
{
|
||||
goto _magic_parse_fail;
|
||||
@ -105,7 +117,7 @@ bool FileFormat::openStreams(const QString fileName,
|
||||
|
||||
// Parse and verify checksum
|
||||
if (!cksum.ParseFromArray(
|
||||
(void*)(buf.constData() + size - kFileChecksumSize),
|
||||
(void*)(buf.constData() + size - kFileChecksumSize),
|
||||
kFileChecksumSize))
|
||||
{
|
||||
goto _cksum_parse_fail;
|
||||
@ -118,7 +130,7 @@ bool FileFormat::openStreams(const QString fileName,
|
||||
{
|
||||
goto _zero_cksum_serialize_fail;
|
||||
}
|
||||
|
||||
|
||||
calcCksum = checksumCrc32C((quint8*) buf.constData(), size);
|
||||
|
||||
qDebug("checksum \nExpected:%x Actual:%x",
|
||||
@ -129,17 +141,18 @@ bool FileFormat::openStreams(const QString fileName,
|
||||
|
||||
// Parse the metadata first before we parse the full contents
|
||||
if (!meta.ParseFromArray(
|
||||
(void*)(buf.constData() + kFileMetaDataOffset),
|
||||
size - kFileMetaDataOffset))
|
||||
(void*)(buf.constData() + kFileMetaDataOffset),
|
||||
fileMetaSize((quint8*)buf.constData(), size)))
|
||||
{
|
||||
goto _metadata_parse_fail;
|
||||
}
|
||||
|
||||
qDebug("%s: File MetaData (INFORMATION) - \n%s", __FUNCTION__,
|
||||
qDebug("%s: File MetaData (INFORMATION) - \n%s", __FUNCTION__,
|
||||
QString().fromStdString(meta.DebugString()).toAscii().constData());
|
||||
qDebug("%s: END MetaData", __FUNCTION__);
|
||||
|
||||
// MetaData Validation(s)
|
||||
if (meta.data().file_type() != OstProto::kStreamsFileType)
|
||||
if (meta.data().file_type() != fileType)
|
||||
goto _unexpected_file_type;
|
||||
|
||||
if (meta.data().format_version_major() != kFileFormatVersionMajor)
|
||||
@ -165,34 +178,26 @@ bool FileFormat::openStreams(const QString fileName,
|
||||
// ByteSize() does not include the Tag/Key, so we add 2 for that
|
||||
contentOffset = kFileMetaDataOffset + meta.data().ByteSize() + 2;
|
||||
contentSize = size - contentOffset - kFileChecksumSize;
|
||||
qDebug("%s: content offset/size = %d/%d", __FUNCTION__,
|
||||
contentOffset, contentSize);
|
||||
|
||||
// Parse full contents
|
||||
if (!content.ParseFromArray(
|
||||
(void*)(buf.constData() + contentOffset),
|
||||
(void*)(buf.constData() + contentOffset),
|
||||
contentSize))
|
||||
{
|
||||
goto _content_parse_fail;
|
||||
}
|
||||
|
||||
if (!content.matter().has_streams())
|
||||
goto _missing_streams;
|
||||
|
||||
postParseFixup(meta.data(), content);
|
||||
|
||||
streams.CopyFrom(content.matter().streams());
|
||||
|
||||
return true;
|
||||
|
||||
_missing_streams:
|
||||
error = QString(tr("%1 does not contain any streams")).arg(fileName);
|
||||
goto _fail;
|
||||
_content_parse_fail:
|
||||
error = QString(tr("Failed parsing %1 contents")).arg(fileName);
|
||||
qDebug("Error: %s", QString().fromStdString(
|
||||
content.matter().InitializationErrorString())
|
||||
content.InitializationErrorString())
|
||||
.toAscii().constData());
|
||||
qDebug("Debug: %s", QString().fromStdString(
|
||||
content.matter().DebugString()).toAscii().constData());
|
||||
content.DebugString()).toAscii().constData());
|
||||
goto _fail;
|
||||
_incompatible_file_version:
|
||||
error = QString(tr("%1 is in an incompatible format version - %2.%3.%4"
|
||||
@ -206,7 +211,9 @@ _incompatible_file_version:
|
||||
.arg(kFileFormatVersionRevision);
|
||||
goto _fail;
|
||||
_unexpected_file_type:
|
||||
error = QString(tr("%1 is not a streams file")).arg(fileName);
|
||||
error = QString(tr("%1 is not a %2 file"))
|
||||
.arg(fileName)
|
||||
.arg(fileTypeStr(fileType));
|
||||
goto _fail;
|
||||
_metadata_parse_fail:
|
||||
error = QString(tr("Failed parsing %1 meta data")).arg(fileName);
|
||||
@ -260,12 +267,14 @@ _fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error)
|
||||
bool NativeFileFormat::save(
|
||||
OstProto::FileType fileType,
|
||||
const OstProto::FileContent &content,
|
||||
const QString fileName,
|
||||
QString &error)
|
||||
{
|
||||
OstProto::FileMagic magic;
|
||||
OstProto::FileMeta meta;
|
||||
OstProto::FileContent content;
|
||||
OstProto::FileChecksum cksum;
|
||||
QFile file(fileName);
|
||||
int metaSize, contentSize;
|
||||
@ -280,13 +289,12 @@ bool FileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
Q_ASSERT(cksum.IsInitialized());
|
||||
|
||||
initFileMetaData(*(meta.mutable_data()));
|
||||
meta.mutable_data()->set_file_type(OstProto::kStreamsFileType);
|
||||
meta.mutable_data()->set_file_type(fileType);
|
||||
Q_ASSERT(meta.IsInitialized());
|
||||
|
||||
if (!streams.IsInitialized())
|
||||
goto _stream_not_init;
|
||||
if (!content.IsInitialized())
|
||||
goto _content_not_init;
|
||||
|
||||
content.mutable_matter()->mutable_streams()->CopyFrom(streams);
|
||||
Q_ASSERT(content.IsInitialized());
|
||||
|
||||
metaSize = meta.ByteSize();
|
||||
@ -323,7 +331,7 @@ bool FileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
goto _zero_cksum_serialize_fail;
|
||||
}
|
||||
|
||||
emit status("Calculating checksum...");
|
||||
// TODO: emit status("Calculating checksum...");
|
||||
|
||||
// Calculate and write checksum
|
||||
calcCksum = checksumCrc32C((quint8*)buf.constData(), buf.size());
|
||||
@ -338,7 +346,7 @@ bool FileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
qDebug("Writing %d bytes", buf.size());
|
||||
//qDebug("%s", QString(buf.toHex()).toAscii().constData());
|
||||
|
||||
emit status("Writing to disk...");
|
||||
// TODO: emit status("Writing to disk...");
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
goto _open_fail;
|
||||
|
||||
@ -346,7 +354,7 @@ bool FileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
goto _write_fail;
|
||||
|
||||
file.close();
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
_write_fail:
|
||||
@ -387,18 +395,20 @@ _magic_serialize_fail:
|
||||
magic.InitializationErrorString()))
|
||||
.arg(QString().fromStdString(magic.DebugString()));
|
||||
goto _fail;
|
||||
_stream_not_init:
|
||||
error = QString(tr("Internal Error: Streams not initialized\n%1\n%2"))
|
||||
_content_not_init:
|
||||
error = QString(tr("Internal Error: Content not initialized\n%1\n%2"))
|
||||
.arg(QString().fromStdString(
|
||||
streams.InitializationErrorString()))
|
||||
.arg(QString().fromStdString(streams.DebugString()));
|
||||
content.InitializationErrorString()))
|
||||
.arg(QString().fromStdString(content.DebugString()));
|
||||
goto _fail;
|
||||
_fail:
|
||||
qDebug("%s", error.toAscii().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileFormat::isMyFileFormat(const QString fileName)
|
||||
bool NativeFileFormat::isNativeFileFormat(
|
||||
const QString fileName,
|
||||
OstProto::FileType fileType)
|
||||
{
|
||||
bool ret = false;
|
||||
QFile file(fileName);
|
||||
@ -408,13 +418,25 @@ bool FileFormat::isMyFileFormat(const QString fileName)
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
goto _exit;
|
||||
|
||||
buf = file.peek(kFileMagicOffset + kFileMagicSize);
|
||||
if (!magic.ParseFromArray((void*)(buf.constData() + kFileMagicOffset),
|
||||
// Assume tag/length for MetaData will fit in 8 bytes
|
||||
buf = file.peek(kFileMagicOffset + kFileMagicSize + 8);
|
||||
if (!magic.ParseFromArray((void*)(buf.constData() + kFileMagicOffset),
|
||||
kFileMagicSize))
|
||||
goto _close_exit;
|
||||
|
||||
if (magic.value() == kFileMagicValue)
|
||||
ret = true;
|
||||
if (magic.value() == kFileMagicValue) {
|
||||
OstProto::FileMeta meta;
|
||||
int metaSize = fileMetaSize((quint8*)buf.constData(), buf.size());
|
||||
buf = file.peek(kFileMagicOffset + kFileMagicSize + metaSize);
|
||||
if (!meta.ParseFromArray(
|
||||
(void*)(buf.constData() + kFileMetaDataOffset), metaSize)) {
|
||||
qDebug("%s: File MetaData\n%s", __FUNCTION__,
|
||||
QString().fromStdString(meta.DebugString()).toAscii().constData());
|
||||
goto _close_exit;
|
||||
}
|
||||
if (meta.data().file_type() == fileType)
|
||||
ret = true;
|
||||
}
|
||||
|
||||
_close_exit:
|
||||
file.close();
|
||||
@ -422,15 +444,7 @@ _exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool FileFormat::isMyFileType(const QString fileType)
|
||||
{
|
||||
if (fileType.startsWith("Ostinato"))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileFormat::initFileMetaData(OstProto::FileMetaData &metaData)
|
||||
void NativeFileFormat::initFileMetaData(OstProto::FileMetaData &metaData)
|
||||
{
|
||||
// Fill in the "native" file format version
|
||||
metaData.set_format_version_major(kFileFormatVersionMajor);
|
||||
@ -445,9 +459,53 @@ void FileFormat::initFileMetaData(OstProto::FileMetaData &metaData)
|
||||
qApp->property("revision").toString().toUtf8().constData());
|
||||
}
|
||||
|
||||
int NativeFileFormat::fileMetaSize(const quint8* file, int size)
|
||||
{
|
||||
int i = kFileMetaDataOffset;
|
||||
uint result, shift;
|
||||
const int kWireTypeLengthDelimited = 2;
|
||||
|
||||
// An embedded Message field is encoded as
|
||||
// <Key> <Length> <Serialized-Value>
|
||||
// See Protobuf Encoding for more details
|
||||
|
||||
// Decode 'Key' varint
|
||||
result = 0;
|
||||
shift = 0;
|
||||
while (i < size) {
|
||||
quint8 byte = file[i++];
|
||||
result |= (byte & 0x7f) << shift;
|
||||
if (!(byte & 0x80)) // MSB == 0?
|
||||
break;
|
||||
shift += 7;
|
||||
}
|
||||
|
||||
if (i >= size)
|
||||
return 0;
|
||||
|
||||
Q_ASSERT(result == ((OstProto::File::kMetaDataFieldNumber << 3)
|
||||
| kWireTypeLengthDelimited));
|
||||
|
||||
// Decode 'Length' varint
|
||||
result = 0;
|
||||
shift = 0;
|
||||
while (i < size) {
|
||||
quint8 byte = file[i++];
|
||||
result |= (byte & 0x7f) << shift;
|
||||
if (!(byte & 0x80)) // MSB == 0?
|
||||
break;
|
||||
shift += 7;
|
||||
}
|
||||
|
||||
if (i >= size)
|
||||
return 0;
|
||||
|
||||
return int(result+(i-kFileMetaDataOffset));
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
/*! Fixup content to what is expected in the native version */
|
||||
void FileFormat::postParseFixup(OstProto::FileMetaData metaData,
|
||||
void NativeFileFormat::postParseFixup(OstProto::FileMetaData metaData,
|
||||
OstProto::FileContent &content)
|
||||
{
|
||||
Q_ASSERT(metaData.format_version_major() == kFileFormatVersionMajor);
|
||||
@ -460,7 +518,7 @@ void FileFormat::postParseFixup(OstProto::FileMetaData metaData,
|
||||
int n = content.matter().streams().stream_size();
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
OstProto::StreamControl *sctl =
|
||||
OstProto::StreamControl *sctl =
|
||||
content.mutable_matter()->mutable_streams()->mutable_stream(i)->mutable_control();
|
||||
sctl->set_packets_per_sec(sctl->obsolete_packets_per_sec());
|
||||
sctl->set_bursts_per_sec(sctl->obsolete_bursts_per_sec());
|
||||
@ -473,7 +531,7 @@ void FileFormat::postParseFixup(OstProto::FileMetaData metaData,
|
||||
|
||||
case 0:
|
||||
default:
|
||||
qWarning("%s: minor version %u unhandled", __FUNCTION__,
|
||||
qWarning("%s: minor version %u unhandled", __FUNCTION__,
|
||||
metaData.format_version_minor());
|
||||
Q_ASSERT_X(false, "postParseFixup", "unhandled minor version");
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
Copyright (C) 2010, 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
@ -16,31 +16,48 @@ GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
#ifndef _FILE_FORMAT_H
|
||||
#define _FILE_FORMAT_H
|
||||
#ifndef _NATIVE_FILE_FORMAT_H
|
||||
#define _NATIVE_FILE_FORMAT_H
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
/*
|
||||
* This file contains helper functions for the native file format
|
||||
* defined in fileformat.proto
|
||||
*
|
||||
* The actual file format classes - (Ostm)FileFormat and OssnFileFormat
|
||||
* use multiple inheritance from the abstract interface class and this
|
||||
* helper class
|
||||
*
|
||||
* The primary reason for the existence of this class is to have a common
|
||||
* code for dealing with native file formats
|
||||
*/
|
||||
|
||||
#include "fileformat.pb.h"
|
||||
|
||||
class FileFormat : public AbstractFileFormat
|
||||
#include <QString>
|
||||
|
||||
class NativeFileFormat
|
||||
{
|
||||
public:
|
||||
FileFormat();
|
||||
~FileFormat();
|
||||
NativeFileFormat();
|
||||
|
||||
virtual bool openStreams(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error);
|
||||
virtual bool saveStreams(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error);
|
||||
bool open(const QString fileName,
|
||||
OstProto::FileType fileType,
|
||||
OstProto::FileMeta &meta,
|
||||
OstProto::FileContent &content,
|
||||
QString &error);
|
||||
bool save(OstProto::FileType fileType,
|
||||
const OstProto::FileContent &content,
|
||||
const QString fileName,
|
||||
QString &error);
|
||||
|
||||
bool isMyFileFormat(const QString fileName);
|
||||
bool isMyFileType(const QString fileType);
|
||||
bool isNativeFileFormat(const QString fileName,
|
||||
OstProto::FileType fileType);
|
||||
void postParseFixup(OstProto::FileMetaData metaData,
|
||||
OstProto::FileContent &content);
|
||||
|
||||
private:
|
||||
void initFileMetaData(OstProto::FileMetaData &metaData);
|
||||
void postParseFixup(OstProto::FileMetaData metaData,
|
||||
OstProto::FileContent &content);
|
||||
int fileMetaSize(const quint8* file, int size);
|
||||
|
||||
static const int kFileMagicSize = 12;
|
||||
static const int kFileChecksumSize = 5;
|
||||
@ -50,13 +67,11 @@ private:
|
||||
static const int kFileMetaDataOffset = kFileMagicSize;
|
||||
|
||||
static const std::string kFileMagicValue;
|
||||
|
||||
|
||||
// Native file format version
|
||||
static const uint kFileFormatVersionMajor = 0;
|
||||
static const uint kFileFormatVersionMinor = 2;
|
||||
static const uint kFileFormatVersionRevision = 4;
|
||||
};
|
||||
|
||||
extern FileFormat fileFormat;
|
||||
|
||||
#endif
|
91
common/ossnfileformat.cpp
Normal file
91
common/ossnfileformat.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "ossnfileformat.h"
|
||||
|
||||
OssnFileFormat ossnFileFormat;
|
||||
|
||||
OssnFileFormat::OssnFileFormat()
|
||||
: SessionFileFormat(), NativeFileFormat()
|
||||
{
|
||||
// Do Nothing
|
||||
}
|
||||
|
||||
bool OssnFileFormat::open(const QString fileName,
|
||||
OstProto::SessionContent &session, QString &error)
|
||||
{
|
||||
OstProto::FileMeta meta;
|
||||
OstProto::FileContent content;
|
||||
bool ret = NativeFileFormat::open(fileName, OstProto::kSessionFileType,
|
||||
meta, content, error);
|
||||
if (!ret)
|
||||
goto _exit;
|
||||
|
||||
if (!content.matter().has_session())
|
||||
goto _missing_session;
|
||||
|
||||
postParseFixup(meta.data(), content);
|
||||
|
||||
session.CopyFrom(content.matter().session());
|
||||
|
||||
return true;
|
||||
|
||||
_missing_session:
|
||||
error = QString(tr("%1 does not contain a session")).arg(fileName);
|
||||
goto _fail;
|
||||
_fail:
|
||||
qDebug("%s", error.toAscii().constData());
|
||||
_exit:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OssnFileFormat::save(const OstProto::SessionContent &session,
|
||||
const QString fileName, QString &error)
|
||||
{
|
||||
OstProto::FileContent content;
|
||||
|
||||
if (!session.IsInitialized())
|
||||
goto _session_not_init;
|
||||
|
||||
content.mutable_matter()->mutable_session()->CopyFrom(session);
|
||||
Q_ASSERT(content.IsInitialized());
|
||||
|
||||
return NativeFileFormat::save(OstProto::kSessionFileType, content,
|
||||
fileName, error);
|
||||
|
||||
_session_not_init:
|
||||
error = QString(tr("Internal Error: Session not initialized\n%1\n%2"))
|
||||
.arg(QString().fromStdString(
|
||||
session.InitializationErrorString()))
|
||||
.arg(QString().fromStdString(session.DebugString()));
|
||||
goto _fail;
|
||||
_fail:
|
||||
qDebug("%s", error.toAscii().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OssnFileFormat::isMyFileFormat(const QString fileName)
|
||||
{
|
||||
return isNativeFileFormat(fileName, OstProto::kSessionFileType);
|
||||
}
|
||||
|
||||
bool OssnFileFormat::isMyFileType(const QString fileType)
|
||||
{
|
||||
return fileType.contains("(*.ossn)") ? true : false;
|
||||
}
|
43
common/ossnfileformat.h
Normal file
43
common/ossnfileformat.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _OSSN_FILE_FORMAT_H
|
||||
#define _OSSN_FILE_FORMAT_H
|
||||
|
||||
#include "nativefileformat.h"
|
||||
#include "sessionfileformat.h"
|
||||
|
||||
class OssnFileFormat : public SessionFileFormat, public NativeFileFormat
|
||||
{
|
||||
public:
|
||||
OssnFileFormat();
|
||||
|
||||
virtual bool open(const QString fileName,
|
||||
OstProto::SessionContent &session, QString &error);
|
||||
virtual bool save(const OstProto::SessionContent &session,
|
||||
const QString fileName, QString &error);
|
||||
|
||||
virtual bool isMyFileFormat(const QString fileName);
|
||||
virtual bool isMyFileType(const QString fileType);
|
||||
};
|
||||
|
||||
extern OssnFileFormat ossnFileFormat;
|
||||
|
||||
#endif
|
||||
|
94
common/ostmfileformat.cpp
Normal file
94
common/ostmfileformat.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "ostmfileformat.h"
|
||||
|
||||
OstmFileFormat fileFormat;
|
||||
|
||||
OstmFileFormat::OstmFileFormat()
|
||||
: StreamFileFormat(), NativeFileFormat()
|
||||
{
|
||||
// Do Nothing!
|
||||
}
|
||||
|
||||
bool OstmFileFormat::open(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error)
|
||||
{
|
||||
OstProto::FileMeta meta;
|
||||
OstProto::FileContent content;
|
||||
bool ret = NativeFileFormat::open(fileName, OstProto::kStreamsFileType,
|
||||
meta, content, error);
|
||||
if (!ret)
|
||||
goto _fail;
|
||||
|
||||
if (!content.matter().has_streams())
|
||||
goto _missing_streams;
|
||||
|
||||
postParseFixup(meta.data(), content);
|
||||
|
||||
streams.CopyFrom(content.matter().streams());
|
||||
|
||||
return true;
|
||||
|
||||
_missing_streams:
|
||||
error = QString(tr("%1 does not contain any streams")).arg(fileName);
|
||||
goto _fail;
|
||||
_fail:
|
||||
qDebug("%s", error.toAscii().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OstmFileFormat::save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error)
|
||||
{
|
||||
OstProto::FileContent content;
|
||||
|
||||
if (!streams.IsInitialized())
|
||||
goto _stream_not_init;
|
||||
|
||||
content.mutable_matter()->mutable_streams()->CopyFrom(streams);
|
||||
Q_ASSERT(content.IsInitialized());
|
||||
|
||||
return NativeFileFormat::save(OstProto::kStreamsFileType, content,
|
||||
fileName, error);
|
||||
|
||||
_stream_not_init:
|
||||
error = QString(tr("Internal Error: Streams not initialized\n%1\n%2"))
|
||||
.arg(QString().fromStdString(
|
||||
streams.InitializationErrorString()))
|
||||
.arg(QString().fromStdString(streams.DebugString()));
|
||||
goto _fail;
|
||||
_fail:
|
||||
qDebug("%s", error.toAscii().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OstmFileFormat::isMyFileFormat(const QString fileName)
|
||||
{
|
||||
return isNativeFileFormat(fileName, OstProto::kStreamsFileType);
|
||||
}
|
||||
|
||||
bool OstmFileFormat::isMyFileType(const QString fileType)
|
||||
{
|
||||
if (fileType.startsWith("Ostinato"))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
43
common/ostmfileformat.h
Normal file
43
common/ostmfileformat.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
#ifndef _OSTM_FILE_FORMAT_H
|
||||
#define _OSTM_FILE_FORMAT_H
|
||||
|
||||
#include "nativefileformat.h"
|
||||
#include "streamfileformat.h"
|
||||
|
||||
#include "fileformat.pb.h"
|
||||
|
||||
class OstmFileFormat : public StreamFileFormat, public NativeFileFormat
|
||||
{
|
||||
public:
|
||||
OstmFileFormat();
|
||||
|
||||
virtual bool open(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error);
|
||||
virtual bool save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error);
|
||||
|
||||
bool isMyFileFormat(const QString fileName);
|
||||
bool isMyFileType(const QString fileType);
|
||||
};
|
||||
|
||||
extern OstmFileFormat fileFormat;
|
||||
|
||||
#endif
|
@ -35,16 +35,19 @@ PROTOS = \
|
||||
# TODO: Move fileformat related stuff into a different library - why?
|
||||
HEADERS = \
|
||||
ostprotolib.h \
|
||||
abstractfileformat.h \
|
||||
fileformat.h \
|
||||
ipv4addressdelegate.h \
|
||||
ipv6addressdelegate.h \
|
||||
nativefileformat.h \
|
||||
ossnfileformat.h \
|
||||
ostmfileformat.h \
|
||||
pcapfileformat.h \
|
||||
pdmlfileformat.h \
|
||||
pythonfileformat.h \
|
||||
pdmlprotocol.h \
|
||||
pdmlprotocols.h \
|
||||
pdmlreader.h \
|
||||
sessionfileformat.h \
|
||||
streamfileformat.h \
|
||||
spinboxdelegate.h
|
||||
|
||||
HEADERS += \
|
||||
@ -80,14 +83,17 @@ HEADERS += \
|
||||
|
||||
SOURCES += \
|
||||
ostprotolib.cpp \
|
||||
abstractfileformat.cpp \
|
||||
fileformat.cpp \
|
||||
nativefileformat.cpp \
|
||||
ossnfileformat.cpp \
|
||||
ostmfileformat.cpp \
|
||||
pcapfileformat.cpp \
|
||||
pdmlfileformat.cpp \
|
||||
pythonfileformat.cpp \
|
||||
pdmlprotocol.cpp \
|
||||
pdmlprotocols.cpp \
|
||||
pdmlreader.cpp \
|
||||
sessionfileformat.cpp \
|
||||
streamfileformat.cpp \
|
||||
spinboxdelegate.cpp
|
||||
|
||||
SOURCES += \
|
||||
|
@ -91,7 +91,7 @@ PcapFileFormat::~PcapFileFormat()
|
||||
delete importDialog_;
|
||||
}
|
||||
|
||||
bool PcapFileFormat::openStreams(const QString fileName,
|
||||
bool PcapFileFormat::open(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error)
|
||||
{
|
||||
bool isOk = false;
|
||||
@ -325,7 +325,7 @@ bool PcapFileFormat::openStreams(const QString fileName,
|
||||
goto _diff_fail;
|
||||
}
|
||||
|
||||
if (!saveStreams(streams, importedPcapFile.fileName(), error))
|
||||
if (!save(streams, importedPcapFile.fileName(), error))
|
||||
{
|
||||
error.append("Error saving imported streams as PCAP for diff");
|
||||
goto _diff_fail;
|
||||
@ -553,7 +553,7 @@ bool PcapFileFormat::readPacket(PcapPacketHeader &pktHdr, QByteArray &pktBuf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PcapFileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
bool PcapFileFormat::save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error)
|
||||
{
|
||||
bool isOk = false;
|
||||
|
@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#ifndef _PCAP_FILE_FORMAT_H
|
||||
#define _PCAP_FILE_FORMAT_H
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
#include "streamfileformat.h"
|
||||
#include "ui_pcapfileimport.h"
|
||||
|
||||
#include <QDataStream>
|
||||
@ -39,7 +39,7 @@ private:
|
||||
};
|
||||
|
||||
class PdmlReader;
|
||||
class PcapFileFormat : public AbstractFileFormat
|
||||
class PcapFileFormat : public StreamFileFormat
|
||||
{
|
||||
friend class PdmlReader;
|
||||
|
||||
@ -47,9 +47,9 @@ public:
|
||||
PcapFileFormat();
|
||||
~PcapFileFormat();
|
||||
|
||||
bool openStreams(const QString fileName,
|
||||
bool open(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error);
|
||||
bool saveStreams(const OstProto::StreamConfigList streams,
|
||||
bool save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error);
|
||||
|
||||
virtual QDialog* openOptionsDialog();
|
||||
|
@ -35,7 +35,7 @@ PdmlFileFormat::~PdmlFileFormat()
|
||||
{
|
||||
}
|
||||
|
||||
bool PdmlFileFormat::openStreams(const QString fileName,
|
||||
bool PdmlFileFormat::open(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error)
|
||||
{
|
||||
bool isOk = false;
|
||||
@ -75,12 +75,12 @@ _exit:
|
||||
return isOk;
|
||||
}
|
||||
|
||||
bool PdmlFileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
bool PdmlFileFormat::save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error)
|
||||
{
|
||||
bool isOk = false;
|
||||
QTemporaryFile pcapFile;
|
||||
AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromType("PCAP");
|
||||
StreamFileFormat *fmt = StreamFileFormat::fileFormatFromType("PCAP");
|
||||
QProcess tshark;
|
||||
|
||||
Q_ASSERT(fmt);
|
||||
@ -97,7 +97,7 @@ bool PdmlFileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
connect(fmt, SIGNAL(progress(int)), this, SIGNAL(progress(int)));
|
||||
|
||||
emit status("Writing intermediate PCAP file...");
|
||||
isOk = fmt->saveStreams(streams, pcapFile.fileName(), error);
|
||||
isOk = fmt->save(streams, pcapFile.fileName(), error);
|
||||
|
||||
qDebug("generating PDML %s", fileName.toAscii().constData());
|
||||
emit status("Converting PCAP to PDML...");
|
||||
|
@ -19,17 +19,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#ifndef _PDML_FILE_FORMAT_H
|
||||
#define _PDML_FILE_FORMAT_H
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
#include "streamfileformat.h"
|
||||
|
||||
class PdmlFileFormat : public AbstractFileFormat
|
||||
class PdmlFileFormat : public StreamFileFormat
|
||||
{
|
||||
public:
|
||||
PdmlFileFormat();
|
||||
~PdmlFileFormat();
|
||||
|
||||
virtual bool openStreams(const QString fileName,
|
||||
virtual bool open(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error);
|
||||
virtual bool saveStreams(const OstProto::StreamConfigList streams,
|
||||
virtual bool save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error);
|
||||
|
||||
bool isMyFileFormat(const QString fileName);
|
||||
|
@ -46,14 +46,14 @@ PythonFileFormat::~PythonFileFormat()
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
bool PythonFileFormat::openStreams(const QString /*fileName*/,
|
||||
bool PythonFileFormat::open(const QString /*fileName*/,
|
||||
OstProto::StreamConfigList &/*streams*/, QString &/*error*/)
|
||||
{
|
||||
// NOT SUPPORTED!
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PythonFileFormat::saveStreams(const OstProto::StreamConfigList streams,
|
||||
bool PythonFileFormat::save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error)
|
||||
{
|
||||
QFile file(fileName);
|
||||
|
@ -20,19 +20,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#ifndef _PYTHON_FILE_FORMAT_H
|
||||
#define _PYTHON_FILE_FORMAT_H
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
#include "streamfileformat.h"
|
||||
|
||||
#include <QTextStream>
|
||||
|
||||
class PythonFileFormat : public AbstractFileFormat
|
||||
class PythonFileFormat : public StreamFileFormat
|
||||
{
|
||||
public:
|
||||
PythonFileFormat();
|
||||
~PythonFileFormat();
|
||||
|
||||
virtual bool openStreams(const QString fileName,
|
||||
virtual bool open(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error);
|
||||
virtual bool saveStreams(const OstProto::StreamConfigList streams,
|
||||
virtual bool save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error);
|
||||
|
||||
bool isMyFileFormat(const QString fileName);
|
||||
|
117
common/sessionfileformat.cpp
Normal file
117
common/sessionfileformat.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "sessionfileformat.h"
|
||||
|
||||
#include "ossnfileformat.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
SessionFileFormat::SessionFileFormat()
|
||||
{
|
||||
stop_ = false;
|
||||
}
|
||||
|
||||
SessionFileFormat::~SessionFileFormat()
|
||||
{
|
||||
}
|
||||
|
||||
QDialog* SessionFileFormat::openOptionsDialog()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QDialog* SessionFileFormat::saveOptionsDialog()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QStringList SessionFileFormat::supportedFileTypes(Operation op)
|
||||
{
|
||||
QStringList fileTypes;
|
||||
|
||||
fileTypes << "Ostinato Session (*.ossn)";
|
||||
|
||||
if (op == kOpenFile)
|
||||
fileTypes << "All files (*)";
|
||||
|
||||
return fileTypes;
|
||||
}
|
||||
|
||||
void SessionFileFormat::openAsync(const QString fileName,
|
||||
OstProto::SessionContent &session, QString &error)
|
||||
{
|
||||
fileName_ = fileName;
|
||||
openSession_ = &session;
|
||||
error_ = &error;
|
||||
op_ = kOpenFile;
|
||||
stop_ = false;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void SessionFileFormat::saveAsync(
|
||||
const OstProto::SessionContent &session,
|
||||
const QString fileName, QString &error)
|
||||
{
|
||||
saveSession_ = &session;
|
||||
fileName_ = fileName;
|
||||
error_ = &error;
|
||||
op_ = kSaveFile;
|
||||
stop_ = false;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
bool SessionFileFormat::result()
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
SessionFileFormat* SessionFileFormat::fileFormatFromFile(
|
||||
const QString fileName)
|
||||
{
|
||||
if (ossnFileFormat.isMyFileFormat(fileName))
|
||||
return &ossnFileFormat;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SessionFileFormat* SessionFileFormat::fileFormatFromType(
|
||||
const QString fileType)
|
||||
{
|
||||
|
||||
if (ossnFileFormat.isMyFileType(fileType))
|
||||
return &ossnFileFormat;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SessionFileFormat::cancel()
|
||||
{
|
||||
stop_ = true;
|
||||
}
|
||||
|
||||
void SessionFileFormat::run()
|
||||
{
|
||||
if (op_ == kOpenFile)
|
||||
result_ = open(fileName_, *openSession_, *error_);
|
||||
else if (op_ == kSaveFile)
|
||||
result_ = save(*saveSession_, fileName_, *error_);
|
||||
}
|
87
common/sessionfileformat.h
Normal file
87
common/sessionfileformat.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _SESSION_FILE_FORMAT_H
|
||||
#define _SESSION_FILE_FORMAT_H
|
||||
|
||||
#include "fileformat.pb.h"
|
||||
#include "protocol.pb.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
|
||||
class QDialog;
|
||||
|
||||
class SessionFileFormat : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Operation { kOpenFile, kSaveFile };
|
||||
|
||||
SessionFileFormat();
|
||||
virtual ~SessionFileFormat();
|
||||
|
||||
virtual bool open(const QString fileName,
|
||||
OstProto::SessionContent &session, QString &error) = 0;
|
||||
virtual bool save(const OstProto::SessionContent &session,
|
||||
const QString fileName, QString &error) = 0;
|
||||
|
||||
virtual QDialog* openOptionsDialog();
|
||||
virtual QDialog* saveOptionsDialog();
|
||||
|
||||
void openAsync(const QString fileName,
|
||||
OstProto::SessionContent &session, QString &error);
|
||||
void saveAsync(const OstProto::SessionContent &session,
|
||||
const QString fileName, QString &error);
|
||||
|
||||
bool result();
|
||||
|
||||
static QStringList supportedFileTypes(Operation op);
|
||||
|
||||
static SessionFileFormat* fileFormatFromFile(const QString fileName);
|
||||
static SessionFileFormat* fileFormatFromType(const QString fileType);
|
||||
|
||||
virtual bool isMyFileFormat(const QString fileName) = 0;
|
||||
virtual bool isMyFileType(const QString fileType) = 0;
|
||||
|
||||
signals:
|
||||
void status(QString text);
|
||||
void target(int value);
|
||||
void progress(int value);
|
||||
|
||||
public slots:
|
||||
void cancel();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
bool stop_;
|
||||
|
||||
private:
|
||||
QString fileName_;
|
||||
OstProto::SessionContent *openSession_;
|
||||
const OstProto::SessionContent *saveSession_;
|
||||
QString *error_;
|
||||
Operation op_;
|
||||
bool result_;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -17,74 +17,82 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
#include "streamfileformat.h"
|
||||
|
||||
#include "fileformat.h"
|
||||
#include "ostmfileformat.h"
|
||||
#include "pcapfileformat.h"
|
||||
#include "pdmlfileformat.h"
|
||||
#include "pythonfileformat.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
AbstractFileFormat::AbstractFileFormat()
|
||||
StreamFileFormat::StreamFileFormat()
|
||||
{
|
||||
stop_ = false;
|
||||
}
|
||||
|
||||
AbstractFileFormat::~AbstractFileFormat()
|
||||
StreamFileFormat::~StreamFileFormat()
|
||||
{
|
||||
}
|
||||
|
||||
QDialog* AbstractFileFormat::openOptionsDialog()
|
||||
QDialog* StreamFileFormat::openOptionsDialog()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QDialog* AbstractFileFormat::saveOptionsDialog()
|
||||
QDialog* StreamFileFormat::saveOptionsDialog()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QStringList AbstractFileFormat::supportedFileTypes()
|
||||
QStringList StreamFileFormat::supportedFileTypes(Operation op)
|
||||
{
|
||||
return QStringList()
|
||||
<< "Ostinato (*)"
|
||||
QStringList fileTypes;
|
||||
|
||||
fileTypes
|
||||
<< "Ostinato (*.ostm)"
|
||||
<< "PCAP (*)"
|
||||
<< "PDML (*.pdml)"
|
||||
<< "PythonScript (*.py)";
|
||||
<< "PDML (*.pdml)";
|
||||
|
||||
if (op == kSaveFile)
|
||||
fileTypes << "PythonScript (*.py)";
|
||||
else if (op == kOpenFile)
|
||||
fileTypes << "All files (*)";
|
||||
|
||||
return fileTypes;
|
||||
}
|
||||
|
||||
void AbstractFileFormat::openStreamsOffline(const QString fileName,
|
||||
void StreamFileFormat::openAsync(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error)
|
||||
{
|
||||
fileName_ = fileName;
|
||||
openStreams_ = &streams;
|
||||
error_ = &error;
|
||||
op_ = kOpen;
|
||||
op_ = kOpenFile;
|
||||
stop_ = false;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void AbstractFileFormat::saveStreamsOffline(
|
||||
void StreamFileFormat::saveAsync(
|
||||
const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error)
|
||||
{
|
||||
saveStreams_ = streams;
|
||||
fileName_ = fileName;
|
||||
error_ = &error;
|
||||
op_ = kSave;
|
||||
op_ = kSaveFile;
|
||||
stop_ = false;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
bool AbstractFileFormat::result()
|
||||
bool StreamFileFormat::result()
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
AbstractFileFormat* AbstractFileFormat::fileFormatFromFile(
|
||||
StreamFileFormat* StreamFileFormat::fileFormatFromFile(
|
||||
const QString fileName)
|
||||
{
|
||||
if (fileFormat.isMyFileFormat(fileName))
|
||||
@ -99,7 +107,7 @@ AbstractFileFormat* AbstractFileFormat::fileFormatFromFile(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AbstractFileFormat* AbstractFileFormat::fileFormatFromType(
|
||||
StreamFileFormat* StreamFileFormat::fileFormatFromType(
|
||||
const QString fileType)
|
||||
{
|
||||
|
||||
@ -118,15 +126,15 @@ AbstractFileFormat* AbstractFileFormat::fileFormatFromType(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void AbstractFileFormat::cancel()
|
||||
void StreamFileFormat::cancel()
|
||||
{
|
||||
stop_ = true;
|
||||
}
|
||||
|
||||
void AbstractFileFormat::run()
|
||||
void StreamFileFormat::run()
|
||||
{
|
||||
if (op_ == kOpen)
|
||||
result_ = openStreams(fileName_, *openStreams_, *error_);
|
||||
else if (op_ == kSave)
|
||||
result_ = saveStreams(saveStreams_, fileName_, *error_);
|
||||
if (op_ == kOpenFile)
|
||||
result_ = open(fileName_, *openStreams_, *error_);
|
||||
else if (op_ == kSaveFile)
|
||||
result_ = save(saveStreams_, fileName_, *error_);
|
||||
}
|
@ -17,8 +17,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _ABSTRACT_FILE_FORMAT_H
|
||||
#define _ABSTRACT_FILE_FORMAT_H
|
||||
#ifndef _STREAM_FILE_FORMAT_H
|
||||
#define _STREAM_FILE_FORMAT_H
|
||||
|
||||
#include "protocol.pb.h"
|
||||
|
||||
@ -27,32 +27,34 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
class QDialog;
|
||||
|
||||
class AbstractFileFormat : public QThread
|
||||
class StreamFileFormat : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AbstractFileFormat();
|
||||
virtual ~AbstractFileFormat();
|
||||
enum Operation { kOpenFile, kSaveFile };
|
||||
|
||||
virtual bool openStreams(const QString fileName,
|
||||
StreamFileFormat();
|
||||
virtual ~StreamFileFormat();
|
||||
|
||||
virtual bool open(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error) = 0;
|
||||
virtual bool saveStreams(const OstProto::StreamConfigList streams,
|
||||
virtual bool save(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error) = 0;
|
||||
|
||||
virtual QDialog* openOptionsDialog();
|
||||
virtual QDialog* saveOptionsDialog();
|
||||
|
||||
void openStreamsOffline(const QString fileName,
|
||||
void openAsync(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error);
|
||||
void saveStreamsOffline(const OstProto::StreamConfigList streams,
|
||||
void saveAsync(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error);
|
||||
|
||||
bool result();
|
||||
|
||||
static QStringList supportedFileTypes();
|
||||
static QStringList supportedFileTypes(Operation op);
|
||||
|
||||
static AbstractFileFormat* fileFormatFromFile(const QString fileName);
|
||||
static AbstractFileFormat* fileFormatFromType(const QString fileType);
|
||||
static StreamFileFormat* fileFormatFromFile(const QString fileName);
|
||||
static StreamFileFormat* fileFormatFromType(const QString fileType);
|
||||
|
||||
#if 0
|
||||
bool isMyFileFormat(const QString fileName) = 0;
|
||||
@ -73,16 +75,11 @@ protected:
|
||||
bool stop_;
|
||||
|
||||
private:
|
||||
enum kOp
|
||||
{
|
||||
kOpen,
|
||||
kSave
|
||||
};
|
||||
QString fileName_;
|
||||
OstProto::StreamConfigList *openStreams_;
|
||||
OstProto::StreamConfigList saveStreams_;
|
||||
QString *error_;
|
||||
kOp op_;
|
||||
Operation op_;
|
||||
bool result_;
|
||||
|
||||
};
|
@ -32,6 +32,7 @@ PbRpcChannel::PbRpcChannel(QString serverName, quint16 port,
|
||||
isPending = false;
|
||||
pendingMethodId = -1; // don't care as long as isPending is false
|
||||
|
||||
method = NULL;
|
||||
controller = NULL;
|
||||
done = NULL;
|
||||
response = NULL;
|
||||
@ -107,9 +108,10 @@ void PbRpcChannel::CallMethod(
|
||||
{
|
||||
RpcCall call;
|
||||
qDebug("RpcChannel: queueing rpc since method %d is pending;<----\n "
|
||||
"queued method = %d\n"
|
||||
"queued method = %d:%s\n"
|
||||
"queued message = \n%s\n---->",
|
||||
pendingMethodId, method->index(), req->DebugString().c_str());
|
||||
pendingMethodId, method->index(), method->name().c_str(),
|
||||
req->DebugString().c_str());
|
||||
|
||||
call.method = method;
|
||||
call.controller = controller;
|
||||
@ -128,7 +130,8 @@ void PbRpcChannel::CallMethod(
|
||||
if (!req->IsInitialized())
|
||||
{
|
||||
qWarning("RpcChannel: missing required fields in request <----");
|
||||
qDebug("req = \n%s", req->DebugString().c_str());
|
||||
qDebug("req = %s\n%s", method->input_type()->name().c_str(),
|
||||
req->DebugString().c_str());
|
||||
qDebug("error = \n%s\n--->", req->InitializationErrorString().c_str());
|
||||
|
||||
controller->SetFailed("Required fields missing");
|
||||
@ -137,6 +140,7 @@ void PbRpcChannel::CallMethod(
|
||||
}
|
||||
|
||||
pendingMethodId = method->index();
|
||||
this->method=method;
|
||||
this->controller=controller;
|
||||
this->done=done;
|
||||
this->response=response;
|
||||
@ -153,8 +157,10 @@ void PbRpcChannel::CallMethod(
|
||||
qDebug("client(%s) sending %d bytes <----", __FUNCTION__,
|
||||
PB_HDR_SIZE + len);
|
||||
BUFDUMP(msg, PB_HDR_SIZE);
|
||||
qDebug("method = %d\n req = \n%s\n---->",
|
||||
method->index(), req->DebugString().c_str());
|
||||
qDebug("method = %d:%s\n req = %s\n%s\n---->",
|
||||
method->index(), method->name().c_str(),
|
||||
method->input_type()->name().c_str(),
|
||||
req->DebugString().c_str());
|
||||
}
|
||||
|
||||
mpSocket->write(msg, PB_HDR_SIZE);
|
||||
@ -308,14 +314,18 @@ _top:
|
||||
if (method != 13)
|
||||
{
|
||||
qDebug("client(%s): Received Msg <---- ", __FUNCTION__);
|
||||
qDebug("method = %d\nresp = \n%s\n---->",
|
||||
method, response->DebugString().c_str());
|
||||
qDebug("method = %d:%s\nresp = %s\n%s\n---->",
|
||||
method, this->method->name().c_str(),
|
||||
this->method->output_type()->name().c_str(),
|
||||
response->DebugString().c_str());
|
||||
}
|
||||
|
||||
if (!response->IsInitialized())
|
||||
{
|
||||
qWarning("RpcChannel: missing required fields in response <----");
|
||||
qDebug("resp = \n%s", response->DebugString().c_str());
|
||||
qDebug("resp = %s\n%s",
|
||||
this->method->output_type()->name().c_str(),
|
||||
response->DebugString().c_str());
|
||||
qDebug("error = \n%s\n--->",
|
||||
response->InitializationErrorString().c_str());
|
||||
|
||||
@ -419,6 +429,7 @@ _top:
|
||||
done->Run();
|
||||
|
||||
pendingMethodId = -1;
|
||||
this->method = NULL;
|
||||
controller = NULL;
|
||||
response = NULL;
|
||||
isPending = false;
|
||||
@ -428,9 +439,11 @@ _top:
|
||||
{
|
||||
RpcCall call = pendingCallList.takeFirst();
|
||||
qDebug("RpcChannel: executing queued method <----\n"
|
||||
"method = %d\n"
|
||||
"req = \n%s\n---->",
|
||||
call.method->index(), call.request->DebugString().c_str());
|
||||
"method = %d:%s\n"
|
||||
"req = %s\n%s\n---->",
|
||||
call.method->index(), call.method->name().c_str(),
|
||||
call.method->input_type()->name().c_str(),
|
||||
call.request->DebugString().c_str());
|
||||
CallMethod(call.method, call.controller, call.request, call.response,
|
||||
call.done);
|
||||
}
|
||||
@ -475,6 +488,7 @@ void PbRpcChannel::on_mpSocket_disconnected()
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
pendingMethodId = -1;
|
||||
method = NULL;
|
||||
controller = NULL;
|
||||
response = NULL;
|
||||
isPending = false;
|
||||
|
@ -49,6 +49,7 @@ class PbRpcChannel : public QObject, public ::google::protobuf::RpcChannel
|
||||
|
||||
/*! \todo (MED) : change controller, done and response to references
|
||||
instead of pointers? */
|
||||
const ::google::protobuf::MethodDescriptor *method;
|
||||
::google::protobuf::RpcController *controller;
|
||||
::google::protobuf::Closure *done;
|
||||
::google::protobuf::Message *response;
|
||||
|
@ -101,12 +101,8 @@ PcapPort::PcapPort(int id, const char *device)
|
||||
{
|
||||
if (strcmp(device, dev->name) == 0)
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
data_.set_name(QString("if%1").arg(id).toStdString());
|
||||
#else
|
||||
if (dev->name)
|
||||
data_.set_name(dev->name);
|
||||
#endif
|
||||
if (dev->description)
|
||||
data_.set_description(dev->description);
|
||||
|
||||
|
46
test/TODO.md
Normal file
46
test/TODO.md
Normal file
@ -0,0 +1,46 @@
|
||||
# TODO - Test Cases
|
||||
|
||||
## Session Save/Open
|
||||
* Verify save session prompts before opening Save Dialog about only reserved ports being saved if there are some reserved ports and not prompted at all if no ports are reserved
|
||||
* Verify each save session triggers the file dialog at the last path used
|
||||
* Verify saved session file is correct
|
||||
* All portgroups are saved
|
||||
* All suitable (wrt reservation) ports are saved
|
||||
* All port configuration is saved
|
||||
* For each port -
|
||||
* All streams are saved with correct contents
|
||||
* All deviceGroups are saved with correct contents
|
||||
* OSSN Session file format tests (TODO: expand)
|
||||
* Verify no file is saved if user clicks 'Cancel' on the progress dialog while saving session file
|
||||
|
||||
* On open session, verify user is prompted before opening the file dialog if there are existing portgroups and not prompted at all if there are no port groups
|
||||
* Verify each open session triggers the file dialog at the last path used
|
||||
* Verify open file dialog file filter has `(*.ssn *.*)`
|
||||
* Verify opening a unsupported format file triggers an error and existing session is not changed
|
||||
* Verify all existing portgroups are removed before new ones from the file are created and configured
|
||||
* Verify that only ports in the opened session file are overwritten and other ports are not changed
|
||||
* Verify that if port in the opened session file was reserved at save time, and the same port is now reserved by someone else, it is not changed and user is informed; if current port reservation is by self, port is overwritten with contents from the session file; all reservations made by open session are with self username, not the username who had reserved the port during save time (in other words, allow session files to be exchanged between users)
|
||||
* Verify no unnecessary RPCs during open session
|
||||
* if port has no existing streams, deleteStreams() is not invoked
|
||||
* if port has no existing deviceGroups, deleteDeviceGroups() is not invoked
|
||||
* if port config has no change, modifyPort() is not invoked
|
||||
* if opened port has no streams, addStreams()/modifyStreams() is not invoked
|
||||
* if opened port has no deviceGroups, addDeviceGroups()/modifyDeviceGroups() is not invoked
|
||||
* Verify open session is successful
|
||||
* All streams are restored with correct contents
|
||||
* All deviceGroups are restored with correct contents
|
||||
* Port config (TxMode, ExclusiveMode, UserName) is changed, if required
|
||||
* OSSN Session file format tests (TODO: expand)
|
||||
* Verify no change in existing port groups if user clicks 'Cancel' on the options dialog
|
||||
* Verify no change in existing port groups if user clicks 'Cancel' on the progress dialog while opening session file
|
||||
* Verify all old portgroups are removed before new portgroups from the session file are added
|
||||
* Verify config of portGroups loaded from the session file are correct
|
||||
* Verify config of a portGroup is NOT restored to the config saved in session file after a open session - disconnect - connect
|
||||
|
||||
## Streams Save/Open
|
||||
* Verify save file dialog file filter has all supported types but no `*.*`
|
||||
* Stream file format tests (TODO: expand)
|
||||
|
||||
* Verify open file dialog file filter has all supported types except `*.py` and `*.*`
|
||||
* Verify opening a unsupported format file triggers an error and existing streams are not changed
|
||||
* Stream file format tests (TODO: expand)
|
Loading…
Reference in New Issue
Block a user