Add version and revision information to UDP heartbeat messages

Updated  UDP examples  to show  the version  and revision  information
received from clients.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7358 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2016-12-04 00:55:15 +00:00
parent ac859c8f68
commit 2255b17e91
11 changed files with 79 additions and 23 deletions

View File

@ -21,9 +21,12 @@ class MessageClient::impl
Q_OBJECT; Q_OBJECT;
public: public:
impl (QString const& id, port_type server_port, MessageClient * self) impl (QString const& id, QString const& version, QString const& revision,
port_type server_port, MessageClient * self)
: self_ {self} : self_ {self}
, id_ {id} , id_ {id}
, version_ {version}
, revision_ {revision}
, server_port_ {server_port} , server_port_ {server_port}
, schema_ {2} // use 2 prior to negotiation not 1 which is broken , schema_ {2} // use 2 prior to negotiation not 1 which is broken
, heartbeat_timer_ {new QTimer {this}} , heartbeat_timer_ {new QTimer {this}}
@ -66,6 +69,8 @@ public:
MessageClient * self_; MessageClient * self_;
QString id_; QString id_;
QString version_;
QString revision_;
QString server_string_; QString server_string_;
port_type server_port_; port_type server_port_;
QHostAddress server_; QHostAddress server_;
@ -188,6 +193,11 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
default: default:
// Ignore // Ignore
//
// Note that although server heartbeat messages are not
// parsed here they are still partially parsed in the
// message reader class to negotiate the maximum schema
// number being used on the network.
break; break;
} }
} }
@ -208,7 +218,8 @@ void MessageClient::impl::heartbeat ()
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id_, schema_}; NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id_, schema_};
hb << NetworkMessage::Builder::schema_number; // maximum schema number accepted hb << NetworkMessage::Builder::schema_number // maximum schema number accepted
<< version_.toUtf8 () << revision_.toUtf8 ();
if (OK == check_status (hb)) if (OK == check_status (hb))
{ {
writeDatagram (message, server_, server_port_); writeDatagram (message, server_, server_port_);
@ -273,9 +284,10 @@ auto MessageClient::impl::check_status (QDataStream const& stream) const -> Stre
return result; return result;
} }
MessageClient::MessageClient (QString const& id, QString const& server, port_type server_port, QObject * self) MessageClient::MessageClient (QString const& id, QString const& version, QString const& revision,
QString const& server, port_type server_port, QObject * self)
: QObject {self} : QObject {self}
, m_ {id, server_port, this} , m_ {id, version, revision, server_port, this}
{ {
connect (&*m_, static_cast<void (impl::*) (impl::SocketError)> (&impl::error) connect (&*m_, static_cast<void (impl::*) (impl::SocketError)> (&impl::error)
, [this] (impl::SocketError e) , [this] (impl::SocketError e)

View File

@ -32,7 +32,8 @@ public:
// instantiate and initiate a host lookup on the server // instantiate and initiate a host lookup on the server
// //
// messages will be silently dropped until a server host lookup is complete // messages will be silently dropped until a server host lookup is complete
MessageClient (QString const& id, QString const& server, port_type server_port, QObject * parent = nullptr); MessageClient (QString const& id, QString const& version, QString const& revision,
QString const& server, port_type server_port, QObject * parent = nullptr);
// query server details // query server details
QHostAddress server_address () const; QHostAddress server_address () const;

View File

@ -21,8 +21,10 @@ class MessageServer::impl
Q_OBJECT; Q_OBJECT;
public: public:
impl (MessageServer * self) impl (MessageServer * self, QString const& version, QString const& revision)
: self_ {self} : self_ {self}
, version_ {version}
, revision_ {revision}
, port_ {0u} , port_ {0u}
, clock_ {new QTimer {this}} , clock_ {new QTimer {this}}
{ {
@ -60,6 +62,8 @@ public:
} }
MessageServer * self_; MessageServer * self_;
QString version_;
QString revision_;
port_type port_; port_type port_;
QHostAddress multicast_group_address_; QHostAddress multicast_group_address_;
static BindMode constexpr bind_mode_ = ShareAddress | ReuseAddressHint; static BindMode constexpr bind_mode_ = ShareAddress | ReuseAddressHint;
@ -145,6 +149,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
if (!clients_.contains (id)) if (!clients_.contains (id))
{ {
auto& client = (clients_[id] = {sender, sender_port}); auto& client = (clients_[id] = {sender, sender_port});
QByteArray client_version;
QByteArray client_revision;
if (NetworkMessage::Heartbeat == in.type ()) if (NetworkMessage::Heartbeat == in.type ())
{ {
@ -159,7 +165,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
// negotiated schema number // negotiated schema number
QByteArray message; QByteArray message;
NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id, client.negotiated_schema_number_}; NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id, client.negotiated_schema_number_};
hb << NetworkMessage::Builder::schema_number; // maximum schema number accepted hb << NetworkMessage::Builder::schema_number // maximum schema number accepted
<< version_.toUtf8 () << revision_.toUtf8 ();
if (impl::OK == check_status (hb)) if (impl::OK == check_status (hb))
{ {
writeDatagram (message, client.sender_address_, client.sender_port_); writeDatagram (message, client.sender_address_, client.sender_port_);
@ -169,8 +176,11 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
Q_EMIT self_->error ("Error creating UDP message"); Q_EMIT self_->error ("Error creating UDP message");
} }
} }
// we don't care if this fails to read
in >> client_version >> client_revision;
} }
Q_EMIT self_->client_opened (id); Q_EMIT self_->client_opened (id, QString::fromUtf8 (client_version),
QString::fromUtf8 (client_revision));
} }
clients_[id].last_activity_ = QDateTime::currentDateTime (); clients_[id].last_activity_ = QDateTime::currentDateTime ();
@ -350,9 +360,9 @@ auto MessageServer::impl::check_status (QDataStream const& stream) const -> Stre
return result; return result;
} }
MessageServer::MessageServer (QObject * parent) MessageServer::MessageServer (QObject * parent, QString const& version, QString const& revision)
: QObject {parent} : QObject {parent}
, m_ {this} , m_ {this, version, revision}
{ {
} }

