Display External IP Address in status bar

This change displays the last detected IPv4 and/or IPv6 address(es) in the GUI and WebUI's status bar. This does not yet handle systems with multiple addresses of the same type (e.g. multiple IPv6 addresses).
This commit is contained in:
Odin Vex 2023-12-06 23:10:31 -05:00 committed by Thomas Piccirello
parent a23f45cc70
commit b0b2fa20a0
No known key found for this signature in database
16 changed files with 138 additions and 7 deletions

View file

@ -467,6 +467,9 @@ namespace BitTorrent
virtual void topTorrentsQueuePos(const QList<TorrentID> &ids) = 0;
virtual void bottomTorrentsQueuePos(const QList<TorrentID> &ids) = 0;
virtual QString lastExternalIPv4Address() const = 0;
virtual QString lastExternalIPv6Address() const = 0;
signals:
void startupProgressUpdated(int progress);
void addTorrentFailed(const InfoHash &infoHash, const QString &reason);

View file

@ -4945,6 +4945,16 @@ void SessionImpl::setTrackerFilteringEnabled(const bool enabled)
}
}
QString SessionImpl::lastExternalIPv4Address() const
{
return m_lastExternalIPv4Address;
}
QString SessionImpl::lastExternalIPv6Address() const
{
return m_lastExternalIPv6Address;
}
bool SessionImpl::isListening() const
{
return m_nativeSessionExtension->isSessionListening();
@ -5932,11 +5942,19 @@ void SessionImpl::handleExternalIPAlert(const lt::external_ip_alert *alert)
LogMsg(tr("Detected external IP. IP: \"%1\"")
.arg(externalIP), Log::INFO);
if (m_lastExternalIP != externalIP)
const bool isIPv6 = alert->external_address.is_v6();
const bool isIPv4 = alert->external_address.is_v4();
if (isIPv6 && (externalIP != m_lastExternalIPv6Address))
{
if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIP.isEmpty())
if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIPv6Address.isEmpty())
reannounceToAllTrackers();
m_lastExternalIP = externalIP;
m_lastExternalIPv6Address = externalIP;
}
else if (isIPv4 && (externalIP != m_lastExternalIPv4Address))
{
if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIPv4Address.isEmpty())
reannounceToAllTrackers();
m_lastExternalIPv4Address = externalIP;
}
}

View file

@ -444,6 +444,9 @@ namespace BitTorrent
void topTorrentsQueuePos(const QList<TorrentID> &ids) override;
void bottomTorrentsQueuePos(const QList<TorrentID> &ids) override;
QString lastExternalIPv4Address() const override;
QString lastExternalIPv6Address() const override;
// Torrent interface
void handleTorrentResumeDataRequested(const TorrentImpl *torrent);
void handleTorrentShareLimitChanged(TorrentImpl *torrent);
@ -807,7 +810,8 @@ namespace BitTorrent
QList<MoveStorageJob> m_moveStorageQueue;
QString m_lastExternalIP;
QString m_lastExternalIPv4Address;
QString m_lastExternalIPv6Address;
bool m_needUpgradeDownloadPath = false;

View file

@ -359,6 +359,19 @@ void Preferences::setStatusbarDisplayed(const bool displayed)
setValue(u"Preferences/General/StatusbarDisplayed"_s, displayed);
}
bool Preferences::isStatusbarExternalIPDisplayed() const
{
return value(u"Preferences/General/StatusbarExternalIPDisplayed"_s, true);
}
void Preferences::setStatusbarExternalIPDisplayed(const bool displayed)
{
if (displayed == isStatusbarExternalIPDisplayed())
return;
setValue(u"Preferences/General/StatusbarExternalIPDisplayed"_s, displayed);
}
bool Preferences::isSplashScreenDisabled() const
{
return value(u"Preferences/General/NoSplashScreen"_s, true);

View file

@ -119,6 +119,8 @@ public:
void setHideZeroComboValues(int n);
bool isStatusbarDisplayed() const;
void setStatusbarDisplayed(bool displayed);
bool isStatusbarExternalIPDisplayed() const;
void setStatusbarExternalIPDisplayed(bool displayed);
bool isToolbarDisplayed() const;
void setToolbarDisplayed(bool displayed);
bool isSplashScreenDisabled() const;

View file

@ -1443,6 +1443,7 @@ void MainWindow::loadPreferences()
}
showStatusBar(pref->isStatusbarDisplayed());
m_statusBar->showStatusBarExternalIP(pref->isStatusbarExternalIPDisplayed());
m_transferListWidget->setAlternatingRowColors(pref->useAlternatingRowColors());
m_propertiesWidget->getFilesList()->setAlternatingRowColors(pref->useAlternatingRowColors());

