2022-09-29 16:17:51 +00:00
|
|
|
#include "cluster.h"
|
|
|
|
#include "logcategories.h"
|
|
|
|
|
|
|
|
|
|
|
|
dxClusterClient::dxClusterClient(QObject* parent):
|
|
|
|
QObject(parent)
|
|
|
|
{
|
|
|
|
qInfo(logCluster()) << "starting dxClusterClient()";
|
|
|
|
}
|
|
|
|
|
|
|
|
dxClusterClient::~dxClusterClient()
|
|
|
|
{
|
|
|
|
qInfo(logCluster()) << "closing dxClusterClient()";
|
|
|
|
enableUdp(false);
|
|
|
|
enableTcp(false);
|
2022-10-05 11:43:39 +00:00
|
|
|
#ifdef USESQL
|
2022-10-05 10:03:15 +00:00
|
|
|
database db;
|
|
|
|
db.close();
|
2022-10-05 11:43:39 +00:00
|
|
|
#else
|
|
|
|
QMap<QString, spotData*>::iterator spot = allSpots.begin();
|
|
|
|
while (spot != allSpots.end())
|
|
|
|
{
|
|
|
|
delete spot.value(); // Stop memory leak?
|
|
|
|
spot = allSpots.erase(spot);
|
|
|
|
}
|
|
|
|
#endif
|
2022-09-29 16:17:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dxClusterClient::enableUdp(bool enable)
|
|
|
|
{
|
|
|
|
udpEnable = enable;
|
|
|
|
if (enable)
|
|
|
|
{
|
|
|
|
if (udpSocket == Q_NULLPTR)
|
|
|
|
{
|
|
|
|
udpSocket = new QUdpSocket(this);
|
|
|
|
bool result = udpSocket->bind(QHostAddress::AnyIPv4, udpPort);
|
|
|
|
qInfo(logCluster()) << "Starting udpSocket() on:" << udpPort << "Result:" << result;
|
|
|
|
|
|
|
|
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(udpDataReceived()), Qt::QueuedConnection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (udpSocket != Q_NULLPTR)
|
|
|
|
{
|
2022-09-30 16:05:42 +00:00
|
|
|
qInfo(logCluster()) << "Stopping udpSocket() on:" << udpPort;
|
|
|
|
|
2022-09-29 16:17:51 +00:00
|
|
|
udpSocket->disconnect();
|
|
|
|
delete udpSocket;
|
2022-09-30 16:05:42 +00:00
|
|
|
udpSocket = Q_NULLPTR;
|
2022-09-29 16:17:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dxClusterClient::enableTcp(bool enable)
|
|
|
|
{
|
|
|
|
tcpEnable = enable;
|
2022-09-30 16:05:42 +00:00
|
|
|
if (enable)
|
|
|
|
{
|
2022-10-31 12:39:27 +00:00
|
|
|
tcpRegex = QRegularExpression("^DX de ([a-z-|A-Z|0-9|#|/]+):\\s+([0-9|.]+)\\s+([a-z|A-Z|0-9|/]+)+\\s+(.*)\\s+(\\d{4}Z)");
|
2022-09-30 16:05:42 +00:00
|
|
|
|
|
|
|
if (tcpSocket == Q_NULLPTR)
|
|
|
|
{
|
|
|
|
tcpSocket = new QTcpSocket(this);
|
|
|
|
tcpSocket->connectToHost(tcpServerName, tcpPort);
|
|
|
|
qInfo(logCluster()) << "Starting tcpSocket() on:" << tcpPort;
|
|
|
|
|
|
|
|
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(tcpDataReceived()), Qt::QueuedConnection);
|
2022-10-05 10:03:15 +00:00
|
|
|
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(tcpDisconnected()));
|
2022-09-30 16:05:42 +00:00
|
|
|
|
|
|
|
tcpCleanupTimer = new QTimer(this);
|
|
|
|
tcpCleanupTimer->setInterval(1000 * 10); // Run once a minute
|
|
|
|
connect(tcpCleanupTimer, SIGNAL(timeout()), this, SLOT(tcpCleanup()));
|
|
|
|
tcpCleanupTimer->start();
|
2022-10-31 12:15:42 +00:00
|
|
|
authenticated = false;
|
2022-09-30 16:05:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (tcpSocket != Q_NULLPTR)
|
|
|
|
{
|
2022-10-28 19:04:32 +00:00
|
|
|
sendTcpData(QString("bye\n"));
|
2022-09-30 16:05:42 +00:00
|
|
|
qInfo(logCluster()) << "Disconnecting tcpSocket() on:" << tcpPort;
|
|
|
|
if (tcpCleanupTimer != Q_NULLPTR)
|
|
|
|
{
|
|
|
|
tcpCleanupTimer->stop();
|
|
|
|
delete tcpCleanupTimer;
|
|
|
|
tcpCleanupTimer = Q_NULLPTR;
|
|
|
|
}
|
|
|
|
tcpSocket->disconnect();
|
|
|
|
delete tcpSocket;
|
|
|
|
tcpSocket = Q_NULLPTR;
|
|
|
|
}
|
|
|
|
}
|
2022-09-29 16:17:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dxClusterClient::udpDataReceived()
|
|
|
|
{
|
|
|
|
QHostAddress sender;
|
|
|
|
quint16 port;
|
|
|
|
QByteArray datagram;
|
|
|
|
datagram.resize(udpSocket->pendingDatagramSize());
|
|
|
|
udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
|
|
|
|
|
|
|
|
if (udpSpotReader.setContent(datagram))
|
|
|
|
{
|
|
|
|
QDomElement spot = udpSpotReader.firstChildElement("spot");
|
|
|
|
if (spot.nodeName() == "spot")
|
|
|
|
{
|
|
|
|
// This is a spot?
|
|
|
|
QString action = spot.firstChildElement("action").text();
|
|
|
|
if (action == "add") {
|
2022-09-30 16:05:42 +00:00
|
|
|
spotData* data = new spotData();
|
|
|
|
data->dxcall = spot.firstChildElement("dxcall").text();
|
|
|
|
data->frequency = spot.firstChildElement("frequency").text().toDouble() / 1000.0;
|
|
|
|
data->spottercall = spot.firstChildElement("spottercall").text();
|
|
|
|
data->timestamp = QDateTime::fromString(spot.firstChildElement("timestamp").text(),"yyyy-MM-dd hh:mm:ss");
|
|
|
|
data->mode = spot.firstChildElement("mode").text();
|
|
|
|
data->comment = spot.firstChildElement("comment").text();
|
2022-10-05 10:03:15 +00:00
|
|
|
|
2022-10-05 11:43:39 +00:00
|
|
|
#ifdef USESQL
|
2022-10-05 10:03:15 +00:00
|
|
|
database db = database();
|
|
|
|
db.query(QString("DELETE from spots where dxcall='%1'").arg(data->dxcall));
|
|
|
|
QString query = QString("INSERT INTO spots(type,spottercall,frequency,dxcall,mode,comment,timestamp) VALUES('%1','%2',%3,'%4','%5','%6','%7')\n")
|
|
|
|
.arg("UDP").arg(data->spottercall).arg(data->frequency).arg(data->dxcall).arg(data->mode).arg(data->comment).arg(data->timestamp.toString("yyyy-MM-dd hh:mm:ss"));
|
|
|
|
db.query(query);
|
2022-10-05 11:43:39 +00:00
|
|
|
#else
|
|
|
|
bool found = false;
|
|
|
|
QMap<QString, spotData*>::iterator spot = allSpots.find(data->dxcall);
|
|
|
|
while (spot != allSpots.end() && spot.key() == data->dxcall && spot.value()->frequency == data->frequency) {
|
|
|
|
found = true;
|
|
|
|
++spot;
|
|
|
|
}
|
|
|
|
if (found == false) {
|
|
|
|
allSpots.insert(data->dxcall, data);
|
|
|
|
}
|
|
|
|
#endif
|
2022-10-09 13:23:07 +00:00
|
|
|
emit sendOutput(QString("<spot><action>add</action><dxcall>%1</dxcall><spottercall>%2</spottercall><frequency>%3</frequency><comment>%4</comment></spot>\n")
|
|
|
|
.arg(data->dxcall).arg(data->spottercall).arg(data->frequency).arg(data->comment));
|
2022-10-05 11:43:39 +00:00
|
|
|
|
2022-09-29 16:17:51 +00:00
|
|
|
}
|
|
|
|
else if (action == "delete")
|
|
|
|
{
|
|
|
|
QString dxcall = spot.firstChildElement("dxcall").text();
|
2022-10-05 10:03:15 +00:00
|
|
|
double frequency = spot.firstChildElement("frequency").text().toDouble() / 1000.0;
|
2022-10-05 11:43:39 +00:00
|
|
|
|
|
|
|
#ifdef USESQL
|
2022-10-05 10:03:15 +00:00
|
|
|
database db = database();
|
|
|
|
QString query=QString("DELETE from spots where dxcall='%1' AND frequency=%2").arg(dxcall).arg(frequency);
|
|
|
|
db.query(query);
|
|
|
|
qInfo(logCluster()) << query;
|
2022-10-05 11:43:39 +00:00
|
|
|
#else
|
|
|
|
QMap<QString, spotData*>::iterator spot = allSpots.find(dxcall);
|
|
|
|
while (spot != allSpots.end() && spot.key() == dxcall && spot.value()->frequency == frequency)
|
|
|
|
{
|
|
|
|
delete spot.value(); // Stop memory leak?
|
|
|
|
spot = allSpots.erase(spot);
|
|
|
|
}
|
|
|
|
#endif
|
2022-10-09 13:23:07 +00:00
|
|
|
emit sendOutput(QString("<spot><action>delete</action><dxcall>%1</dxcall<frequency>%3</frequency></spot>\n")
|
|
|
|
.arg(dxcall).arg(frequency));
|
2022-09-29 16:17:51 +00:00
|
|
|
}
|
2022-10-05 10:03:15 +00:00
|
|
|
updateSpots();
|
2022-09-29 16:17:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-30 16:05:42 +00:00
|
|
|
|
|
|
|
void dxClusterClient::tcpDataReceived()
|
|
|
|
{
|
|
|
|
QString data = QString(tcpSocket->readAll());
|
|
|
|
|
2022-10-09 13:35:24 +00:00
|
|
|
emit sendOutput(data);
|
2022-10-31 12:15:42 +00:00
|
|
|
if (!authenticated) {
|
|
|
|
if (data.contains("login:") || data.contains("call:") || data.contains("callsign:")) {
|
|
|
|
sendTcpData(QString("%1\n").arg(tcpUserName));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (data.contains("password:")) {
|
|
|
|
sendTcpData(QString("%1\n").arg(tcpPassword));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (data.contains("Hello")) {
|
|
|
|
authenticated = true;
|
2022-10-31 12:39:27 +00:00
|
|
|
enableSkimmerSpots(skimmerSpots);
|
2022-10-31 12:15:42 +00:00
|
|
|
}
|
2022-09-30 16:05:42 +00:00
|
|
|
}
|
2022-10-31 12:15:42 +00:00
|
|
|
else {
|
|
|
|
QRegularExpressionMatchIterator i = tcpRegex.globalMatch(data);
|
|
|
|
while (i.hasNext()) {
|
|
|
|
QRegularExpressionMatch match = i.next();
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
spotData* data = new spotData();
|
|
|
|
data->spottercall = match.captured(1);
|
|
|
|
data->frequency = match.captured(2).toDouble() / 1000.0;
|
|
|
|
data->dxcall = match.captured(3);
|
|
|
|
data->comment = match.captured(4).trimmed();
|
|
|
|
data->timestamp = QDateTime::currentDateTimeUtc();
|
2022-10-05 11:43:39 +00:00
|
|
|
|
|
|
|
#ifdef USESQL
|
2022-10-31 12:15:42 +00:00
|
|
|
database db = database();
|
|
|
|
db.query(QString("DELETE from spots where dxcall='%1'").arg(data->dxcall));
|
|
|
|
QString query = QString("INSERT INTO spots(type,spottercall,frequency,dxcall,comment,timestamp) VALUES('%1','%2',%3,'%4','%5','%6')\n")
|
|
|
|
.arg("TCP").arg(data->spottercall).arg(data->frequency).arg(data->dxcall).arg(data->comment).arg(data->timestamp.toString("yyyy-MM-dd hh:mm:ss"));
|
|
|
|
db.query(query);
|
2022-10-05 11:43:39 +00:00
|
|
|
#else
|
2022-10-31 12:15:42 +00:00
|
|
|
bool found = false;
|
|
|
|
QMap<QString, spotData*>::iterator spot = allSpots.find(data->dxcall);
|
|
|
|
while (spot != allSpots.end() && spot.key() == data->dxcall && spot.value()->frequency == data->frequency) {
|
|
|
|
found = true;
|
|
|
|
++spot;
|
|
|
|
}
|
|
|
|
if (found == false) {
|
|
|
|
allSpots.insert(data->dxcall, data);
|
|
|
|
}
|
2022-10-05 11:43:39 +00:00
|
|
|
#endif
|
2022-10-31 12:15:42 +00:00
|
|
|
}
|
2022-09-30 16:05:42 +00:00
|
|
|
}
|
2022-10-31 12:15:42 +00:00
|
|
|
updateSpots();
|
2022-09-30 16:05:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dxClusterClient::sendTcpData(QString data)
|
|
|
|
{
|
|
|
|
qInfo(logCluster()) << "Sending:" << data;
|
|
|
|
if (tcpSocket != Q_NULLPTR && tcpSocket->isValid() && tcpSocket->isOpen())
|
|
|
|
{
|
|
|
|
tcpSocket->write(data.toLatin1());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
qInfo(logCluster()) << "socket not open!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dxClusterClient::tcpCleanup()
|
|
|
|
{
|
2022-10-05 11:43:39 +00:00
|
|
|
#ifdef USESQL
|
2022-10-05 10:03:15 +00:00
|
|
|
database db = database();
|
|
|
|
db.query(QString("DELETE FROM spots where timestamp < datetime('now', '-%1 minutes')").arg(tcpTimeout));
|
2022-10-05 11:43:39 +00:00
|
|
|
#else
|
|
|
|
QMap<QString, spotData*>::iterator spot = allSpots.begin();;
|
|
|
|
while (spot != allSpots.end()) {
|
|
|
|
if (spot.value()->timestamp.addSecs(tcpTimeout * 60) < QDateTime::currentDateTimeUtc())
|
|
|
|
{
|
|
|
|
delete spot.value(); // Stop memory leak?
|
|
|
|
spot = allSpots.erase(spot);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++spot;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2022-10-05 10:03:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dxClusterClient::tcpDisconnected() {
|
|
|
|
qWarning(logCluster()) << "TCP Cluster server disconnected...";
|
|
|
|
// Need to start a timer and attempt reconnect.
|
|
|
|
}
|
|
|
|
|
|
|
|
void dxClusterClient::freqRange(double low, double high)
|
|
|
|
{
|
|
|
|
lowFreq = low;
|
|
|
|
highFreq = high;
|
|
|
|
//qInfo(logCluster) << "New range" << low << "-" << high;
|
|
|
|
updateSpots();
|
|
|
|
}
|
|
|
|
|
|
|
|
void dxClusterClient::updateSpots()
|
|
|
|
{
|
2022-10-05 11:43:39 +00:00
|
|
|
QList<spotData> spots;
|
|
|
|
#ifdef USESQL
|
|
|
|
// Set the required frequency range.
|
2022-10-05 10:05:29 +00:00
|
|
|
QString queryText = QString("SELECT * FROM spots WHERE frequency > %1 AND frequency < %2").arg(lowFreq).arg(highFreq);
|
2022-10-05 10:03:15 +00:00
|
|
|
//QString queryText = QString("SELECT * FROM spots");
|
|
|
|
database db;
|
|
|
|
auto query = db.query(queryText);
|
|
|
|
|
|
|
|
while (query.next()) {
|
|
|
|
// Step through all current spots within range
|
|
|
|
spotData s = spotData();
|
|
|
|
s.dxcall = query.value(query.record().indexOf("dxcall")).toString();
|
|
|
|
s.frequency = query.value(query.record().indexOf("frequency")).toDouble();
|
|
|
|
spots.append(s);
|
|
|
|
}
|
2022-10-05 11:43:39 +00:00
|
|
|
#else
|
|
|
|
QMap<QString, spotData*>::iterator spot = allSpots.begin();;
|
|
|
|
while (spot != allSpots.end()) {
|
|
|
|
if (spot.value()->frequency > lowFreq && spot.value()->frequency < highFreq)
|
|
|
|
{
|
|
|
|
spots.append(**spot);
|
|
|
|
}
|
2022-10-05 13:26:42 +00:00
|
|
|
++spot;
|
2022-10-05 11:43:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2022-10-05 10:03:15 +00:00
|
|
|
emit sendSpots(spots);
|
|
|
|
}
|
2022-10-31 12:39:27 +00:00
|
|
|
|
|
|
|
void dxClusterClient::enableSkimmerSpots(bool enable)
|
|
|
|
{
|
|
|
|
skimmerSpots = enable;
|
|
|
|
if (authenticated) {
|
|
|
|
if (skimmerSpots) {
|
|
|
|
sendTcpData(QString("Set Dx Filter Skimmer\n"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sendTcpData(QString("Set Dx Filter Not Skimmer\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|