11 KiB
Project Structure and Source Search
Unless noted otherwise, run commands from ShadowsocksX-NG2/; paths in this document are relative to that directory.
Project structure
-
project.yml— XcodeGen project definition and single source of truth..xcodeproj,App/Resources/Info.plist,*.entitlements, andTests/Info.plistare generated and gitignored. Change the project structure inproject.yml, then regenerate the project. -
App/— app target source code (a SwiftUI menu bar app withLSUIElement). Directories define layers; files within each layer are grouped by feature:Composition/— composition root and process lifecycle:@main, dependency assembly, app form, and window activation strategy.Application/— application layer without SwiftUI views:*Workflow/workflow modules (UI-facing interfaces and implementation collaborators), theProxyRuntime/runtime-controller family and fact projections, andServices/for LaunchAgent, login item, helper, and firewall.Presentation/— cross-feature presentation: error presentation and state models shared by multiple views.UI/— view layer, organized by subview (Workspace/,Home/,Servers/,Subscriptions/,Rules/,Settings/,Diagnostics/, andStatusMenu/);Servers/Plugin/contains plugin-management views.PlatformEffects/— platform-effect seams (protocols and AppKit adapters; test doubles are inTests/Support/); access to system frameworks is centralized here.Resources/— generatedInfo.plistand entitlements, plus checked-inAssets.xcassetsand*.xcstrings.
Tests/Architecture/SkeletonTests.swiftenforces layer boundaries with an allowlist guard that scans onlyApp/UI/. The view layer must not reference runtime controllers, workflow implementation collaborators, or raw directory/credential storage types. New runtime adapters belong inApplication/, which is outside the scan scope and needs no exemption. Note that XcodeGen includes any non-source file underApp/in the Resources build phase and signs it into the bundle, so do not put documents there (project.ymlexcludes**/*.md). See ADR-0029 for the layer and theme organization, why the guard uses an allowlist, and the XcodeGen constraint. -
Agent/— standalone background-supervision executable, installed inContents/MacOS/and kept running by a LaunchAgent. It reads only non-secretagent-supervision.json, switches stable configuration and ACL links, and launches and supervisessslocal; it does not parse sslocal configuration or LAN credentials. See ADR-0037 and ADR-0038 for release and failure handling, and ADR-0043 for one-way configuration output from the GUI. -
LaunchAgent/— registration manifest forSMAppService.agent(plistName:), installed inContents/Library/LaunchAgents/.ProgramArgumentsuses bundle-relative paths, which launchd resolves from the registered app's bundle location. -
Domain/— domain core for the configuration catalog tree, credential references, and persistence (spec #21 D3/D5), independent of the UI. Directories define topics; there are no flat files at the root. Child-directory boundaries follow the sections in the glossary:Catalog/— configuration catalog tree, structural invariant errors, catalog file storage, node and credential identities, andSsUriforss://encoding and decoding.Subscription/— subscription document parsing, fetching, subscription records, and refresh failures.Rules/— proxy modes, rule identity and matching, bundled rule snapshots, rule collections/browsing/analysis, and offline rule tests;Rules/Custom/contains edit drafts, validation, and storage for user-defined rules.Runtime/— proxy runtime services: runtime documents and listener settings, ACLs and deployment receipts, paths, atomic writes, file storage, logs and events (SystemLogunified-log emitter,LogLineunified-log line, and sslocal-output intake), plus endpoint/port/socket probes.Activation/— activation-candidate validation, activation state machine, andRuntimeConfiguration.Settings/— proxy-listening configuration file, independent proxy-control preferences, in-memory snapshots of runtime calculations, and silent-launch preference.SystemProxy/— typed system-proxy configuration, property-list mapping, planner, privileged-helper XPC contract/request engine, and helper-side log events.Plugin/— managed plugins, user-plugin mappings, and plugin security inspection.Credentials/,LegacyImport/, andDiagnostics/— master-key storage and encrypted-file commits, legacy import, and diagnostic reports.
Cross-process contracts are compiled into other targets file by file: nine files from
Runtime/andSettings/ApplicationSupportPaths.swiftare also compiled into the wrapper (RuntimePaths,RuntimeSupervision,RuntimeLog,SystemLog,LogLine,SslocalOutputIntake, and others); all seven files fromSystemProxy/, together withRuntime/SystemLog.swift, are compiled into the privileged helper (helper logs go only to the unified log; see ADR-0047). These 18 entries are explicit paths inproject.yml. Moving a file underDomain/requires updating the project definition too; otherwise,xcodegen generatefails immediately because a file is missing. The layout guard (DomainLayoutTestsinTests/Architecture/SkeletonTests.swift) asserts that there are no flat.swiftfiles at the root and that the tree contains only.swiftfiles. XcodeGen would otherwise include non-source files in the Resources build phase and sign them into the bundle. -
Tests/— unit-test target, run with theShadowsocksX-NG2scheme. Directories define topics; there are no flat test files at the root:Architecture/— guards for cross-cutting project constraints (layers and layout, platform-effect seams, window entry points, and manifest completeness). They scan source or build artifacts without driving behavior.TestSupport/— regression tests for test-wait and cleanup helpers.Support/— fixtures, doubles, and helpers, with no test cases (CatalogFixtures,ProxyRuntimeFixture,SystemProxyFakes,AppArtifact,TestSourceTree, and others).Agent/,Activation/,Catalog/(workflow tests are inCatalog/Workflow/),Subscription/,Rules/(custom rules are inRules/Custom/),ProxyRuntime/,ProxyControl/,Runtime/,Settings/,SystemProxy/,Plugin/,Diagnostics/,Credentials/,Workspace/, andServers/— feature-domain tests aligned with production domain topics and*Workflowboundaries.Smoke/— real-process smoke tests in a separate target and scheme (task test:smoke).Fixtures/RuleSnapshots/— generated fixtures for bundled rule snapshots, distributed as folder resources in the test bundle and read byGeneratedRuleSnapshotTestswithsubdirectory:.
When an assertion needs to read the source tree (
Vendor/manifests,App/, orDomain/), useSupport/TestSourceTree.swiftto locateShadowsocksX-NG2/by walking up from#filePath. Do not hard-code the number of parent directories: test files are at different depths, and a move could make the path silently point elsewhere.TestsLayoutTestsonly asserts that there are no flat.swiftfiles at the root. This is weaker than theDomain/guard because the rootInfo.plistand JSON underFixtures/are required.Tests/Support/AppArtifact.swiftis also compiled into the Smoke target and is an explicit file path inproject.yml; update it when moving the file. -
Vendor/<name>/manifest.json— pinned supply-chain manifest for an external binary (tag, asset URL, asset SHA-256, location inside the bundle, and signing identifier). The binary itself and.fetched.sha256stamp are build cache and are not checked in. -
Vendor/rules/geolocation-cn/— bundled snapshot of Chinese domain rules (issue #63):snapshot.json(normalized rules, metadata, and loss report),manifest.json(upstream version and snapshot SHA-256), andNOTICE(license and attribution). Normal builds read only the local snapshot; they never fetch or convert rules. -
Vendor/rules/china-ipv4/— bundled snapshot of Chinese IPv4 CIDRs considered for direct routing (issue #64): the same three files, sourced from a pinned commit ofchina.txtin gaoyifan/china-operator-ip. The rule-modeproxy_allACL includes both Chinese-domain and IPv4-CIDR direct-routing candidates. -
Vendor/rules/gfwlist/— bundled snapshot of GFWList proxy candidates (issue #65): the same three files, sourced from the official Base64 AutoProxygfwlist.txtin gfwlist/gfwlist at a pinned commit. Domain anchors are converted to suffix matching. Eligible URL prefixes with an empty or root path are converted to exact-domain matching. Thebypass_allACL for “direct when unmatched” includes these proxy candidates. -
Scripts/— supply-chain scripts (see External binary supply chain) and packaging-gate assertions.update-geolocation-cn.sh,update-china-ipv4.sh, andupdate-gfwlist.share explicit maintenance actions that fetch pinned upstream versions and convert them.verify-rule-snapshots.shchecks snapshot integrity offline before a build.
Source search
First use rg --files to locate files based on the directory layers above, then search content in the relevant directory or file type. If there are no matches, expand the search gradually. Run these commands from ShadowsocksX-NG2/:
# Find the external-binary version and source by locating its manifest first.
rg --files Vendor/sslocal -g 'manifest.json'
# Search relevant Swift source for runtime responsibilities.
rg -n -g '*.swift' 'sslocal|reload' Agent Domain/Runtime App/Application/ProxyRuntime
# List files matching a rule term before displaying matches.
rg -l 'keyword' Vendor/rules Tests/Fixtures/RuleSnapshots
# Display matching lines while limiting long lines and retaining match context.
rg -n -M 300 'keyword' Vendor/rules
Vendor/rules/*/snapshot.json and Tests/Fixtures/RuleSnapshots/*.json are generated, single-line JSON files. -M 300 limits the displayed length of a line in bytes; it does not limit total output. -m and head -n limit line counts but do not prevent one long line from producing too much output. To inspect complete rules, locate the specific snapshot and read the relevant JSON fields. Manifests and NOTICE files remain in their respective Vendor directories and can be searched separately as needed.