The refactored code keeps the 1.5.x Steam/TCP/TUN behavior and wire formats, but separates policy from transport and presentation.
modules/ConnectTool (QML module + C++ backing plugin)
└─ App (typed singleton)
├─ SessionController / LobbyController / SocialController
├─ ChatController / NetworkController / UpdaterController
└─ ApplicationRuntime
├─ integrations/steam (SDK adapters)
├─ network (protocol, TCP multiplexing, VPN negotiation)
├─ platform (audio, TUN, OS services)
└─ services/UpdateController
modules/ConnectTool/ versioned QML URI, backing types, pages, assets
src/application/ process orchestration and application services
src/domain/ SDK- and framework-independent value types
src/network/ protocol, transport, and VPN core
src/integrations/steam/ the only Steamworks adapter layer
src/platform/ TUN, audio, and operating-system implementations
deps/cmake/ dependency discovery and pinned dependency fixes
deps/vendor/ vendored source dependencies
tests/ protocol, compatibility, and boundary tests
Every first-party layer is a separate CMake target. connecttool_ui is a
static qt_add_qml_module() target with its own ConnectToolPlugin, matching
the way Qcm.Material is consumed. The executable contains startup and
diagnostics only; it imports and links the module instead of compiling QML and
controllers directly.
src/domain/contains strongly typed identifiers. Different identifier kinds cannot be mixed accidentally.src/network/protocol/andsrc/network/vpn/are Steam-independent core boundaries. They usestd::span,std::expected, concepts, constrained templates, and explicit byte order instead of packed-pointer casts.src/network/tcp/ReliableChannelis the transport port.MultiplexSessiondepends on that interface, whileSteamReliableChannellives insrc/integrations/steam/; no Steamworks type crosses into the core target.src/integrations/steam/adapts the core to Steam Networking. Ownership is explicit (unique_ptrfor owned services, raw pointers only for non-owning SDK handles).modules/ConnectTool/controllers/application_controller.*is the narrow, typed API consumed by QML. QML does not reach intoApplicationRuntimedirectly.src/application/services/update_controller.*owns update checking and downloads independently of room/network state.src/platform/system/platform_environment.*isolates Windows, Linux, and macOS privilege and Steam discovery workarounds from orchestration.- Windows TUN configuration is isolated in
src/platform/tun/windows_network_config.*and uses IP Helper APIs for addresses, routes, MTU, and interface state. Firewall rules use the Windows Firewall COM API. Joining a room therefore launches no command shell, PowerShell process,route.exe, ornetsh.exe. modules/ConnectTool/uses the pinnedQcm.Materialmodule for Material Design 3 tokens, controls, icons, motion, and shaders.Main.qmlowns only the application shell, theme bootstrap, navigation, dialogs, and snackbars.- The room surface is split into
ConnectionPanel,ChatPanel, andPeoplePanel; message/member/friend delegates are separate types. Page code binds only to the typedAppfaçade and contains no transport policy.
The binary packet layouts remain compatible with ConnectTool 1.5.x. Golden-byte
tests lock those layouts in place. Decoders reject truncated, oversized, or
unknown frames before exposing payload spans, and payload structs are copied
with alignment-safe operations. Packet-level IP conflict resolution now emits
the defined ForcedReleasePayload; 1.5.x incorrectly relabeled an entire IP
packet as a forced-release message.
Long-running workers use std::jthread and stop tokens. TCP client lifetime is
held in a shared registry so asynchronous close callbacks never dereference a
destroyed server. Each client also owns a serialized write queue, so asynchronous
writes never overlap. The server has a single read owner; this removes the
previous double-read path between TcpTunnelServer and MultiplexSession.
Use the CMake presets from the repository root:
cmake --preset core-tests
cmake --build --preset core-tests
ctest --preset core-testsThe core preset compiles connecttool_domain, connecttool_protocol, and
connecttool_network without locating Steamworks. The
architecture-boundaries test rejects Qt/Steam imports in these directories
and rejects parent-relative first-party includes.
With a Steamworks SDK available, dev also builds the application and runs the
offscreen QML smoke test. connecttool_ui_qmllint statically checks every
application QML binding without treating warnings in the pinned dependency as
first-party failures. The three platform CI jobs run both checks before packaging.
For visual regression checks, an application build can render any primary page offscreen without changing normal startup behavior:
QT_QPA_PLATFORM=offscreen QT_QUICK_BACKEND=software \
./connecttool-qt --qml-page=0 --qml-screenshot=/tmp/connecttool-room.pngThe release preset builds connecttool_protocol_benchmark. Run it on the same
machine before and after transport changes; it reports encode/decode operations
per second for a 1,200-byte payload. End-to-end throughput should still be
measured with the existing iperf3 procedure because Steam relay selection and
peer latency dominate real sessions.