View File

@ -31,12 +31,14 @@ public:
using port_type = quint16; using port_type = quint16;
using Frequency = Radio::Frequency; using Frequency = Radio::Frequency;
MessageServer (QObject * parent = nullptr); MessageServer (QObject * parent = nullptr,
QString const& version = QString {}, QString const& revision = QString {});
// start or restart the server, if the multicast_group_address // start or restart the server, if the multicast_group_address
// argument is given it is assumed to be a multicast group address // argument is given it is assumed to be a multicast group address
// which the server will join // which the server will join
Q_SLOT void start (port_type port, QHostAddress const& multicast_group_address = QHostAddress {}); Q_SLOT void start (port_type port,
QHostAddress const& multicast_group_address = QHostAddress {});
// ask the client with identification 'id' to make the same action // ask the client with identification 'id' to make the same action
// as a double click on the decode would // as a double click on the decode would
@ -59,7 +61,7 @@ public:
// the following signals are emitted when a client broadcasts the // the following signals are emitted when a client broadcasts the
// matching message // matching message
Q_SIGNAL void client_opened (QString const& id); Q_SIGNAL void client_opened (QString const& id, QString const& version, QString const& revision);
Q_SIGNAL void status_update (QString const& id, Frequency, QString const& mode, QString const& dx_call Q_SIGNAL void status_update (QString const& id, Frequency, QString const& mode, QString const& dx_call
, QString const& report, QString const& tx_mode, bool tx_enabled , QString const& report, QString const& tx_mode, bool tx_enabled
, bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df , bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df

View File

@ -78,6 +78,8 @@
* Heartbeat Out/In 0 quint32 * Heartbeat Out/In 0 quint32
* Id (unique key) utf8 * Id (unique key) utf8
* Maximum schema number quint32 * Maximum schema number quint32
* version utf8
* revision utf8
* *
* The heartbeat message shall be sent on a periodic basis every * The heartbeat message shall be sent on a periodic basis every
* NetworkMessage::pulse seconds (see below), the WSJT-X * NetworkMessage::pulse seconds (see below), the WSJT-X

View File

@ -94,9 +94,27 @@ void ClientWidget::IdFilterModel::rx_df (int df)
} }
} }
namespace
{
QString make_title (QString const& id, QString const& version, QString const& revision)
{
QString title {id};
if (version.size ())
{
title += QString {" v%1"}.arg (version);
}
if (revision.size ())
{
title += QString {" (%1)"}.arg (revision);
}
return title;
}
}
ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
, QString const& id, QWidget * parent) , QString const& id, QString const& version, QString const& revision
: QDockWidget {id, parent} , QWidget * parent)
: QDockWidget {make_title (id, version, revision), parent}
, id_ {id} , id_ {id}
, decodes_proxy_model_ {id_} , decodes_proxy_model_ {id_}
, decodes_table_view_ {new QTableView} , decodes_table_view_ {new QTableView}

