fatedier/frp
frp is built around registries. New proxy types plug in through three coordinated tables: proxyConfigTypeMap in pkg/config/v1, server-side RegisterProxyFactory (init() per type in server/proxy), and client-side RegisterProxyFactory (init() in client/proxy). Client connection-handling plugins register via pkg/plugin/client's Register/Create; server hooks come from external HTTP plugin processes managed by pkg/plugin/server. frpc CLI subcommands are generated automatically from the proxy type list. Config extensibility goes through source.Source implementations aggregated by source.Aggregator, and embedding is supported via pkg/virtual.Client plus ServiceOptions hooks (ConnectorCreator, HandleWorkConnCb). Feature gates (pkg/policy/featuregate) guard experimental features.
- server/proxy uses a reflect.Type-keyed factory registry: each type file (tcp.go, udp.go, http.go, https.go, tcpmux.go, stcp.go, sudp.go, xtcp.go) calls RegisterProxyFactory in init(); adding a server proxy type means adding a config type + factory init.
- client/proxy mirrors the pattern: RegisterProxyFactory keyed by configurer reflect.Type, invoked from NewProxy which first builds a BaseProxy with limiter/encryption key/msgTransporter.
- Client plugins register a CreatorFn by name via plugin.Register (panics on duplicate) and are instantiated lazily in BaseProxy.Run when baseCfg.Plugin.Type is set; the Plugin interface is Handle(ctx, *ConnectionInfo) + Close.
- Server plugin ops are an open enum: Manager.Register bins each Plugin by IsSupport(op) into per-op slices for Login, NewProxy, CloseProxy, Ping, NewWorkConn, NewUserConn; new ops require extending the manager dispatch.
- frpc single-proxy subcommands are generated in a loop over proxyTypes, so a new type automatically gains a CLI command and (for stcp/sudp/xtcp) a nested visitor command.
- Config sources are pluggable: source.Aggregator merges a ConfigSource (in-memory/file) with an optional StoreSource; Service consumes aggregator.Load() at boot and on reload, so new persistence backends slot in as Source implementations.
- Embedding hooks: client.ServiceOptions exposes ConnectorCreator (custom transports/virtual clients) and HandleWorkConnCb (intercept work conns); pkg/virtual.Client demonstrates running frpc against an in-process InternalListener.
- pkg/sdk/client provides a programmatic client API for running proxies from Go code rather than config files.
- Admin routes are registered centrally in each Service's registerRouteHandlers, so new endpoints slot into the gorilla/mux subRouter (with auth middleware already applied); server has a separate encoded-path subrouter for /api/v2 names.
- Feature gates: ClientCommonConfig.FeatureGates map plus pkg/policy/featuregate control rollout of features like VirtualNet; reload path validates gate-dependent config against runtime capabilities.
- vhost.Routers + vhost.NewHTTPReverseProxy/NewHTTPSMuxer are the extension seam for HTTP(S) routing behavior; group controllers (TCP/HTTP/HTTPS/TCPMux) encapsulate shared-port load balancing.
- Message/protocol extension: msg.Dispatcher.RegisterHandler maps message structs to handlers on both sides; adding a control message means defining it in pkg/msg and registering handlers in client/control.go and server/control.go.