CodeVetter · Repo Unpack · Extension points
2dust/v2rayN
Extension happens at four levels: (1) protocol support via a new *Fmt class plus entries in FmtHandler's switch/prefix dispatch, Global.ProtocolShares/ProtocolTypes, EConfigType and the two SupportConfigType sets; (2) new cores via a CoreInfo record in CoreInfoManager.InitCoreInfo and Global.CoreUrls; (3) core config generation via the per-concern services under Services/CoreConfig/{Singbox,V2ray} plus embedded Sample templates and FullConfigTemplateItem overrides; (4) UI via shared ViewModels + per-shell SimpleViewLocator view resolution and AppEvents channels. Group-type profiles (PolicyGroup/ProxyChain) and subscription prev/next chains are the built-in composition mechanism.
- Adding a share-URI protocol requires: a new Fmt class in ServiceLib/Handler/Fmt implementing Resolve/ToUri, a switch arm in FmtHandler.ResolveConfig and GetShareUri, and entries in Global.ProtocolShares/ProtocolTypes — FmtHandlerTests enforces the ProtocolShares/factory parity so a missing test fails.
- New proxy cores plug into CoreInfoManager.InitCoreInfo's list of CoreInfo records (CoreExes, Arguments template with {0}=config path, Environment dict, VersionArg/Match for version detection, per-arch DownloadUrl* fields for auto-update).
- Core config generation is decomposed so a single concern (e.g. DNS) can be changed in isolation: CoreConfigSingboxService composes SingboxLog/Inbound/Outbound/Routing/Dns/Ruleset/Statistic/ConfigTemplate services, mirrored by the V2ray set — each is independently instantiable against a CoreConfigContext.
- Embedded Sample resources (ServiceLib/Sample/* registered in ServiceLib.csproj and read via EmbedUtils.GetEmbedText) are the template extension point for default client configs, inbounds, TUN blocks, DNS presets, PAC script, autostart units, sudo/kill scripts, routing presets and root-cert PEMs.
- Users/agents can override generated config wholesale per core type through FullConfigTemplateItem rows fetched in CoreConfigContextBuilder (GetFullConfigTemplateItem) and through per-node EConfigType.Custom/Outbound types that inject literal config/outbound files.
- Routing/DNS customization is data-driven: RoutingItem.RuleSet JSON -> RulesItem list where any OutboundTag not in Global.OutboundTags resolves to a profile by remarks and is injected into AllProxiesMap — enabling per-rule per-node routing without code changes; DNSItem rows store per-core normal/tun DNS JSON.
- Group-type profiles compose nodes without new code: EConfigType.PolicyGroup/ProxyChain nodes carry ProtocolExtraItem.ChildItems, traversed recursively by CoreConfigContextBuilder.TraverseGroupNodeAsync with cycle detection via ancestor/visited sets, and GroupProfileManager resolves child IndexIds.
- Subscriptions gain proxy chains declaratively: SubItem.PrevProfile/NextProfile name profiles by remarks which BuildSubscriptionChainNodeAsync wraps into a virtual 'inner-<guid>' ProxyChain node around the selected node.
- New UI screens follow the ReactiveUI + SimpleViewLocator convention: create a ViewModel in ServiceLib/ViewModels, a View per shell (v2rayN/Views/*.xaml, v2rayN.Desktop/Views/*.axaml), wire commands through ReactiveCommand.CreateFromTask, dialogs through AppManager.Instance.WindowDialog.ShowDialogAsync, and notifications through NoticeManager.
- AppEvents/EventChannel is the extension point for cross-VM signaling — new events are added as static EventChannel<T> fields and consumed via .AsObservable().ObserveOn(RxSchedulers.MainThreadScheduler).SubscribeAsync.
- New user-facing strings go into ServiceLib/Resx/ResUI.resx (plus satellites); new global option lists (e.g. fingerprints, networks, mux protocols, subconvert endpoints, geo sources) are centralized as public static lists in Global.cs.
- UpdateService's download-source indirection (ConstItem.GeoSourceUrl/SrsSourceUrl/SubConvertUrl with Global.* defaults) is a designed extension seam for alternate geo/rule-set/subconvert providers, including the Russia and Iran preset sources.