View File

@ -21,7 +21,8 @@ class ClientWidget
public: public:
explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
, QString const& id, QWidget * parent = nullptr); , QString const& id, QString const& version, QString const& revision
, QWidget * parent = nullptr);
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
, QString const& report, QString const& tx_mode, bool tx_enabled , QString const& report, QString const& tx_mode, bool tx_enabled

View File

@ -126,9 +126,9 @@ void MessageAggregatorMainWindow::log_qso (QString const& /*id*/, QDateTime time
log_table_view_->scrollToBottom (); log_table_view_->scrollToBottom ();
} }
void MessageAggregatorMainWindow::add_client (QString const& id) void MessageAggregatorMainWindow::add_client (QString const& id, QString const& version, QString const& revision)
{ {
auto dock = new ClientWidget {decodes_model_, beacons_model_, id, this}; auto dock = new ClientWidget {decodes_model_, beacons_model_, id, version, revision, this};
dock->setAttribute (Qt::WA_DeleteOnClose); dock->setAttribute (Qt::WA_DeleteOnClose);
auto view_action = dock->toggleViewAction (); auto view_action = dock->toggleViewAction ();
view_action->setEnabled (true); view_action->setEnabled (true);

View File

@ -32,7 +32,7 @@ public:
, QString const& name); , QString const& name);
private: private:
void add_client (QString const& id); void add_client (QString const& id, QString const& version, QString const& revision);
void remove_client (QString const& id); void remove_client (QString const& id);
QStandardItemModel * log_; QStandardItemModel * log_;

View File

@ -112,7 +112,7 @@ public:
} }
private: private:
void add_client (QString const& id) void add_client (QString const& id, QString const& version, QString const& revision)
{ {
auto client = new Client {id}; auto client = new Client {id};
connect (server_, &MessageServer::status_update, client, &Client::update_status); connect (server_, &MessageServer::status_update, client, &Client::update_status);
@ -120,7 +120,16 @@ private:
connect (server_, &MessageServer::WSPR_decode, client, &Client::beacon_spot_added); connect (server_, &MessageServer::WSPR_decode, client, &Client::beacon_spot_added);
clients_[id] = client; clients_[id] = client;
server_->replay (id); server_->replay (id);
std::cout << "Discovered WSJT-X instance: " << id.toStdString () << std::endl; std::cout << "Discovered WSJT-X instance: " << id.toStdString ();
if (version.size ())
{
std::cout << " v" << version.toStdString ();
}
if (revision.size ())
{
std::cout << " (" << revision.toStdString () << ")";
}
std::cout << std::endl;
} }
void remove_client (QString const& id) void remove_client (QString const& id)

View File

@ -332,8 +332,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
"Please be patient,\n" "Please be patient,\n"
"this may take a few minutes", QString {}, 0, 1, this}, "this may take a few minutes", QString {}, 0, 1, this},
m_messageClient {new MessageClient {QApplication::applicationName (), m_messageClient {new MessageClient {QApplication::applicationName (),
m_config.udp_server_name (), m_config.udp_server_port (), version (), revision (),
this}}, m_config.udp_server_name (), m_config.udp_server_port (),
this}},
psk_Reporter {new PSK_Reporter {m_messageClient, this}}, psk_Reporter {new PSK_Reporter {m_messageClient, this}},
m_manual {network_manager} m_manual {network_manager}
{ {