# Extension points — 2dust/v2rayN

> Canonical page: https://codevetter.com/unpack/v2rayn/extension-points

# Extension points — 2dust/v2rayN

Scanned commit 28139853a8087d81e1ac7ffaf7013b937958f5d2 (2026-09-20). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

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. — [v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs#L7-110](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Fmt/FmtHandler.cs#L7-L110) [v2rayN/ServiceLib/Global.cs#L238-265](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Global.cs#L238-L265) [v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs#L10-43](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib.Tests/Fmt/FmtHandlerTests.cs#L10-L43)
- 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). — [v2rayN/ServiceLib/Manager/CoreInfoManager.cs#L104-293](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/CoreInfoManager.cs#L104-L293)
- 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. — [v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Services/CoreConfig/Singbox/CoreConfigSingboxService.cs) [v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs)
- 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. — [v2rayN/ServiceLib/ServiceLib.csproj#L28-57](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ServiceLib.csproj#L28-L57) [v2rayN/ServiceLib/Common/EmbedUtils.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Common/EmbedUtils.cs) [v2rayN/ServiceLib/Global.cs#L18-44](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Global.cs#L18-L44)
- 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. — [v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L44](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L44) [v2rayN/ServiceLib/Handler/CoreConfigHandler.cs#L16-31](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/CoreConfigHandler.cs#L16-L31) [v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L35-36](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L35-L36)
- 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. — [v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L63-98](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L63-L98) [v2rayN/ServiceLib/Models/Entities/RulesItem.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Models/Entities/RulesItem.cs)
- 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. — [v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L418-509](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L418-L509) [v2rayN/ServiceLib/Manager/GroupProfileManager.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Manager/GroupProfileManager.cs)
- 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. — [v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L252-315](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Handler/Builder/CoreConfigContextBuilder.cs#L252-L315) [v2rayN/ServiceLib/Models/Entities/SubItem.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Models/Entities/SubItem.cs)
- 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. — [v2rayN/v2rayN/Common/SimpleViewLocator.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/v2rayN/Common/SimpleViewLocator.cs) [v2rayN/v2rayN.Desktop/Common/SimpleViewLocator.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/v2rayN.Desktop/Common/SimpleViewLocator.cs) [v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L565-631](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L565-L631)
- 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. — [v2rayN/ServiceLib/Events/AppEvents.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Events/AppEvents.cs) [v2rayN/ServiceLib/Events/EventChannel.cs](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Events/EventChannel.cs) [v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L257-315](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs#L257-L315)
- 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. — [v2rayN/ServiceLib/Resx/ResUI.resx](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Resx/ResUI.resx) [v2rayN/ServiceLib/Global.cs#L330-419](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Global.cs#L330-L419)
- 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. — [v2rayN/ServiceLib/Services/UpdateService.cs#L369-413](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Services/UpdateService.cs#L369-L413) [v2rayN/ServiceLib/Global.cs#L185-211](https://github.com/2dust/v2rayN/blob/28139853a8087d81e1ac7ffaf7013b937958f5d2/v2rayN/ServiceLib/Global.cs#L185-L211)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
