mirror of
https://github.com/tnodir/fort
synced 2024-11-15 09:45:44 +00:00
UI: Add IpListModel & HostInfoCache.
This commit is contained in:
parent
39bec283c7
commit
cf1fee6d6c
@ -20,6 +20,7 @@ SOURCES += \
|
||||
log/logentryblocked.cpp \
|
||||
log/logmanager.cpp \
|
||||
log/model/appblockedmodel.cpp \
|
||||
log/model/iplistmodel.cpp \
|
||||
log/model/stringlistmodel.cpp \
|
||||
mainwindow.cpp \
|
||||
task/taskinfo.cpp \
|
||||
@ -33,6 +34,7 @@ SOURCES += \
|
||||
util/fileutil.cpp \
|
||||
util/guiutil.cpp \
|
||||
util/net/hostinfo.cpp \
|
||||
util/net/hostinfocache.cpp \
|
||||
util/net/hostinfoworker.cpp \
|
||||
util/net/ip4range.cpp \
|
||||
util/net/netdownloader.cpp \
|
||||
@ -55,6 +57,7 @@ HEADERS += \
|
||||
log/logentryblocked.h \
|
||||
log/logmanager.h \
|
||||
log/model/appblockedmodel.h \
|
||||
log/model/iplistmodel.h \
|
||||
log/model/stringlistmodel.h \
|
||||
mainwindow.h \
|
||||
task/taskinfo.h \
|
||||
@ -68,6 +71,7 @@ HEADERS += \
|
||||
util/fileutil.h \
|
||||
util/guiutil.h \
|
||||
util/net/hostinfo.h \
|
||||
util/net/hostinfocache.h \
|
||||
util/net/hostinfoworker.h \
|
||||
util/net/ip4range.h \
|
||||
util/net/netdownloader.h \
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "translationmanager.h"
|
||||
#include "util/fileutil.h"
|
||||
#include "util/guiutil.h"
|
||||
#include "util/net/hostinfo.h"
|
||||
#include "util/net/hostinfocache.h"
|
||||
#include "util/net/netutil.h"
|
||||
#include "util/osutil.h"
|
||||
|
||||
@ -77,7 +77,7 @@ void FortManager::registerQmlTypes()
|
||||
|
||||
qmlRegisterType<FileUtil>("com.fortfirewall", 1, 0, "FileUtil");
|
||||
qmlRegisterType<GuiUtil>("com.fortfirewall", 1, 0, "GuiUtil");
|
||||
qmlRegisterType<HostInfo>("com.fortfirewall", 1, 0, "HostInfo");
|
||||
qmlRegisterType<HostInfoCache>("com.fortfirewall", 1, 0, "HostInfoCache");
|
||||
qmlRegisterType<NetUtil>("com.fortfirewall", 1, 0, "NetUtil");
|
||||
qmlRegisterType<OsUtil>("com.fortfirewall", 1, 0, "OsUtil");
|
||||
}
|
||||
|
@ -21,6 +21,16 @@ QAbstractItemModel *LogManager::appBlockedModel() const
|
||||
return m_appBlockedModel;
|
||||
}
|
||||
|
||||
QAbstractItemModel *LogManager::ipListModel(const QString &appPath) const
|
||||
{
|
||||
return m_appBlockedModel->ipListModel(appPath);
|
||||
}
|
||||
|
||||
void LogManager::clearModels() const
|
||||
{
|
||||
m_appBlockedModel->clear();
|
||||
}
|
||||
|
||||
void LogManager::setErrorMessage(const QString &errorMessage)
|
||||
{
|
||||
if (m_errorMessage != errorMessage) {
|
||||
|
@ -25,6 +25,9 @@ signals:
|
||||
|
||||
public slots:
|
||||
QAbstractItemModel *appBlockedModel() const;
|
||||
QAbstractItemModel *ipListModel(const QString &appPath) const;
|
||||
|
||||
void clearModels() const;
|
||||
|
||||
void setLogReadingEnabled(bool enabled);
|
||||
|
||||
|
@ -4,14 +4,34 @@
|
||||
#include "../../util/net/netutil.h"
|
||||
#include "../../util/osutil.h"
|
||||
#include "../logentryblocked.h"
|
||||
#include "iplistmodel.h"
|
||||
|
||||
#define IP_LIST_COUNT_MAX 64
|
||||
#define IP_LIST_SIZE_MAX 64
|
||||
|
||||
AppBlockedModel::AppBlockedModel(QObject *parent) :
|
||||
StringListModel(parent)
|
||||
StringListModel(parent),
|
||||
m_ipListModel(new IpListModel(this))
|
||||
{
|
||||
}
|
||||
|
||||
QAbstractItemModel *AppBlockedModel::ipListModel(const QString &appPath) const
|
||||
{
|
||||
if (appPath != m_ipListModel->appPath()) {
|
||||
m_ipListModel->setAppPath(appPath);
|
||||
m_ipListModel->setList(m_appIpList.value(appPath));
|
||||
}
|
||||
|
||||
return m_ipListModel;
|
||||
}
|
||||
|
||||
void AppBlockedModel::clear()
|
||||
{
|
||||
m_appIpList.clear();
|
||||
m_appIpSet.clear();
|
||||
|
||||
setList(QStringList());
|
||||
}
|
||||
|
||||
void AppBlockedModel::addLogEntry(const LogEntryBlocked &logEntry)
|
||||
{
|
||||
const QString appPath = getEntryPath(logEntry);
|
||||
@ -34,11 +54,17 @@ void AppBlockedModel::addLogEntry(const LogEntryBlocked &logEntry)
|
||||
ipList.prepend(ipText);
|
||||
|
||||
if (isNewApp) {
|
||||
insert(appPath);
|
||||
} else if (ipList.size() > IP_LIST_COUNT_MAX) {
|
||||
insert(appPath); // update at the end to refresh the view
|
||||
} else {
|
||||
if (ipList.size() > IP_LIST_SIZE_MAX) {
|
||||
const QString oldIpText = ipList.takeLast();
|
||||
ipSet.remove(oldIpText);
|
||||
}
|
||||
|
||||
if (appPath == m_ipListModel->appPath()) {
|
||||
m_ipListModel->setList(ipList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString AppBlockedModel::getEntryPath(const LogEntryBlocked &logEntry)
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "stringlistmodel.h"
|
||||
|
||||
class IpListModel;
|
||||
class LogEntryBlocked;
|
||||
|
||||
class AppBlockedModel : public StringListModel
|
||||
@ -20,6 +21,9 @@ public:
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
QAbstractItemModel *ipListModel(const QString &appPath) const;
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
static QString getEntryPath(const LogEntryBlocked &logEntry);
|
||||
@ -27,6 +31,8 @@ private:
|
||||
private:
|
||||
QHash<QString, QStringList> m_appIpList;
|
||||
QHash<QString, QSet<QString>> m_appIpSet;
|
||||
|
||||
IpListModel *m_ipListModel;
|
||||
};
|
||||
|
||||
#endif // APPBLOCKEDMODEL_H
|
||||
|
11
src/ui/log/model/iplistmodel.cpp
Normal file
11
src/ui/log/model/iplistmodel.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "iplistmodel.h"
|
||||
|
||||
IpListModel::IpListModel(QObject *parent) :
|
||||
StringListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void IpListModel::setAppPath(const QString &appPath)
|
||||
{
|
||||
m_appPath = appPath;
|
||||
}
|
24
src/ui/log/model/iplistmodel.h
Normal file
24
src/ui/log/model/iplistmodel.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef IPLISTMODEL_H
|
||||
#define IPLISTMODEL_H
|
||||
|
||||
#include "stringlistmodel.h"
|
||||
|
||||
class IpListModel : public StringListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit IpListModel(QObject *parent = nullptr);
|
||||
|
||||
QString appPath() const { return m_appPath; }
|
||||
void setAppPath(const QString &appPath);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
QString m_appPath;
|
||||
};
|
||||
|
||||
#endif // IPLISTMODEL_H
|
@ -20,6 +20,13 @@ QVariant StringListModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void StringListModel::setList(const QStringList &list)
|
||||
{
|
||||
beginResetModel();
|
||||
m_list = list;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void StringListModel::insert(const QString &text, int row)
|
||||
{
|
||||
row = adjustRow(row);
|
||||
|
@ -14,6 +14,8 @@ public:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
void setList(const QStringList &list);
|
||||
|
||||
protected:
|
||||
void insert(const QString &text, int row = -1);
|
||||
void remove(int row = -1);
|
||||
|
@ -6,26 +6,14 @@ import com.fortfirewall 1.0
|
||||
|
||||
BasePage {
|
||||
|
||||
readonly property DriverManager driverManager: fortManager.driverManager
|
||||
readonly property LogManager logManager: fortManager.logManager
|
||||
|
||||
property bool logReadingEnabled: false
|
||||
property bool addressResolvingEnabled: false
|
||||
|
||||
// TODO: Use SHGetFileInfo() to get app's display name and icon
|
||||
property var appNames: []
|
||||
property var appPaths: []
|
||||
property var appPathIpMap: ({})
|
||||
property var appPathIpArray: ({})
|
||||
|
||||
property var hostNames: ({})
|
||||
|
||||
function readLogAsync() {
|
||||
driverManager.readLogAsync(logBuffer);
|
||||
}
|
||||
|
||||
function cancelAsyncIo() {
|
||||
driverManager.cancelAsyncIo();
|
||||
}
|
||||
readonly property string currentAppPath:
|
||||
(appListView.currentIndex >= 0 && appListView.currentItem)
|
||||
? appListView.currentItem.appPath : ""
|
||||
|
||||
function switchLogReading(enable) {
|
||||
if (logReadingEnabled === enable)
|
||||
@ -34,12 +22,6 @@ BasePage {
|
||||
logReadingEnabled = enable;
|
||||
|
||||
fortManager.setLogBlocked(enable);
|
||||
|
||||
if (enable) {
|
||||
readLogAsync();
|
||||
} else {
|
||||
cancelAsyncIo();
|
||||
}
|
||||
}
|
||||
|
||||
function switchResolveAddresses(enable) {
|
||||
@ -47,85 +29,10 @@ BasePage {
|
||||
return;
|
||||
|
||||
addressResolvingEnabled = enable;
|
||||
|
||||
if (!enable) {
|
||||
hostInfo.clear();
|
||||
}
|
||||
}
|
||||
|
||||
function clearAppPaths() {
|
||||
appNames = [];
|
||||
appPaths = [];
|
||||
appPathIpMap = ({});
|
||||
appPathIpArray = ({});
|
||||
|
||||
hostNames = ({});
|
||||
hostInfo.clear();
|
||||
|
||||
refreshListViews();
|
||||
}
|
||||
|
||||
function processLogBuffer() {
|
||||
var isNewEntry = false;
|
||||
|
||||
while (logBuffer.read(logEntry)) {
|
||||
var path = getEntryPath(logEntry);
|
||||
var ipText = netUtil.ip4ToText(logEntry.ip);
|
||||
|
||||
var ipTextsMap = appPathIpMap[path];
|
||||
if (!ipTextsMap) {
|
||||
ipTextsMap = ({});
|
||||
appPathIpMap[path] = ipTextsMap;
|
||||
appPathIpArray[path] = [];
|
||||
appNames.push(fileUtil.fileName(path));
|
||||
appPaths.push(path);
|
||||
|
||||
isNewEntry = true;
|
||||
}
|
||||
|
||||
var ipCount = ipTextsMap[ipText];
|
||||
ipTextsMap[ipText] = (ipCount || 0) + 1;
|
||||
|
||||
var ipTextsArray = appPathIpArray[path];
|
||||
if (!ipCount) {
|
||||
if (ipTextsArray.length > 64) {
|
||||
var oldIp = ipTextsArray.pop();
|
||||
delete ipTextsMap[oldIp];
|
||||
}
|
||||
ipTextsArray.unshift(ipText);
|
||||
|
||||
isNewEntry = true;
|
||||
}
|
||||
|
||||
// Host name
|
||||
if (hostNames[ipText] === undefined) {
|
||||
hostNames[ipText] = false;
|
||||
if (addressResolvingEnabled) {
|
||||
hostInfo.lookupHost(ipText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewEntry) {
|
||||
refreshListViews();
|
||||
}
|
||||
}
|
||||
|
||||
function getEntryPath(logEntry) {
|
||||
const kernelPath = logEntry.kernelPath;
|
||||
if (kernelPath) {
|
||||
return fileUtil.kernelPathToPath(kernelPath);
|
||||
}
|
||||
|
||||
return osUtil.pidToPath(logEntry.pid);
|
||||
}
|
||||
|
||||
function refreshListViews() {
|
||||
const curIndex = appListView.currentIndex;
|
||||
appListView.model = undefined;
|
||||
|
||||
appListView.model = appNames;
|
||||
appListView.currentIndex = curIndex;
|
||||
logManager.clearModels();
|
||||
}
|
||||
|
||||
Connections {
|
||||
@ -136,36 +43,8 @@ BasePage {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: driverManager
|
||||
onReadLogResult: {
|
||||
if (success) {
|
||||
processLogBuffer();
|
||||
}
|
||||
|
||||
if (logReadingEnabled) {
|
||||
readLogAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HostInfo {
|
||||
id: hostInfo
|
||||
onLookupFinished: {
|
||||
if (addressResolvingEnabled) {
|
||||
hostNames[address] = hostName;
|
||||
if (hostName) {
|
||||
refreshListViews();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogBuffer {
|
||||
id: logBuffer
|
||||
}
|
||||
LogEntryBlocked {
|
||||
id: logEntry
|
||||
HostInfoCache {
|
||||
id: hostInfoCache
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
@ -214,6 +93,8 @@ BasePage {
|
||||
Layout.fillHeight: true
|
||||
spacing: 10
|
||||
|
||||
model: logManager.appBlockedModel()
|
||||
|
||||
highlightRangeMode: ListView.ApplyRange
|
||||
highlightResizeDuration: 0
|
||||
highlightMoveDuration: 200
|
||||
@ -230,9 +111,13 @@ BasePage {
|
||||
}
|
||||
|
||||
delegate: Row {
|
||||
id: appItem
|
||||
width: appListView.width
|
||||
spacing: 6
|
||||
|
||||
readonly property string appPath: modelData
|
||||
|
||||
// TODO: Use SHGetFileInfo() to get app's display name and icon
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: 1
|
||||
@ -241,7 +126,7 @@ BasePage {
|
||||
Label {
|
||||
font.pixelSize: 20
|
||||
elide: Text.ElideRight
|
||||
text: modelData
|
||||
text: fileUtil.fileName(appItem.appPath)
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,19 +147,14 @@ BasePage {
|
||||
Layout.fillHeight: true
|
||||
spacing: 4
|
||||
|
||||
model: {
|
||||
const curIndex = appListView.currentIndex;
|
||||
if (curIndex < 0)
|
||||
return undefined;
|
||||
|
||||
const path = appPaths[curIndex];
|
||||
return appPathIpArray[path];
|
||||
}
|
||||
model: logManager.ipListModel(currentAppPath)
|
||||
|
||||
delegate: Label {
|
||||
width: ipListView.width
|
||||
elide: Text.ElideRight
|
||||
text: hostNames[ipText] || ipText
|
||||
text: (addressResolvingEnabled && hostInfoCache.dummyBool
|
||||
&& hostInfoCache.hostName(ipText)) || ipText
|
||||
|
||||
readonly property string ipText: modelData
|
||||
}
|
||||
}
|
||||
@ -283,7 +163,7 @@ BasePage {
|
||||
|
||||
TextFieldFrame {
|
||||
Layout.fillWidth: true
|
||||
text: appPaths[appListView.currentIndex] || ""
|
||||
text: currentAppPath || ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
41
src/ui/util/net/hostinfocache.cpp
Normal file
41
src/ui/util/net/hostinfocache.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include "hostinfocache.h"
|
||||
|
||||
#include "hostinfo.h"
|
||||
|
||||
HostInfoCache::HostInfoCache(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_hostInfo(new HostInfo(this))
|
||||
{
|
||||
}
|
||||
|
||||
QString HostInfoCache::hostName(const QString &address)
|
||||
{
|
||||
if (!m_cache.contains(address)) {
|
||||
m_cache.insert(address, QString());
|
||||
m_hostInfo->lookupHost(address);
|
||||
return QString();
|
||||
}
|
||||
|
||||
return m_cache.value(address);
|
||||
}
|
||||
|
||||
void HostInfoCache::clear()
|
||||
{
|
||||
m_hostInfo->clear();
|
||||
m_cache.clear();
|
||||
|
||||
emitCacheChanged();
|
||||
}
|
||||
|
||||
void HostInfoCache::handleFinishedLookup(const QString &address,
|
||||
const QString &hostName)
|
||||
{
|
||||
m_cache.insert(address, hostName);
|
||||
|
||||
emitCacheChanged();
|
||||
}
|
||||
|
||||
void HostInfoCache::emitCacheChanged()
|
||||
{
|
||||
emit cacheChanged();
|
||||
}
|
40
src/ui/util/net/hostinfocache.h
Normal file
40
src/ui/util/net/hostinfocache.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef HOSTINFOCACHE_H
|
||||
#define HOSTINFOCACHE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
|
||||
class HostInfo;
|
||||
|
||||
class HostInfoCache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool dummyBool READ dummyBool NOTIFY cacheChanged)
|
||||
|
||||
public:
|
||||
explicit HostInfoCache(QObject *parent = nullptr);
|
||||
|
||||
bool dummyBool() const { return true; }
|
||||
|
||||
signals:
|
||||
void cacheChanged();
|
||||
|
||||
public slots:
|
||||
QString hostName(const QString &address);
|
||||
|
||||
void clear();
|
||||
|
||||
private slots:
|
||||
void handleFinishedLookup(const QString &address,
|
||||
const QString &hostName);
|
||||
|
||||
private:
|
||||
void emitCacheChanged();
|
||||
|
||||
private:
|
||||
HostInfo *m_hostInfo;
|
||||
|
||||
QHash<QString, QString> m_cache;
|
||||
};
|
||||
|
||||
#endif // HOSTINFOCACHE_H
|
Loading…
Reference in New Issue
Block a user