View file

@ -344,6 +344,7 @@ void OptionsDialog::loadBehaviorTabOptions()
m_ui->checkFileLog->setChecked(app()->isFileLoggerEnabled());
m_ui->checkBoxPerformanceWarning->setChecked(session->isPerformanceWarningEnabled());
m_ui->checkBoxExternalIPStatusBar->setChecked(pref->isStatusbarExternalIPDisplayed());
connect(m_ui->comboI18n, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
@ -423,6 +424,7 @@ void OptionsDialog::loadBehaviorTabOptions()
connect(m_ui->comboFileLogAgeType, qComboBoxCurrentIndexChanged, this, &ThisType::enableApplyButton);
connect(m_ui->checkBoxPerformanceWarning, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
connect(m_ui->checkBoxExternalIPStatusBar, &QAbstractButton::toggled, this, &ThisType::enableApplyButton);
}
void OptionsDialog::saveBehaviorTabOptions() const
@ -507,6 +509,7 @@ void OptionsDialog::saveBehaviorTabOptions() const
app()->setStartUpWindowState(m_ui->windowStateComboBox->currentData().value<WindowState>());
session->setPerformanceWarningEnabled(m_ui->checkBoxPerformanceWarning->isChecked());
pref->setStatusbarExternalIPDisplayed(m_ui->checkBoxExternalIPStatusBar->isChecked());
}
void OptionsDialog::loadDownloadsTabOptions()

View file

@ -772,6 +772,13 @@
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxExternalIPStatusBar">
<property name="text">
<string>Show external IP in status bar</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxPerformanceWarning">
<property name="text">

View file

@ -86,6 +86,9 @@ StatusBar::StatusBar(QWidget *parent)
m_upSpeedLbl->setStyleSheet(u"text-align:left;"_s);
m_upSpeedLbl->setMinimumWidth(200);
m_lastExternalIPsLbl = new QLabel(tr("External IP: N/A"));
m_lastExternalIPsLbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
m_DHTLbl = new QLabel(tr("DHT: %1 nodes").arg(0), this);
m_DHTLbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
@ -129,14 +132,21 @@ StatusBar::StatusBar(QWidget *parent)
#ifndef Q_OS_MACOS
statusSep4->setFrameShadow(QFrame::Raised);
#endif
layout->addWidget(m_DHTLbl);
QFrame *statusSep5 = new QFrame(this);
statusSep5->setFrameStyle(QFrame::VLine);
#ifndef Q_OS_MACOS
statusSep5->setFrameShadow(QFrame::Raised);
#endif
layout->addWidget(m_lastExternalIPsLbl);
layout->addWidget(statusSep1);
layout->addWidget(m_connecStatusLblIcon);
layout->addWidget(m_DHTLbl);
layout->addWidget(statusSep2);
layout->addWidget(m_connecStatusLblIcon);
layout->addWidget(statusSep3);
layout->addWidget(m_altSpeedsBtn);
layout->addWidget(statusSep4);
layout->addWidget(m_dlSpeedLbl);
layout->addWidget(statusSep3);
layout->addWidget(statusSep5);
layout->addWidget(m_upSpeedLbl);
addPermanentWidget(container);
@ -170,6 +180,11 @@ void StatusBar::showRestartRequired()
insertWidget(1, restartLbl);
}
void StatusBar::showStatusBarExternalIP(const bool display)
{
m_lastExternalIPsLbl->setVisible(display);
}
void StatusBar::updateConnectionStatus()
{
const BitTorrent::SessionStatus &sessionStatus = BitTorrent::Session::instance()->status();
@ -212,6 +227,23 @@ void StatusBar::updateDHTNodesNumber()
}
}
void StatusBar::updateExternalAddressesLabel()
{
const QString lastExternalIPv4Address = BitTorrent::Session::instance()->lastExternalIPv4Address();
const QString lastExternalIPv6Address = BitTorrent::Session::instance()->lastExternalIPv6Address();
QString addressText = tr("External IP: N/A");
const bool hasIPv4Address = !lastExternalIPv4Address.isEmpty();
const bool hasIPv6Address = !lastExternalIPv6Address.isEmpty();
if (hasIPv4Address && hasIPv6Address)
addressText = tr("External IPs: %1, %2").arg(lastExternalIPv4Address, lastExternalIPv6Address);
else if (hasIPv4Address || hasIPv6Address)
addressText = tr("External IP: %1%2").arg(lastExternalIPv4Address, lastExternalIPv6Address);
m_lastExternalIPsLbl->setText(addressText);
}
void StatusBar::updateSpeedLabels()
{
const BitTorrent::SessionStatus &sessionStatus = BitTorrent::Session::instance()->status();
@ -235,6 +267,7 @@ void StatusBar::refresh()
{
updateConnectionStatus();
updateDHTNodesNumber();
updateExternalAddressesLabel();
updateSpeedLabels();
}

View file

@ -47,6 +47,8 @@ public:
StatusBar(QWidget *parent = nullptr);
~StatusBar() override;
void showStatusBarExternalIP(bool display);
signals:
void alternativeSpeedsButtonClicked();
void connectionButtonClicked();
@ -62,10 +64,12 @@ private slots:
private:
void updateConnectionStatus();
void updateDHTNodesNumber();
void updateExternalAddressesLabel();
void updateSpeedLabels();
QPushButton *m_dlSpeedLbl = nullptr;
QPushButton *m_upSpeedLbl = nullptr;
QLabel *m_lastExternalIPsLbl = nullptr;
QLabel *m_DHTLbl = nullptr;
QPushButton *m_connecStatusLblIcon = nullptr;
QPushButton *m_altSpeedsBtn = nullptr;

View file

@ -127,6 +127,7 @@ void AppController::preferencesAction()
// Language
data[u"locale"_s] = pref->getLocale();
data[u"performance_warning"_s] = session->isPerformanceWarningEnabled();
data[u"status_bar_external_ip"_s] = pref->isStatusbarExternalIPDisplayed();
// Transfer List
data[u"confirm_torrent_deletion"_s] = pref->confirmTorrentDeletion();
// Log file
@ -510,6 +511,8 @@ void AppController::setPreferencesAction()
}
if (hasKey(u"performance_warning"_s))
session->setPerformanceWarningEnabled(it.value().toBool());
if (hasKey(u"status_bar_external_ip"_s))
pref->setStatusbarExternalIPDisplayed(it.value().toBool());
// Transfer List
if (hasKey(u"confirm_torrent_deletion"_s))
pref->setConfirmTorrentDeletion(it.value().toBool());

