UI: Add IpListModel & HostInfoCache.

This commit is contained in:
Nodir Temirkhodjaev 2017-11-17 15:33:14 +05:00
parent 39bec283c7
commit cf1fee6d6c
13 changed files with 201 additions and 147 deletions

View File

@ -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 \

View File

@ -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");
}

View File

@ -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) {

View File

@ -25,6 +25,9 @@ signals:
public slots:
QAbstractItemModel *appBlockedModel() const;
QAbstractItemModel *ipListModel(const QString &appPath) const;
void clearModels() const;
void setLogReadingEnabled(bool enabled);

View File

@ -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,10 +54,16 @@ void AppBlockedModel::addLogEntry(const LogEntryBlocked &logEntry)
ipList.prepend(ipText);
if (isNewApp) {
insert(appPath);
} else if (ipList.size() > IP_LIST_COUNT_MAX) {
const QString oldIpText = ipList.takeLast();
ipSet.remove(oldIpText);
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);
}
}
}

View File

@ -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

View File

@ -0,0 +1,11 @@
#include "iplistmodel.h"
IpListModel::IpListModel(QObject *parent) :
StringListModel(parent)
{
}
void IpListModel::setAppPath(const QString &appPath)
{
m_appPath = appPath;
}

View 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

View File

@ -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);

View File

@ -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);

View File

@ -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 || ""
}
}
}

View 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();
}

View 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