add chain hop
This commit is contained in:
parent
1a1c038fd7
commit
5237f79740
@ -20,6 +20,7 @@ type options struct {
|
|||||||
matchers []string
|
matchers []string
|
||||||
fileLoader loader.Loader
|
fileLoader loader.Loader
|
||||||
redisLoader loader.Loader
|
redisLoader loader.Loader
|
||||||
|
httpLoader loader.Loader
|
||||||
period time.Duration
|
period time.Duration
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
@ -56,6 +57,12 @@ func RedisLoaderOption(redisLoader loader.Loader) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HTTPLoaderOption(httpLoader loader.Loader) Option {
|
||||||
|
return func(opts *options) {
|
||||||
|
opts.httpLoader = httpLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LoggerOption(logger logger.Logger) Option {
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.logger = logger
|
opts.logger = logger
|
||||||
@ -200,6 +207,16 @@ func (p *admission) load(ctx context.Context) (patterns []string, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.options.httpLoader != nil {
|
||||||
|
r, er := p.options.httpLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
p.options.logger.Warnf("http loader: %v", er)
|
||||||
|
}
|
||||||
|
if v, _ := p.parsePatterns(r); v != nil {
|
||||||
|
patterns = append(patterns, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p.options.logger.Debugf("load items %d", len(patterns))
|
p.options.logger.Debugf("load items %d", len(patterns))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
18
auth/auth.go
18
auth/auth.go
@ -17,6 +17,7 @@ type options struct {
|
|||||||
auths map[string]string
|
auths map[string]string
|
||||||
fileLoader loader.Loader
|
fileLoader loader.Loader
|
||||||
redisLoader loader.Loader
|
redisLoader loader.Loader
|
||||||
|
httpLoader loader.Loader
|
||||||
period time.Duration
|
period time.Duration
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
@ -47,6 +48,12 @@ func RedisLoaderOption(redisLoader loader.Loader) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HTTPLoaderOption(httpLoader loader.Loader) Option {
|
||||||
|
return func(opts *options) {
|
||||||
|
opts.httpLoader = httpLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LoggerOption(logger logger.Logger) Option {
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.logger = logger
|
opts.logger = logger
|
||||||
@ -179,6 +186,17 @@ func (p *authenticator) load(ctx context.Context) (m map[string]string, err erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if p.options.httpLoader != nil {
|
||||||
|
r, er := p.options.httpLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
p.options.logger.Warnf("http loader: %v", er)
|
||||||
|
}
|
||||||
|
if auths, _ := p.parseAuths(r); auths != nil {
|
||||||
|
for k, v := range auths {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p.options.logger.Debugf("load items %d", len(m))
|
p.options.logger.Debugf("load items %d", len(m))
|
||||||
return
|
return
|
||||||
|
@ -20,6 +20,7 @@ type options struct {
|
|||||||
matchers []string
|
matchers []string
|
||||||
fileLoader loader.Loader
|
fileLoader loader.Loader
|
||||||
redisLoader loader.Loader
|
redisLoader loader.Loader
|
||||||
|
httpLoader loader.Loader
|
||||||
period time.Duration
|
period time.Duration
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
@ -56,6 +57,12 @@ func RedisLoaderOption(redisLoader loader.Loader) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HTTPLoaderOption(httpLoader loader.Loader) Option {
|
||||||
|
return func(opts *options) {
|
||||||
|
opts.httpLoader = httpLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LoggerOption(logger logger.Logger) Option {
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.logger = logger
|
opts.logger = logger
|
||||||
@ -195,6 +202,15 @@ func (bp *bypass) load(ctx context.Context) (patterns []string, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if bp.options.httpLoader != nil {
|
||||||
|
r, er := bp.options.httpLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
bp.options.logger.Warnf("http loader: %v", er)
|
||||||
|
}
|
||||||
|
if v, _ := bp.parsePatterns(r); v != nil {
|
||||||
|
patterns = append(patterns, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bp.options.logger.Debugf("load items %d", len(patterns))
|
bp.options.logger.Debugf("load items %d", len(patterns))
|
||||||
return
|
return
|
||||||
|
125
chain/hop.go
125
chain/hop.go
@ -2,15 +2,25 @@ package chain
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-gost/core/bypass"
|
"github.com/go-gost/core/bypass"
|
||||||
"github.com/go-gost/core/chain"
|
"github.com/go-gost/core/chain"
|
||||||
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/core/selector"
|
"github.com/go-gost/core/selector"
|
||||||
|
"github.com/go-gost/x/internal/loader"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HopOptions struct {
|
type HopOptions struct {
|
||||||
bypass bypass.Bypass
|
bypass bypass.Bypass
|
||||||
selector selector.Selector[*chain.Node]
|
selector selector.Selector[*chain.Node]
|
||||||
|
fileLoader loader.Loader
|
||||||
|
httpLoader loader.Loader
|
||||||
|
redisLoader loader.Loader
|
||||||
|
period time.Duration
|
||||||
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type HopOption func(*HopOptions)
|
type HopOption func(*HopOptions)
|
||||||
@ -27,9 +37,41 @@ func SelectorHopOption(s selector.Selector[*chain.Node]) HopOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FileLoaderHopOption(fileLoader loader.Loader) HopOption {
|
||||||
|
return func(opts *HopOptions) {
|
||||||
|
opts.fileLoader = fileLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RedisLoaderHopOption(redisLoader loader.Loader) HopOption {
|
||||||
|
return func(opts *HopOptions) {
|
||||||
|
opts.redisLoader = redisLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HTTPLoaderHopOption(httpLoader loader.Loader) HopOption {
|
||||||
|
return func(opts *HopOptions) {
|
||||||
|
opts.httpLoader = httpLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReloadPeriodHopOption(period time.Duration) HopOption {
|
||||||
|
return func(opts *HopOptions) {
|
||||||
|
opts.period = period
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoggerHopOption(logger logger.Logger) HopOption {
|
||||||
|
return func(opts *HopOptions) {
|
||||||
|
opts.logger = logger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type chainHop struct {
|
type chainHop struct {
|
||||||
nodes []*chain.Node
|
nodes []*chain.Node
|
||||||
options HopOptions
|
options HopOptions
|
||||||
|
cancelFunc context.CancelFunc
|
||||||
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChainHop(nodes []*chain.Node, opts ...HopOption) chain.Hop {
|
func NewChainHop(nodes []*chain.Node, opts ...HopOption) chain.Hop {
|
||||||
@ -40,10 +82,21 @@ func NewChainHop(nodes []*chain.Node, opts ...HopOption) chain.Hop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &chainHop{
|
ctx, cancel := context.WithCancel(context.TODO())
|
||||||
nodes: nodes,
|
|
||||||
options: options,
|
hop := &chainHop{
|
||||||
|
nodes: nodes,
|
||||||
|
options: options,
|
||||||
|
cancelFunc: cancel,
|
||||||
}
|
}
|
||||||
|
if err := hop.reload(ctx); err != nil {
|
||||||
|
options.logger.Warnf("reload: %v", err)
|
||||||
|
}
|
||||||
|
if hop.options.period > 0 {
|
||||||
|
go hop.periodReload(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hop
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *chainHop) Nodes() []*chain.Node {
|
func (p *chainHop) Nodes() []*chain.Node {
|
||||||
@ -85,3 +138,61 @@ func (p *chainHop) Select(ctx context.Context, opts ...chain.SelectOption) *chai
|
|||||||
}
|
}
|
||||||
return nodes[0]
|
return nodes[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *chainHop) periodReload(ctx context.Context) error {
|
||||||
|
period := p.options.period
|
||||||
|
if period < time.Second {
|
||||||
|
period = time.Second
|
||||||
|
}
|
||||||
|
ticker := time.NewTicker(period)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
if err := p.reload(ctx); err != nil {
|
||||||
|
p.options.logger.Warnf("reload: %v", err)
|
||||||
|
// return err
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chainHop) reload(ctx context.Context) error {
|
||||||
|
_, err := p.load(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *chainHop) load(ctx context.Context) (data []byte, err error) {
|
||||||
|
if p.options.fileLoader != nil {
|
||||||
|
r, er := p.options.fileLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
p.options.logger.Warnf("file loader: %v", er)
|
||||||
|
}
|
||||||
|
return io.ReadAll(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.options.redisLoader != nil {
|
||||||
|
r, er := p.options.redisLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
p.options.logger.Warnf("redis loader: %v", er)
|
||||||
|
}
|
||||||
|
return io.ReadAll(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.options.httpLoader != nil {
|
||||||
|
r, er := p.options.redisLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
p.options.logger.Warnf("http loader: %v", er)
|
||||||
|
}
|
||||||
|
return io.ReadAll(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -84,6 +84,7 @@ type AutherConfig struct {
|
|||||||
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
||||||
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
||||||
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
|
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthConfig struct {
|
type AuthConfig struct {
|
||||||
@ -106,6 +107,7 @@ type AdmissionConfig struct {
|
|||||||
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
||||||
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
||||||
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
|
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BypassConfig struct {
|
type BypassConfig struct {
|
||||||
@ -117,6 +119,7 @@ type BypassConfig struct {
|
|||||||
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
||||||
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
||||||
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
|
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileLoader struct {
|
type FileLoader struct {
|
||||||
@ -131,6 +134,11 @@ type RedisLoader struct {
|
|||||||
Type string `yaml:",omitempty" json:"type,omitempty"`
|
Type string `yaml:",omitempty" json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HTTPLoader struct {
|
||||||
|
URL string `yaml:"url" json:"url"`
|
||||||
|
Timeout time.Duration `yaml:",omitempty" json:"timeout,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type NameserverConfig struct {
|
type NameserverConfig struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
Chain string `yaml:",omitempty" json:"chain,omitempty"`
|
Chain string `yaml:",omitempty" json:"chain,omitempty"`
|
||||||
@ -158,6 +166,7 @@ type HostsConfig struct {
|
|||||||
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
||||||
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
||||||
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
|
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecorderConfig struct {
|
type RecorderConfig struct {
|
||||||
@ -190,6 +199,7 @@ type LimiterConfig struct {
|
|||||||
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
Reload time.Duration `yaml:",omitempty" json:"reload,omitempty"`
|
||||||
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
File *FileLoader `yaml:",omitempty" json:"file,omitempty"`
|
||||||
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
|
||||||
|
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListenerConfig struct {
|
type ListenerConfig struct {
|
||||||
|
@ -70,6 +70,12 @@ func ParseAuther(cfg *config.AutherConfig) auth.Authenticator {
|
|||||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||||
|
opts = append(opts, auth_impl.HTTPLoaderOption(loader.HTTPLoader(
|
||||||
|
cfg.HTTP.URL,
|
||||||
|
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
return auth_impl.NewAuthenticator(opts...)
|
return auth_impl.NewAuthenticator(opts...)
|
||||||
}
|
}
|
||||||
@ -172,6 +178,13 @@ func ParseAdmission(cfg *config.AdmissionConfig) admission.Admission {
|
|||||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||||
|
opts = append(opts, admission_impl.HTTPLoaderOption(loader.HTTPLoader(
|
||||||
|
cfg.HTTP.URL,
|
||||||
|
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
return admission_impl.NewAdmission(opts...)
|
return admission_impl.NewAdmission(opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +213,13 @@ func ParseBypass(cfg *config.BypassConfig) bypass.Bypass {
|
|||||||
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
loader.KeyRedisLoaderOption(cfg.Redis.Key),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||||
|
opts = append(opts, bypass_impl.HTTPLoaderOption(loader.HTTPLoader(
|
||||||
|
cfg.HTTP.URL,
|
||||||
|
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
return bypass_impl.NewBypass(opts...)
|
return bypass_impl.NewBypass(opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,6 +300,12 @@ func ParseHosts(cfg *config.HostsConfig) hosts.HostMapper {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||||
|
opts = append(opts, xhosts.HTTPLoaderOption(loader.HTTPLoader(
|
||||||
|
cfg.HTTP.URL,
|
||||||
|
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||||
|
)))
|
||||||
|
}
|
||||||
return xhosts.NewHostMapper(opts...)
|
return xhosts.NewHostMapper(opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,6 +385,12 @@ func ParseTrafficLimiter(cfg *config.LimiterConfig) (lim traffic.TrafficLimiter)
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||||
|
opts = append(opts, xtraffic.HTTPLoaderOption(loader.HTTPLoader(
|
||||||
|
cfg.HTTP.URL,
|
||||||
|
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||||
|
)))
|
||||||
|
}
|
||||||
opts = append(opts,
|
opts = append(opts,
|
||||||
xtraffic.LimitsOption(cfg.Limits...),
|
xtraffic.LimitsOption(cfg.Limits...),
|
||||||
xtraffic.ReloadPeriodOption(cfg.Reload),
|
xtraffic.ReloadPeriodOption(cfg.Reload),
|
||||||
@ -399,6 +431,12 @@ func ParseConnLimiter(cfg *config.LimiterConfig) (lim conn.ConnLimiter) {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||||
|
opts = append(opts, xconn.HTTPLoaderOption(loader.HTTPLoader(
|
||||||
|
cfg.HTTP.URL,
|
||||||
|
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||||
|
)))
|
||||||
|
}
|
||||||
opts = append(opts,
|
opts = append(opts,
|
||||||
xconn.LimitsOption(cfg.Limits...),
|
xconn.LimitsOption(cfg.Limits...),
|
||||||
xconn.ReloadPeriodOption(cfg.Reload),
|
xconn.ReloadPeriodOption(cfg.Reload),
|
||||||
@ -439,6 +477,12 @@ func ParseRateLimiter(cfg *config.LimiterConfig) (lim rate.RateLimiter) {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cfg.HTTP != nil && cfg.HTTP.URL != "" {
|
||||||
|
opts = append(opts, xrate.HTTPLoaderOption(loader.HTTPLoader(
|
||||||
|
cfg.HTTP.URL,
|
||||||
|
loader.TimeoutHTTPLoaderOption(cfg.HTTP.Timeout),
|
||||||
|
)))
|
||||||
|
}
|
||||||
opts = append(opts,
|
opts = append(opts,
|
||||||
xrate.LimitsOption(cfg.Limits...),
|
xrate.LimitsOption(cfg.Limits...),
|
||||||
xrate.ReloadPeriodOption(cfg.Reload),
|
xrate.ReloadPeriodOption(cfg.Reload),
|
||||||
|
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
||||||
github.com/gin-contrib/cors v1.3.1
|
github.com/gin-contrib/cors v1.3.1
|
||||||
github.com/gin-gonic/gin v1.7.7
|
github.com/gin-gonic/gin v1.7.7
|
||||||
github.com/go-gost/core v0.0.0-20220914115321-50d443049f3b
|
github.com/go-gost/core v0.0.0-20220920034830-41ff9835a66d
|
||||||
github.com/go-gost/gosocks4 v0.0.1
|
github.com/go-gost/gosocks4 v0.0.1
|
||||||
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09
|
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09
|
||||||
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7
|
github.com/go-gost/relay v0.1.1-0.20211123134818-8ef7fd81ffd7
|
||||||
|
4
go.sum
4
go.sum
@ -98,8 +98,8 @@ github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ
|
|||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-gost/core v0.0.0-20220914115321-50d443049f3b h1:fWUPYFp0W/6GEhL0wrURGPQN2AQHhf4IZKiALJJOJh8=
|
github.com/go-gost/core v0.0.0-20220920034830-41ff9835a66d h1:UFn21xIJgWE/te12rzQA7Ymwbo+MaxOcp38K41L+Yck=
|
||||||
github.com/go-gost/core v0.0.0-20220914115321-50d443049f3b/go.mod h1:bHVbCS9da6XtKNYMkMUVcck5UqDDUkyC37erVfs4GXQ=
|
github.com/go-gost/core v0.0.0-20220920034830-41ff9835a66d/go.mod h1:bHVbCS9da6XtKNYMkMUVcck5UqDDUkyC37erVfs4GXQ=
|
||||||
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
||||||
github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
|
github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
|
||||||
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 h1:A95M6UWcfZgOuJkQ7QLfG0Hs5peWIUSysCDNz4pfe04=
|
github.com/go-gost/gosocks5 v0.3.1-0.20211109033403-d894d75b7f09 h1:A95M6UWcfZgOuJkQ7QLfG0Hs5peWIUSysCDNz4pfe04=
|
||||||
|
@ -23,6 +23,7 @@ type options struct {
|
|||||||
mappings []Mapping
|
mappings []Mapping
|
||||||
fileLoader loader.Loader
|
fileLoader loader.Loader
|
||||||
redisLoader loader.Loader
|
redisLoader loader.Loader
|
||||||
|
httpLoader loader.Loader
|
||||||
period time.Duration
|
period time.Duration
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
@ -53,6 +54,12 @@ func RedisLoaderOption(redisLoader loader.Loader) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HTTPLoaderOption(httpLoader loader.Loader) Option {
|
||||||
|
return func(opts *options) {
|
||||||
|
opts.httpLoader = httpLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LoggerOption(logger logger.Logger) Option {
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.logger = logger
|
opts.logger = logger
|
||||||
@ -254,6 +261,15 @@ func (h *hostMapper) load(ctx context.Context) (mappings []Mapping, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if h.options.httpLoader != nil {
|
||||||
|
r, er := h.options.httpLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
h.options.logger.Warnf("http loader: %v", er)
|
||||||
|
}
|
||||||
|
if m, _ := h.parseMapping(r); m != nil {
|
||||||
|
mappings = append(mappings, m...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
h.options.logger.Debugf("load items %d", len(mappings))
|
h.options.logger.Debugf("load items %d", len(mappings))
|
||||||
return
|
return
|
||||||
|
71
internal/loader/http.go
Normal file
71
internal/loader/http.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package loader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type httpLoaderOptions struct {
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPLoaderOption func(opts *httpLoaderOptions)
|
||||||
|
|
||||||
|
func TimeoutHTTPLoaderOption(timeout time.Duration) HTTPLoaderOption {
|
||||||
|
return func(opts *httpLoaderOptions) {
|
||||||
|
opts.timeout = timeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpLoader struct {
|
||||||
|
url string
|
||||||
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPLoader loads data from HTTP request.
|
||||||
|
func HTTPLoader(url string, opts ...HTTPLoaderOption) Loader {
|
||||||
|
var options httpLoaderOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
if opt != nil {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &httpLoader{
|
||||||
|
url: url,
|
||||||
|
httpClient: &http.Client{
|
||||||
|
Timeout: options.timeout,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *httpLoader) Load(ctx context.Context) (io.Reader, error) {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, l.url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := l.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("%d %s", resp.StatusCode, resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.NewReader(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *httpLoader) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -49,7 +49,9 @@ type redisSetLoader struct {
|
|||||||
func RedisSetLoader(addr string, opts ...RedisLoaderOption) Loader {
|
func RedisSetLoader(addr string, opts ...RedisLoaderOption) Loader {
|
||||||
var options redisLoaderOptions
|
var options redisLoaderOptions
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(&options)
|
if opt != nil {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
key := options.key
|
key := options.key
|
||||||
|
@ -62,6 +62,7 @@ type options struct {
|
|||||||
limits []string
|
limits []string
|
||||||
fileLoader loader.Loader
|
fileLoader loader.Loader
|
||||||
redisLoader loader.Loader
|
redisLoader loader.Loader
|
||||||
|
httpLoader loader.Loader
|
||||||
period time.Duration
|
period time.Duration
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
@ -92,6 +93,12 @@ func RedisLoaderOption(redisLoader loader.Loader) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HTTPLoaderOption(httpLoader loader.Loader) Option {
|
||||||
|
return func(opts *options) {
|
||||||
|
opts.httpLoader = httpLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LoggerOption(logger logger.Logger) Option {
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.logger = logger
|
opts.logger = logger
|
||||||
@ -292,6 +299,15 @@ func (l *connLimiter) load(ctx context.Context) (patterns []string, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if l.options.httpLoader != nil {
|
||||||
|
r, er := l.options.httpLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
l.options.logger.Warnf("http loader: %v", er)
|
||||||
|
}
|
||||||
|
if v, _ := l.parsePatterns(r); v != nil {
|
||||||
|
patterns = append(patterns, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
l.options.logger.Debugf("load items %d", len(patterns))
|
l.options.logger.Debugf("load items %d", len(patterns))
|
||||||
return
|
return
|
||||||
|
@ -55,6 +55,7 @@ type options struct {
|
|||||||
limits []string
|
limits []string
|
||||||
fileLoader loader.Loader
|
fileLoader loader.Loader
|
||||||
redisLoader loader.Loader
|
redisLoader loader.Loader
|
||||||
|
httpLoader loader.Loader
|
||||||
period time.Duration
|
period time.Duration
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
@ -85,6 +86,12 @@ func RedisLoaderOption(redisLoader loader.Loader) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HTTPLoaderOption(httpLoader loader.Loader) Option {
|
||||||
|
return func(opts *options) {
|
||||||
|
opts.httpLoader = httpLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LoggerOption(logger logger.Logger) Option {
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.logger = logger
|
opts.logger = logger
|
||||||
@ -285,6 +292,15 @@ func (l *rateLimiter) load(ctx context.Context) (patterns []string, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if l.options.httpLoader != nil {
|
||||||
|
r, er := l.options.httpLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
l.options.logger.Warnf("http loader: %v", er)
|
||||||
|
}
|
||||||
|
if v, _ := l.parsePatterns(r); v != nil {
|
||||||
|
patterns = append(patterns, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
l.options.logger.Debugf("load items %d", len(patterns))
|
l.options.logger.Debugf("load items %d", len(patterns))
|
||||||
return
|
return
|
||||||
|
@ -54,6 +54,7 @@ type options struct {
|
|||||||
limits []string
|
limits []string
|
||||||
fileLoader loader.Loader
|
fileLoader loader.Loader
|
||||||
redisLoader loader.Loader
|
redisLoader loader.Loader
|
||||||
|
httpLoader loader.Loader
|
||||||
period time.Duration
|
period time.Duration
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
}
|
}
|
||||||
@ -84,6 +85,12 @@ func RedisLoaderOption(redisLoader loader.Loader) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HTTPLoaderOption(httpLoader loader.Loader) Option {
|
||||||
|
return func(opts *options) {
|
||||||
|
opts.httpLoader = httpLoader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LoggerOption(logger logger.Logger) Option {
|
func LoggerOption(logger logger.Logger) Option {
|
||||||
return func(opts *options) {
|
return func(opts *options) {
|
||||||
opts.logger = logger
|
opts.logger = logger
|
||||||
@ -337,6 +344,15 @@ func (l *trafficLimiter) load(ctx context.Context) (patterns []string, err error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if l.options.httpLoader != nil {
|
||||||
|
r, er := l.options.httpLoader.Load(ctx)
|
||||||
|
if er != nil {
|
||||||
|
l.options.logger.Warnf("http loader: %v", er)
|
||||||
|
}
|
||||||
|
if v, _ := l.parsePatterns(r); v != nil {
|
||||||
|
patterns = append(patterns, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
l.options.logger.Debugf("load items %d", len(patterns))
|
l.options.logger.Debugf("load items %d", len(patterns))
|
||||||
return
|
return
|
||||||
|
Loading…
Reference in New Issue
Block a user