View file

@ -87,6 +87,8 @@ namespace
const QString KEY_TRANSFER_DLRATELIMIT = u"dl_rate_limit"_s;
const QString KEY_TRANSFER_DLSPEED = u"dl_info_speed"_s;
const QString KEY_TRANSFER_FREESPACEONDISK = u"free_space_on_disk"_s;
const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4 = u"last_external_address_v4"_s;
const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6 = u"last_external_address_v6"_s;
const QString KEY_TRANSFER_UPDATA = u"up_info_data"_s;
const QString KEY_TRANSFER_UPRATELIMIT = u"up_rate_limit"_s;
const QString KEY_TRANSFER_UPSPEED = u"up_info_speed"_s;
@ -161,6 +163,8 @@ namespace
map[KEY_TRANSFER_AVERAGE_TIME_QUEUE] = cacheStatus.averageJobTime;
map[KEY_TRANSFER_TOTAL_QUEUED_SIZE] = cacheStatus.queuedBytes;
map[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4] = session->lastExternalIPv4Address();
map[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6] = session->lastExternalIPv6Address();
map[KEY_TRANSFER_DHT_NODES] = sessionStatus.dhtNodes;
map[KEY_TRANSFER_CONNECTION_STATUS] = session->isListening()
? (sessionStatus.hasIncomingConnections ? u"connected"_s : u"firewalled"_s)
@ -450,6 +454,8 @@ void SyncController::updateFreeDiskSpace(const qint64 freeDiskSpace)
// - "dl_info_data": bytes downloaded
// - "dl_info_speed": download speed
// - "dl_rate_limit: download rate limit
// - "last_external_address_v4": last external address v4
// - "last_external_address_v6": last external address v6
// - "up_info_data: bytes uploaded
// - "up_info_speed: upload speed
// - "up_rate_limit: upload speed limit

View file

