Files
ginuerzhandClaude 30ba6d64a5 x: add matcher + probe to chainGroup with independent entry marker
chainGroup now selects chains in two stages: a matcher filter (by host/network)
builds an eligible pool, then the group selector applies FailFilter + strategy.
Each entry carries its own failure marker so chain-level probe marking is
independent of node-level failCodes markers (probe Reset() can't undo a node
failCodes Mark()).

Config gains ChainGroupEntry (chain/matcher/probe) replacing the old []string,
with a mapstructure decode hook preserving backward-compatible "chains: [a, b]"
string lists and time.Duration string parsing. Probe goroutines run per-entry
and mark the entry on failure.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-28 21:20:34 +08:00

45 lines
1.4 KiB
Go

package chain
import (
"context"
"github.com/go-gost/core/chain"
"github.com/go-gost/core/routing"
"github.com/go-gost/core/selector"
)
// ChainEntry wraps a chain.Chainer with an optional matcher and an independent
// failure marker for chain-level probe tracking. The entry's marker is
// separate from any node-level markers inside the chain so that probe
// Reset() cannot undo a node-level failCodes Mark().
type ChainEntry struct {
chainer chain.Chainer
matcher routing.Matcher
probe *chain.ProbeConfig
marker selector.Marker
}
// NewChainEntry creates a ChainEntry. matcher may be nil (unconditional
// catch-all). probe may be nil (no health check for this entry).
func NewChainEntry(c chain.Chainer, m routing.Matcher, probe *chain.ProbeConfig) *ChainEntry {
return &ChainEntry{
chainer: c,
matcher: m,
probe: probe,
marker: selector.NewFailMarker(),
}
}
// Route implements chain.Chainer so the entry can be passed directly to the
// group selector. The selector's FailFilter reads Marker() from the entry,
// not from the underlying chain — this keeps probe-driven marking independent
// of any node-level markers.
func (e *ChainEntry) Route(ctx context.Context, network, address string, opts ...chain.RouteOption) chain.Route {
return e.chainer.Route(ctx, network, address, opts...)
}
// Marker implements selector.Markable.
func (e *ChainEntry) Marker() selector.Marker {
return e.marker
}