This document describes the architecture of paqetN, a Qt 6 desktop application for managing paqet proxy configurations.
paqetN follows a Model-View-Controller (MVC) architecture with Qt/QML:
- Model: C++ backend classes handling business logic and data
- View: QML UI components using FluentUI design system
- Controller:
PaqetControllerorchestrating interactions between models and views
- Qt 6.8+: Application framework
- QML: Declarative UI
- C++17: Backend implementation
- FluentUI: Microsoft Fluent Design System for Qt
- QuaZip: Cross-platform ZIP archive library
- CMake: Build system
- Qt Test: Testing framework
┌─────────────────────────────────────────────────────────────┐
│ QML UI Layer │
│ (Main.qml, HostsPage, LogPage, ConfigEditorDialog, etc.) │
└────────────────────┬────────────────────────────────────────┘
│ Q_PROPERTY / Q_INVOKABLE
▼
┌─────────────────────────────────────────────────────────────┐
│ PaqetController │
│ (Orchestrator / Facade) │
└──┬──────────┬──────────┬──────────┬──────────┬──────┬──────┘
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌──────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌──────┐ ┌────────┐
│Config│ │ Config │ │ Paqet │ │ Log │ │Settings│ │Update │
│List │ │Repo. │ │ Runner │ │ Buffer │ │Repo. │ │Manager│
│Model │ │ │ │ │ │ │ │ │ │ │
└──────┘ └────────┘ └────────┘ └────────┘ └────────┘ └───┬───┘
│ │ │ │
│ │ └─────> QProcess (paqet) │
│ │ │
│ └─────> JSON Persistence │
│ │
└─────> QAbstractListModel │
│
┌───────────────────────┴────┐
▼ ▼
GitHub API QuaZip/ZIP
(Update Check) Extraction
File: src/PaqetController.h/cpp
The main orchestrator that:
- Exposes unified API to QML via
Q_PROPERTYandQ_INVOKABLE - Manages config lifecycle (add, edit, delete, import, export)
- Controls paqet process (start, stop, status)
- Coordinates between ConfigRepository, ConfigListModel, PaqetRunner, LogBuffer
- Handles clipboard operations and file I/O
Key Properties:
configModel: ConfigListModel for UI bindingcurrentConfigId: Currently selected/running configisConnected: Proxy connection statelogs: LogBuffer for real-time log viewing
Key Methods:
connectConfig(id): Start paqet with specified configdisconnect(): Stop paqet processtestLatency(id): Check proxy latencyimportFromClipboard(),importFromFile(): Config importexportConfigAsLink(),exportConfigAsYaml(): Config export
File: src/ConfigRepository.h/cpp
Manages persistent storage of configurations:
- JSON serialization/deserialization
- CRUD operations (add, update, remove, get)
- Loads from
QStandardPaths::AppDataLocation/configs.json - Thread-safe file operations
- Emits signals on data changes
File: src/ConfigListModel.h/cpp
QAbstractListModel implementation for QML:
- Exposes configs as Qt model with roles (configId, name, serverAddr, group, etc.)
- Supports dynamic updates (add, remove, update operations)
- Integrates with QML ListView, GridView, Repeater
- Role-based data access for QML bindings
Roles:
- ConfigIdRole, NameRole, ServerAddrRole, GroupRole
- KcpBlockRole, KcpModeRole, LatencyRole, etc.
File: src/PaqetRunner.h/cpp
Manages paqet process lifecycle:
QProcesswrapper for paqet binary- Starts paqet with config parameters
- Captures stdout/stderr to LogBuffer
- Process state monitoring
- Graceful shutdown handling
File: src/LogBuffer.h/cpp
Circular buffer for log management:
- Stores stdout/stderr from paqet
- Fixed-size buffer (prevents memory bloat)
- Real-time log updates via signals
- Export to file, clear, copy operations
- Word wrap support for UI
File: src/SettingsRepository.h/cpp
Application settings persistence:
- Uses QSettings (organization: paqetN, app: paqetN)
- Theme preference (dark/light/system)
- SOCKS port, connection check URL
- Log level, paqet binary path
- UI preferences (window size, etc.)
File: src/LatencyChecker.h/cpp
Proxy latency testing:
- Connects through SOCKS5 proxy
- HTTP GET request to check URL
- Measures round-trip time
- Async operation with timeout
File: src/SingleInstanceGuard.h/cpp
Ensures single app instance:
- Uses
QSharedMemoryfor instance detection - Prevents multiple instances running simultaneously
File: src/UpdateManager.h/cpp
Manages application and binary updates:
- GitHub API Integration: Checks latest releases for paqetN and paqet
- Version Detection: Detects installed paqet version via
paqet versioncommand - Binary Download: Downloads paqet from GitHub releases with progress tracking
- ZIP Extraction: Uses QuaZip (via ZipExtractor) for cross-platform archive extraction
- Auto-Update: Self-update mechanism for paqetN with .exe replacement
- Settings Integration: Auto-download, auto-check, and auto-update preferences
Key Features:
- Async downloads with QNetworkAccessManager
- Platform detection (Windows/macOS/Linux)
- Progress signals for UI updates
- Error handling and retry logic
- Skips example files during extraction
File: src/ZipExtractor.h
Cross-platform ZIP extraction:
- QuaZip Integration: Uses JlCompress for reliable ZIP handling
- All Compression Methods: Supports stored, deflate, and other ZIP formats
- Large File Support: Handles multi-megabyte binaries
- Auto-Cleanup: Removes unwanted files (e.g., example/ folder)
File: src/PaqetConfig.h/cpp
Configuration data model:
- Represents a single paqet config
- Serialization: JSON, YAML, URI (
paqet://...) - Validation and parsing
- Round-trip conversion between formats
All UI components use FluentUI from 3rdparty/FluentUI/:
- Theme System: FluTheme (dark/light modes, colors, typography)
- Components: FluButton, FluTextBox, FluComboBox, FluScrollBar, etc.
- Navigation: FluWindow + FluNavigationView (sidebar navigation)
- Dialogs: FluPopup base for modals
- Icons: FluentIcons enumeration
File: Main.qml
Root window using FluWindow:
- FluNavigationView in Compact mode
- Pages: Hosts, Logs, Settings
- NoStack navigation (no page history)
- Custom title bar with theme toggle
- Acrylic effects (Windows only)
File: HostsPage.qml
Main config management page:
- Card grid layout for configs (grouped by
groupfield) - GroupCard components for each group
- DetailPanel for selected config (right sidebar)
- Actions: Connect, Test, Edit, Delete, Add, Import, Export
File: LogPage.qml
Full-page log viewer:
- Real-time log display from LogBuffer
- Word wrap toggle
- Actions: Copy all, Export to file, Clear
- Monospace font, auto-scroll to bottom
File: SettingsPage.qml
Application settings (replaces old SettingsDialog):
- Theme selection (Dark, Light, System)
- SOCKS port configuration
- Connection check URL
- Log level (Debug, Info, Warn, Error)
- Optional paqet binary path
Collapsible card for a group of configs:
- Displays group name with expand/collapse
- Contains HostCard grid
- Group rename functionality
- Fluent card styling
Individual config display card:
- Config name, server address
- Status indicator (connected, idle)
- Latency display
- Click to select, shows in DetailPanel
Right sidebar panel:
- Displays selected config details
- Actions: Connect, Test, Edit, Delete
- Shows connection status
- Export options (link, YAML)
Modal dialog for config add/edit:
- FluPopup-based modal
- Form fields: name, server, port, password, KCP settings, etc.
- Validation and save/cancel actions
User clicks "Add" → ConfigEditorDialog opens → User fills form →
Click "Add" → PaqetController.addConfig(data) → ConfigRepository.add(config) →
Emits configAdded signal → ConfigListModel.add(config) → UI updates
User clicks "Connect" on config → PaqetController.connectConfig(id) →
ConfigRepository.get(id) → PaqetRunner.start(config) → QProcess starts →
Stdout/stderr → LogBuffer.append() → UI log updates → Status: Connected
User clicks "Import from Clipboard" → PaqetController.importFromClipboard() →
QClipboard.text() → PaqetConfig.fromString(text) → Parse (URI or JSON) →
ConfigRepository.add(config) → ConfigListModel updates → UI shows new config
Location: QStandardPaths::AppDataLocation/configs.json
Format:
{
"configs": [
{
"id": "unique-uuid",
"name": "My Server",
"serverAddr": "example.com",
"serverPort": 8080,
"password": "secret",
"group": "Production",
"localAddr": "127.0.0.1",
"localPort": 1284,
"kcpBlock": "aes",
"kcpMode": "fast",
"kcpMtu": 1350,
"kcpSndwnd": 1024,
"kcpRcvwnd": 1024,
"kcpDatashard": 10,
"kcpParityshard": 3,
"latency": 0
}
]
}Stored via QSettings (platform-specific location):
- Windows: Registry or INI file
- Linux:
~/.config/paqetN/paqetN.conf - macOS:
~/Library/Preferences/paqetN.plist
Directory: tests/
Test Files:
tst_paqetconfig.cpp: PaqetConfig parsing, serializationtst_configrepository.cpp: Repository CRUD operationstst_logbuffer.cpp: Log buffer operationstst_configlistmodel.cpp: Qt model interfacetst_settingsrepository.cpp: Settings persistencetst_controller.cpp: Controller orchestrationtst_ui.cpp: UI smoke tests (QML loading)
- Uses Qt Test framework
- Run via
ctest -Vor direct executable - Mocks: Temporary directories for configs.json
- Coverage: ~90% of backend code
- Root
CMakeLists.txt: Main project configuration - FluentUI:
add_subdirectory(3rdparty/FluentUI/src) - QML module:
qt_add_qml_module(apppaqetN URI paqetN) - Tests: Separate executable with shared sources
apppaqetN: Main executabletst_paqetn: Test executablefluentuiplugin: FluentUI library
- Main Thread: UI (QML) and Qt event loop
- QProcess Thread: paqet subprocess I/O (managed by Qt)
- Network Operations: Async via Qt signals/slots (LatencyChecker)
- File I/O: Synchronous on main thread (configs.json is small)
- Facade Pattern: PaqetController as unified API for QML
- Repository Pattern: ConfigRepository, SettingsRepository for data access
- Observer Pattern: Qt signals/slots for event propagation
- Model-View Pattern: ConfigListModel for Qt Model/View
- Factory Pattern: PaqetConfig parsing from multiple formats
- Passwords: Stored in plaintext in configs.json (consider encryption in future)
- Single Instance: Prevents multiple instances (avoid port conflicts)
- Input Validation: Config validation before process start
- Process Isolation: paqet runs as separate process (limited damage if compromised)
- Password Encryption: Encrypt passwords in configs.json
- Plugin System: Support for custom proxy protocols
- Config Sync: Cloud sync for configs (optional)
- Logging Service: Separate thread for log processing
- Dependency Injection: Improve testability with DI framework
- Qt6::Quick, Qt6::QuickControls2
- Qt6::Network
- Qt6::Widgets (for QSystemTrayIcon potential)
- Qt6::Svg (for icons)
- Qt6::PrintSupport (FluentUI requirement)
- Qt5Compat (FluentUI GraphicalEffects)
- FluentUI:
3rdparty/FluentUI/(zhuzichu520/FluentUI)
- paqet: Proxy binary (not bundled, user-provided or built separately)
- Uses MSYS2/MinGW for build
- Requires Qt's MinGW, NOT system GCC
- Acrylic effects available (FluAcrylic)
- Standard Qt build process
- XDG directories for config storage
- App bundle packaging
- macOS-specific QSettings storage
For build instructions, see BUILDING.md. For development workflow, see DEVELOPMENT.md.