@ -45,6 +45,8 @@ const QString KEY_TRANSFER_DLRATELIMIT = u"dl_rate_limit"_s;
const QString KEY_TRANSFER_UPSPEED = u"up_info_speed"_s;
const QString KEY_TRANSFER_UPDATA = u"up_info_data"_s;
const QString KEY_TRANSFER_UPRATELIMIT = u"up_rate_limit"_s;
const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4 = u"last_external_address_v4"_s;
const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6 = u"last_external_address_v6"_s;
const QString KEY_TRANSFER_DHT_NODES = u"dht_nodes"_s;
const QString KEY_TRANSFER_CONNECTION_STATUS = u"connection_status"_s;
@ -57,6 +59,8 @@ const QString KEY_TRANSFER_CONNECTION_STATUS = u"connection_status"_s;
// - "up_info_data": Data uploaded this session
// - "dl_rate_limit": Download rate limit
// - "up_rate_limit": Upload rate limit
// - "last_external_address_v4": external IPv4 address
// - "last_external_address_v6": external IPv6 address
// - "dht_nodes": DHT nodes connected to
// - "connection_status": Connection status
void TransferController::infoAction()
@ -71,6 +75,8 @@ void TransferController::infoAction()
dict[KEY_TRANSFER_UPDATA] = static_cast<qint64>(sessionStatus.totalPayloadUpload);
dict[KEY_TRANSFER_DLRATELIMIT] = BitTorrent::Session::instance()->downloadSpeedLimit();
dict[KEY_TRANSFER_UPRATELIMIT] = BitTorrent::Session::instance()->uploadSpeedLimit();
dict[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4] = BitTorrent::Session::instance()->lastExternalIPv4Address();
dict[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6] = BitTorrent::Session::instance()->lastExternalIPv6Address();
dict[KEY_TRANSFER_DHT_NODES] = static_cast<qint64>(sessionStatus.dhtNodes);
if (!BitTorrent::Session::instance()->isListening())
dict[KEY_TRANSFER_CONNECTION_STATUS] = u"disconnected"_s;

View file

@ -266,6 +266,8 @@
<tbody>
<tr>
<td id="freeSpaceOnDisk"></td>
<td class="statusBarSeparator invisible"></td>
<td id="externalIPs" class="invisible"></td>
<td class="statusBarSeparator"></td>
<td id="DHTNodes"></td>
<td class="statusBarSeparator"></td>

View file

@ -928,6 +928,25 @@ window.addEventListener("DOMContentLoaded", () => {
$("freeSpaceOnDisk").textContent = "QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]".replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk));
if (window.qBittorrent.Cache.preferences.get().status_bar_external_ip) {
const lastExternalAddressV4 = serverState.last_external_address_v4;
const lastExternalAddressV6 = serverState.last_external_address_v6;
const hasIPv4Address = lastExternalAddressV4 !== "";
const hasIPv6Address = lastExternalAddressV6 !== "";
let lastExternalAddressLabel = "QBT_TR(External IP: N/A)QBT_TR[CONTEXT=HttpServer]";
if (hasIPv4Address && hasIPv6Address)
lastExternalAddressLabel = "QBT_TR(External IPs: %1, %2)QBT_TR[CONTEXT=HttpServer]";
else if (hasIPv4Address || hasIPv6Address)
lastExternalAddressLabel = "QBT_TR(External IP: %1%2)QBT_TR[CONTEXT=HttpServer]";
// replace in reverse order ('%2' before '%1') in case address contains a % character.
// for example, see https://en.wikipedia.org/wiki/IPv6_address#Scoped_literal_IPv6_addresses_(with_zone_index)
$("externalIPs").textContent = lastExternalAddressLabel.replace("%2", lastExternalAddressV6).replace("%1", lastExternalAddressV4);
const elem = document.getElementById("externalIPs");
elem.classList.remove("invisible");
elem.previousElementSibling.classList.remove("invisible");
}
const dhtElement = document.getElementById("DHTNodes");
if (window.qBittorrent.Cache.preferences.get().dht) {
dhtElement.textContent = "QBT_TR(DHT: %1 nodes)QBT_TR[CONTEXT=StatusBar]".replace("%1", serverState.dht_nodes);

View file

@ -80,6 +80,11 @@
</table>
</fieldset>
<div class="formRow" style="margin-bottom: 3px;">
<input type="checkbox" id="statusBarExternalIP">
<label for="statusBarExternalIP">QBT_TR(Show external IP in status bar)QBT_TR[CONTEXT=OptionsDialog]</label>
</div>
<div class="formRow" style="margin-bottom: 5px;">
<input type="checkbox" id="performanceWarning">
<label for="performanceWarning">QBT_TR(Log performance warnings)QBT_TR[CONTEXT=OptionsDialog]</label>
@ -2411,6 +2416,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
// Language
updateWebuiLocaleSelect(pref.locale);
$("performanceWarning").checked = pref.performance_warning;
$("statusBarExternalIP").checked = pref.status_bar_external_ip;
// HTTP Server
$("webui_domain_textarea").value = pref.web_ui_domain_list;
@ -2836,6 +2842,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
// Language
settings["locale"] = $("locale_select").value;
settings["performance_warning"] = $("performanceWarning").checked;
settings["status_bar_external_ip"] = $("statusBarExternalIP").checked;
// HTTP Server
settings["web_ui_domain_list"] = $("webui_domain_textarea").value;