add observer
This commit is contained in:
parent
e1ae379048
commit
c959fc2f73
67
admission/plugin/grpc.go
Normal file
67
admission/plugin/grpc.go
Normal file
@ -0,0 +1,67 @@
|
||||
package admission
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/admission"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/admission/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.AdmissionClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Admission plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) admission.Admission {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "admission",
|
||||
"admission": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewAdmissionClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Admit(ctx context.Context, addr string, opts ...admission.Option) bool {
|
||||
if p.client == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
r, err := p.client.Admit(ctx,
|
||||
&proto.AdmissionRequest{
|
||||
Addr: addr,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return false
|
||||
}
|
||||
return r.Ok
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -4,71 +4,13 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/admission"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/admission/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.AdmissionClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Admission plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) admission.Admission {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "admission",
|
||||
"admission": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewAdmissionClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Admit(ctx context.Context, addr string, opts ...admission.Option) bool {
|
||||
if p.client == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
r, err := p.client.Admit(ctx,
|
||||
&proto.AdmissionRequest{
|
||||
Addr: addr,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return false
|
||||
}
|
||||
return r.Ok
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginRequest struct {
|
||||
Addr string `json:"addr"`
|
||||
}
|
@ -8,8 +8,15 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/registry"
|
||||
"github.com/go-gost/x/service"
|
||||
"github.com/go-gost/x/stats"
|
||||
)
|
||||
|
||||
type serviceStatus interface {
|
||||
Status() *service.Status
|
||||
}
|
||||
|
||||
// swagger:parameters getConfigRequest
|
||||
type getConfigRequest struct {
|
||||
// output format, one of yaml|json, default is json.
|
||||
@ -37,6 +44,40 @@ func getConfig(ctx *gin.Context) {
|
||||
var req getConfigRequest
|
||||
ctx.ShouldBindQuery(&req)
|
||||
|
||||
config.OnUpdate(func(c *config.Config) error {
|
||||
for _, svc := range c.Services {
|
||||
if svc == nil {
|
||||
continue
|
||||
}
|
||||
s := registry.ServiceRegistry().Get(svc.Name)
|
||||
ss, ok := s.(serviceStatus)
|
||||
if ok && ss != nil {
|
||||
status := ss.Status()
|
||||
svc.Status = &config.ServiceStatus{
|
||||
CreateTime: status.CreateTime().Unix(),
|
||||
State: string(status.State()),
|
||||
}
|
||||
if st := status.Stats(); st != nil {
|
||||
svc.Status.Stats = &config.ServiceStats{
|
||||
TotalConns: st.Get(stats.KindTotalConns),
|
||||
CurrentConns: st.Get(stats.KindCurrentConns),
|
||||
TotalErrs: st.Get(stats.KindTotalErrs),
|
||||
InputBytes: st.Get(stats.KindInputBytes),
|
||||
OutputBytes: st.Get(stats.KindOutputBytes),
|
||||
}
|
||||
}
|
||||
for _, ev := range status.Events() {
|
||||
if !ev.Time.IsZero() {
|
||||
svc.Status.Events = append(svc.Status.Events, config.ServiceEvent{
|
||||
Time: ev.Time.Unix(),
|
||||
Msg: ev.Message,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
var resp getConfigResponse
|
||||
resp.Config = config.Global()
|
||||
|
||||
|
@ -110,7 +110,7 @@ func (p *authenticator) Authenticate(ctx context.Context, user, password string,
|
||||
}
|
||||
|
||||
v, ok := p.kvs[user]
|
||||
return "", ok && (v == "" || password == v)
|
||||
return user, ok && (v == "" || password == v)
|
||||
}
|
||||
|
||||
func (p *authenticator) periodReload(ctx context.Context) error {
|
||||
|
72
auth/plugin/grpc.go
Normal file
72
auth/plugin/grpc.go
Normal file
@ -0,0 +1,72 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/auth"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/auth/proto"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.AuthenticatorClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Authenticator plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) auth.Authenticator {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "auther",
|
||||
"auther": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
|
||||
if conn != nil {
|
||||
p.client = proto.NewAuthenticatorClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Authenticate checks the validity of the provided user-password pair.
|
||||
func (p *grpcPlugin) Authenticate(ctx context.Context, user, password string, opts ...auth.Option) (string, bool) {
|
||||
if p.client == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
r, err := p.client.Authenticate(ctx,
|
||||
&proto.AuthenticateRequest{
|
||||
Username: user,
|
||||
Password: password,
|
||||
Client: string(ctxvalue.ClientAddrFromContext(ctx)),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return "", false
|
||||
}
|
||||
return r.Id, r.Ok
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -4,76 +4,14 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/auth"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/auth/proto"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.AuthenticatorClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Authenticator plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) auth.Authenticator {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "auther",
|
||||
"auther": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
|
||||
if conn != nil {
|
||||
p.client = proto.NewAuthenticatorClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Authenticate checks the validity of the provided user-password pair.
|
||||
func (p *grpcPlugin) Authenticate(ctx context.Context, user, password string, opts ...auth.Option) (string, bool) {
|
||||
if p.client == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
r, err := p.client.Authenticate(ctx,
|
||||
&proto.AuthenticateRequest{
|
||||
Username: user,
|
||||
Password: password,
|
||||
Client: string(ctxvalue.ClientAddrFromContext(ctx)),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return "", false
|
||||
}
|
||||
return r.Id, r.Ok
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
77
bypass/plugin/grpc.go
Normal file
77
bypass/plugin/grpc.go
Normal file
@ -0,0 +1,77 @@
|
||||
package bypass
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/bypass/proto"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.BypassClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a Bypass plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) bypass.Bypass {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "bypass",
|
||||
"bypass": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewBypassClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) bool {
|
||||
if p.client == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
var options bypass.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
r, err := p.client.Bypass(ctx,
|
||||
&proto.BypassRequest{
|
||||
Network: network,
|
||||
Addr: addr,
|
||||
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||
Host: options.Host,
|
||||
Path: options.Path,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return true
|
||||
}
|
||||
return r.Ok
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -4,81 +4,14 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/bypass/proto"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.BypassClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a Bypass plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) bypass.Bypass {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "bypass",
|
||||
"bypass": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewBypassClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) bool {
|
||||
if p.client == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
var options bypass.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
r, err := p.client.Bypass(ctx,
|
||||
&proto.BypassRequest{
|
||||
Network: network,
|
||||
Addr: addr,
|
||||
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||
Host: options.Host,
|
||||
Path: options.Path,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return true
|
||||
}
|
||||
return r.Ok
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginRequest struct {
|
||||
Network string `json:"network"`
|
||||
Addr string `json:"addr"`
|
@ -312,6 +312,11 @@ type LimiterConfig struct {
|
||||
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||
}
|
||||
|
||||
type ObserverConfig struct {
|
||||
Name string `json:"name"`
|
||||
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
|
||||
}
|
||||
|
||||
type ListenerConfig struct {
|
||||
Type string `json:"type"`
|
||||
Chain string `yaml:",omitempty" json:"chain,omitempty"`
|
||||
@ -333,6 +338,7 @@ type HandlerConfig struct {
|
||||
Auth *AuthConfig `yaml:",omitempty" json:"auth,omitempty"`
|
||||
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||
Limiter string `yaml:",omitempty" json:"limiter,omitempty"`
|
||||
Observer string `yaml:",omitempty" json:"observer,omitempty"`
|
||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
@ -403,11 +409,34 @@ type ServiceConfig struct {
|
||||
RLimiter string `yaml:"rlimiter,omitempty" json:"rlimiter,omitempty"`
|
||||
Logger string `yaml:",omitempty" json:"logger,omitempty"`
|
||||
Loggers []string `yaml:",omitempty" json:"loggers,omitempty"`
|
||||
Observer string `yaml:",omitempty" json:"observer,omitempty"`
|
||||
Recorders []*RecorderObject `yaml:",omitempty" json:"recorders,omitempty"`
|
||||
Handler *HandlerConfig `yaml:",omitempty" json:"handler,omitempty"`
|
||||
Listener *ListenerConfig `yaml:",omitempty" json:"listener,omitempty"`
|
||||
Forwarder *ForwarderConfig `yaml:",omitempty" json:"forwarder,omitempty"`
|
||||
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
|
||||
// service status, read-only
|
||||
Status *ServiceStatus `yaml:",omitempty" json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type ServiceStatus struct {
|
||||
CreateTime int64 `yaml:"createTime" json:"createTime"`
|
||||
State string `yaml:"state" json:"state"`
|
||||
Events []ServiceEvent `yaml:",omitempty" json:"events,omitempty"`
|
||||
Stats *ServiceStats `yaml:",omitempty" json:"stats,omitempty"`
|
||||
}
|
||||
|
||||
type ServiceEvent struct {
|
||||
Time int64 `yaml:"time" json:"time"`
|
||||
Msg string `yaml:"msg" json:"msg"`
|
||||
}
|
||||
|
||||
type ServiceStats struct {
|
||||
TotalConns uint64 `yaml:"totalConns" json:"totalConns"`
|
||||
CurrentConns uint64 `yaml:"currentConns" json:"currentConns"`
|
||||
TotalErrs uint64 `yaml:"totalErrs" json:"totalErrs"`
|
||||
InputBytes uint64 `yaml:"inputBytes" json:"inputBytes"`
|
||||
OutputBytes uint64 `yaml:"outputBytes" json:"outputBytes"`
|
||||
}
|
||||
|
||||
type ChainConfig struct {
|
||||
@ -475,6 +504,7 @@ type Config struct {
|
||||
Limiters []*LimiterConfig `yaml:",omitempty" json:"limiters,omitempty"`
|
||||
CLimiters []*LimiterConfig `yaml:"climiters,omitempty" json:"climiters,omitempty"`
|
||||
RLimiters []*LimiterConfig `yaml:"rlimiters,omitempty" json:"rlimiters,omitempty"`
|
||||
Observers []*ObserverConfig `yaml:",omitempty" json:"observers,omitempty"`
|
||||
Loggers []*LoggerConfig `yaml:",omitempty" json:"loggers,omitempty"`
|
||||
TLS *TLSConfig `yaml:",omitempty" json:"tls,omitempty"`
|
||||
Log *LogConfig `yaml:",omitempty" json:"log,omitempty"`
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/go-gost/core/admission"
|
||||
"github.com/go-gost/core/logger"
|
||||
xadmission "github.com/go-gost/x/admission"
|
||||
admission_plugin "github.com/go-gost/x/admission/plugin"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
@ -28,13 +29,13 @@ func ParseAdmission(cfg *config.AdmissionConfig) admission.Admission {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xadmission.NewHTTPPlugin(
|
||||
return admission_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xadmission.NewGRPCPlugin(
|
||||
return admission_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/go-gost/core/auth"
|
||||
"github.com/go-gost/core/logger"
|
||||
xauth "github.com/go-gost/x/auth"
|
||||
auth_plugin "github.com/go-gost/x/auth/plugin"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
@ -28,13 +29,13 @@ func ParseAuther(cfg *config.AutherConfig) auth.Authenticator {
|
||||
}
|
||||
switch cfg.Plugin.Type {
|
||||
case "http":
|
||||
return xauth.NewHTTPPlugin(
|
||||
return auth_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xauth.NewGRPCPlugin(
|
||||
return auth_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/go-gost/core/bypass"
|
||||
"github.com/go-gost/core/logger"
|
||||
xbypass "github.com/go-gost/x/bypass"
|
||||
bypass_plugin "github.com/go-gost/x/bypass/plugin"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
@ -28,13 +29,13 @@ func ParseBypass(cfg *config.BypassConfig) bypass.Bypass {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xbypass.NewHTTPPlugin(
|
||||
return bypass_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xbypass.NewGRPCPlugin(
|
||||
return bypass_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
node_parser "github.com/go-gost/x/config/parsing/node"
|
||||
selector_parser "github.com/go-gost/x/config/parsing/selector"
|
||||
xhop "github.com/go-gost/x/hop"
|
||||
hop_plugin "github.com/go-gost/x/hop/plugin"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
)
|
||||
@ -32,13 +33,13 @@ func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xhop.NewHTTPPlugin(
|
||||
return hop_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
), nil
|
||||
default:
|
||||
return xhop.NewGRPCPlugin(
|
||||
return hop_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/x/config"
|
||||
xhosts "github.com/go-gost/x/hosts"
|
||||
hosts_plugin "github.com/go-gost/x/hosts/plugin"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
)
|
||||
@ -28,13 +29,13 @@ func ParseHostMapper(cfg *config.HostsConfig) hosts.HostMapper {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xhosts.NewHTTPPlugin(
|
||||
return hosts_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xhosts.NewGRPCPlugin(
|
||||
return hosts_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/x/config"
|
||||
xingress "github.com/go-gost/x/ingress"
|
||||
ingress_plugin "github.com/go-gost/x/ingress/plugin"
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
)
|
||||
@ -27,13 +28,13 @@ func ParseIngress(cfg *config.IngressConfig) ingress.Ingress {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xingress.NewHTTPPlugin(
|
||||
return ingress_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xingress.NewGRPCPlugin(
|
||||
return ingress_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
xconn "github.com/go-gost/x/limiter/conn"
|
||||
xrate "github.com/go-gost/x/limiter/rate"
|
||||
xtraffic "github.com/go-gost/x/limiter/traffic"
|
||||
traffic_plugin "github.com/go-gost/x/limiter/traffic/plugin"
|
||||
)
|
||||
|
||||
func ParseTrafficLimiter(cfg *config.LimiterConfig) (lim traffic.TrafficLimiter) {
|
||||
@ -31,13 +32,13 @@ func ParseTrafficLimiter(cfg *config.LimiterConfig) (lim traffic.TrafficLimiter)
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xtraffic.NewHTTPPlugin(
|
||||
return traffic_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xtraffic.NewGRPCPlugin(
|
||||
return traffic_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
39
config/parsing/observer/parse.go
Normal file
39
config/parsing/observer/parse.go
Normal file
@ -0,0 +1,39 @@
|
||||
package observer
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gost/core/observer"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
observer_plugin "github.com/go-gost/x/observer/plugin"
|
||||
)
|
||||
|
||||
func ParseObserver(cfg *config.ObserverConfig) observer.Observer {
|
||||
if cfg == nil || cfg.Plugin == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var tlsCfg *tls.Config
|
||||
if cfg.Plugin.TLS != nil {
|
||||
tlsCfg = &tls.Config{
|
||||
ServerName: cfg.Plugin.TLS.ServerName,
|
||||
InsecureSkipVerify: !cfg.Plugin.TLS.Secure,
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return observer_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return observer_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
)
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ const (
|
||||
MDKeyPostUp = "postUp"
|
||||
MDKeyPostDown = "postDown"
|
||||
MDKeyIgnoreChain = "ignoreChain"
|
||||
MDKeyEnableStats = "enableStats"
|
||||
|
||||
MDKeyRecorderDirection = "direction"
|
||||
MDKeyRecorderTimestampFormat = "timeStampFormat"
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
xrecorder "github.com/go-gost/x/recorder"
|
||||
recorder_plugin "github.com/go-gost/x/recorder/plugin"
|
||||
)
|
||||
|
||||
func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
|
||||
@ -25,13 +26,13 @@ func ParseRecorder(cfg *config.RecorderConfig) (r recorder.Recorder) {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xrecorder.NewHTTPPlugin(
|
||||
return recorder_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xrecorder.NewGRPCPlugin(
|
||||
return recorder_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"github.com/go-gost/x/registry"
|
||||
xresolver "github.com/go-gost/x/resolver"
|
||||
resolver_plugin "github.com/go-gost/x/resolver/plugin"
|
||||
)
|
||||
|
||||
func ParseResolver(cfg *config.ResolverConfig) (resolver.Resolver, error) {
|
||||
@ -28,13 +29,13 @@ func ParseResolver(cfg *config.ResolverConfig) (resolver.Resolver, error) {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xresolver.NewHTTPPlugin(
|
||||
return resolver_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
), nil
|
||||
default:
|
||||
return xresolver.NewGRPCPlugin(
|
||||
return resolver_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/go-gost/x/internal/loader"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
xrouter "github.com/go-gost/x/router"
|
||||
router_plugin "github.com/go-gost/x/router/plugin"
|
||||
)
|
||||
|
||||
func ParseRouter(cfg *config.RouterConfig) router.Router {
|
||||
@ -28,13 +29,13 @@ func ParseRouter(cfg *config.RouterConfig) router.Router {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xrouter.NewHTTPPlugin(
|
||||
return router_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xrouter.NewGRPCPlugin(
|
||||
return router_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"github.com/go-gost/core/sd"
|
||||
"github.com/go-gost/x/config"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
xsd "github.com/go-gost/x/sd"
|
||||
sd_plugin "github.com/go-gost/x/sd/plugin"
|
||||
)
|
||||
|
||||
func ParseSD(cfg *config.SDConfig) sd.SD {
|
||||
@ -24,13 +24,13 @@ func ParseSD(cfg *config.SDConfig) sd.SD {
|
||||
}
|
||||
switch strings.ToLower(cfg.Plugin.Type) {
|
||||
case "http":
|
||||
return xsd.NewHTTPPlugin(
|
||||
return sd_plugin.NewHTTPPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
plugin.TimeoutOption(cfg.Plugin.Timeout),
|
||||
)
|
||||
default:
|
||||
return xsd.NewGRPCPlugin(
|
||||
return sd_plugin.NewGRPCPlugin(
|
||||
cfg.Name, cfg.Plugin.Addr,
|
||||
plugin.TokenOption(cfg.Plugin.Token),
|
||||
plugin.TLSConfigOption(tlsCfg),
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
"github.com/go-gost/x/metadata"
|
||||
"github.com/go-gost/x/registry"
|
||||
xservice "github.com/go-gost/x/service"
|
||||
"github.com/go-gost/x/stats"
|
||||
)
|
||||
|
||||
func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
@ -96,6 +97,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
ifce := cfg.Interface
|
||||
var preUp, preDown, postUp, postDown []string
|
||||
var ignoreChain bool
|
||||
var pStats *stats.Stats
|
||||
if cfg.Metadata != nil {
|
||||
md := metadata.NewMetadata(cfg.Metadata)
|
||||
ppv = mdutil.GetInt(md, parsing.MDKeyProxyProtocol)
|
||||
@ -112,6 +114,10 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
postUp = mdutil.GetStrings(md, parsing.MDKeyPostUp)
|
||||
postDown = mdutil.GetStrings(md, parsing.MDKeyPostDown)
|
||||
ignoreChain = mdutil.GetBool(md, parsing.MDKeyIgnoreChain)
|
||||
|
||||
if mdutil.GetBool(md, parsing.MDKeyEnableStats) {
|
||||
pStats = &stats.Stats{}
|
||||
}
|
||||
}
|
||||
|
||||
listenOpts := []listener.Option{
|
||||
@ -125,6 +131,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
listener.LoggerOption(listenerLogger),
|
||||
listener.ServiceOption(cfg.Name),
|
||||
listener.ProxyProtocolOption(ppv),
|
||||
listener.StatsOption(pStats),
|
||||
}
|
||||
if !ignoreChain {
|
||||
listenOpts = append(listenOpts,
|
||||
@ -218,6 +225,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
handler.TLSConfigOption(tlsConfig),
|
||||
handler.RateLimiterOption(registry.RateLimiterRegistry().Get(cfg.RLimiter)),
|
||||
handler.TrafficLimiterOption(registry.TrafficLimiterRegistry().Get(cfg.Handler.Limiter)),
|
||||
handler.ObserverOption(registry.ObserverRegistry().Get(cfg.Handler.Observer)),
|
||||
handler.LoggerOption(handlerLogger),
|
||||
handler.ServiceOption(cfg.Name),
|
||||
)
|
||||
@ -249,6 +257,8 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
|
||||
xservice.PostUpOption(postUp),
|
||||
xservice.PostDownOption(postDown),
|
||||
xservice.RecordersOption(recorders...),
|
||||
xservice.StatsOption(pStats),
|
||||
xservice.ObserverOption(registry.ObserverRegistry().Get(cfg.Observer)),
|
||||
xservice.LoggerOption(serviceLogger),
|
||||
)
|
||||
|
||||
|
4
go.mod
4
go.mod
@ -7,10 +7,10 @@ require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
|
||||
github.com/gin-contrib/cors v1.5.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-gost/core v0.0.0-20231219132306-6b5c04b5e446
|
||||
github.com/go-gost/core v0.0.0-20240103125300-5a427b4eaf99
|
||||
github.com/go-gost/gosocks4 v0.0.1
|
||||
github.com/go-gost/gosocks5 v0.4.0
|
||||
github.com/go-gost/plugin v0.0.0-20231119084331-d49a1cb23b3b
|
||||
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a
|
||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7
|
||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
|
8
go.sum
8
go.sum
@ -49,14 +49,14 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-gost/core v0.0.0-20231219132306-6b5c04b5e446 h1:H7VyfQOOAH7smDQ41O/mMClFv8MyflVk5AO9uIp7qXg=
|
||||
github.com/go-gost/core v0.0.0-20231219132306-6b5c04b5e446/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
|
||||
github.com/go-gost/core v0.0.0-20240103125300-5a427b4eaf99 h1:/0hmilnQBEDlOaRcO+TlwaHH8a5ig6nc2aAsU4FGZcw=
|
||||
github.com/go-gost/core v0.0.0-20240103125300-5a427b4eaf99/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
|
||||
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/gosocks5 v0.4.0 h1:EIrOEkpJez4gwHrMa33frA+hHXJyevjp47thpMQsJzI=
|
||||
github.com/go-gost/gosocks5 v0.4.0/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4=
|
||||
github.com/go-gost/plugin v0.0.0-20231119084331-d49a1cb23b3b h1:ZmnYutflq+KOZK+Px5RDckorDSxTYlkT4aQbjTC8/C4=
|
||||
github.com/go-gost/plugin v0.0.0-20231119084331-d49a1cb23b3b/go.mod h1:qXr2Zm9Ex2ATqnWuNUzVZqySPMnuIihvblYZt4MlZLw=
|
||||
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a h1:ME7P1Brcg4C640DSPqlvQr7JuvvQfJ8QpmS3yCFlK3A=
|
||||
github.com/go-gost/plugin v0.0.0-20240103125338-9c84e29cb81a/go.mod h1:qXr2Zm9Ex2ATqnWuNUzVZqySPMnuIihvblYZt4MlZLw=
|
||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7 h1:qAG1OyjvdA5h221CfFSS3J359V3d2E7dJWyP29QoDSI=
|
||||
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
||||
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451 h1:xj8gUZGYO3nb5+6Bjw9+tsFkA9sYynrOvDvvC4uDV2I=
|
||||
|
@ -19,13 +19,16 @@ import (
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/handler"
|
||||
"github.com/go-gost/core/limiter/traffic"
|
||||
traffic "github.com/go-gost/core/limiter/traffic"
|
||||
"github.com/go-gost/core/logger"
|
||||
md "github.com/go-gost/core/metadata"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
netpkg "github.com/go-gost/x/internal/net"
|
||||
"github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
stats_util "github.com/go-gost/x/internal/util/stats"
|
||||
traffic_wrapper "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -36,6 +39,8 @@ type httpHandler struct {
|
||||
router *chain.Router
|
||||
md metadata
|
||||
options handler.Options
|
||||
stats *stats_util.HandlerStats
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
@ -46,6 +51,7 @@ func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
|
||||
return &httpHandler{
|
||||
options: options,
|
||||
stats: stats_util.NewHandlerStats(options.Service),
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +65,13 @@ func (h *httpHandler) Init(md md.Metadata) error {
|
||||
h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger))
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
h.cancel = cancel
|
||||
|
||||
if h.options.Observer != nil {
|
||||
go h.observeStats(ctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -93,6 +106,13 @@ func (h *httpHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler
|
||||
return h.handleRequest(ctx, conn, req, log)
|
||||
}
|
||||
|
||||
func (h *httpHandler) Close() error {
|
||||
if h.cancel != nil {
|
||||
h.cancel()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *http.Request, log logger.Logger) error {
|
||||
if !req.URL.IsAbs() && govalidator.IsDNSName(req.Host) {
|
||||
req.URL.Scheme = "http"
|
||||
@ -221,12 +241,19 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
}
|
||||
}
|
||||
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn, conn.RemoteAddr().String(),
|
||||
rw := traffic_wrapper.WrapReadWriter(h.options.Limiter, conn,
|
||||
traffic.NetworkOption(network),
|
||||
traffic.AddrOption(addr),
|
||||
traffic.ClientOption(clientID),
|
||||
traffic.SrcOption(conn.RemoteAddr().String()),
|
||||
)
|
||||
if h.options.Observer != nil {
|
||||
pstats := h.stats.Stats(clientID)
|
||||
pstats.Add(stats.KindTotalConns, 1)
|
||||
pstats.Add(stats.KindCurrentConns, 1)
|
||||
defer pstats.Add(stats.KindCurrentConns, -1)
|
||||
rw = stats_wrapper.WrapReadWriter(rw, pstats)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
log.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
||||
@ -378,3 +405,21 @@ func (h *httpHandler) checkRateLimit(addr net.Addr) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *httpHandler) observeStats(ctx context.Context) {
|
||||
if h.options.Observer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
h.options.Observer.Observe(ctx, h.stats.Events())
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,11 @@ import (
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
xio "github.com/go-gost/x/internal/io"
|
||||
netpkg "github.com/go-gost/x/internal/net"
|
||||
stats_util "github.com/go-gost/x/internal/util/stats"
|
||||
"github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -38,6 +41,8 @@ type http2Handler struct {
|
||||
router *chain.Router
|
||||
md metadata
|
||||
options handler.Options
|
||||
stats *stats_util.HandlerStats
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
@ -48,6 +53,7 @@ func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
|
||||
return &http2Handler{
|
||||
options: options,
|
||||
stats: stats_util.NewHandlerStats(options.Service),
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +67,12 @@ func (h *http2Handler) Init(md md.Metadata) error {
|
||||
h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger))
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
h.cancel = cancel
|
||||
|
||||
if h.options.Observer != nil {
|
||||
go h.observeStats(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -98,6 +110,13 @@ func (h *http2Handler) Handle(ctx context.Context, conn net.Conn, opts ...handle
|
||||
)
|
||||
}
|
||||
|
||||
func (h *http2Handler) Close() error {
|
||||
if h.cancel != nil {
|
||||
h.cancel()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE: there is an issue (golang/go#43989) will cause the client hangs
|
||||
// when server returns an non-200 status code,
|
||||
// May be fixed in go1.18.
|
||||
@ -204,12 +223,20 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req
|
||||
return nil
|
||||
}
|
||||
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, xio.NewReadWriter(req.Body, flushWriter{w}), req.RemoteAddr,
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, xio.NewReadWriter(req.Body, flushWriter{w}),
|
||||
traffic.NetworkOption("tcp"),
|
||||
traffic.AddrOption(addr),
|
||||
traffic.ClientOption(clientID),
|
||||
traffic.SrcOption(req.RemoteAddr),
|
||||
)
|
||||
if h.options.Observer != nil {
|
||||
pstats := h.stats.Stats(clientID)
|
||||
pstats.Add(stats.KindTotalConns, 1)
|
||||
pstats.Add(stats.KindCurrentConns, 1)
|
||||
defer pstats.Add(stats.KindCurrentConns, -1)
|
||||
rw = stats_wrapper.WrapReadWriter(rw, pstats)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
log.Infof("%s <-> %s", req.RemoteAddr, addr)
|
||||
netpkg.Transport(rw, cc)
|
||||
@ -386,3 +413,21 @@ func (h *http2Handler) checkRateLimit(addr net.Addr) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *http2Handler) observeStats(ctx context.Context) {
|
||||
if h.options.Observer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
h.options.Observer.Observe(ctx, h.stats.Events())
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ import (
|
||||
xnet "github.com/go-gost/x/internal/net"
|
||||
serial "github.com/go-gost/x/internal/util/serial"
|
||||
"github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func (h *relayHandler) handleConnect(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) (err error) {
|
||||
@ -105,12 +107,20 @@ func (h *relayHandler) handleConnect(ctx context.Context, conn net.Conn, network
|
||||
}
|
||||
}
|
||||
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn, conn.RemoteAddr().String(),
|
||||
clientID := ctxvalue.ClientIDFromContext(ctx)
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn,
|
||||
traffic.NetworkOption(network),
|
||||
traffic.AddrOption(address),
|
||||
traffic.ClientOption(string(ctxvalue.ClientIDFromContext(ctx))),
|
||||
traffic.ClientOption(string(clientID)),
|
||||
traffic.SrcOption(conn.RemoteAddr().String()),
|
||||
)
|
||||
if h.options.Observer != nil {
|
||||
pstats := h.stats.Stats(string(clientID))
|
||||
pstats.Add(stats.KindTotalConns, 1)
|
||||
pstats.Add(stats.KindCurrentConns, 1)
|
||||
defer pstats.Add(stats.KindCurrentConns, -1)
|
||||
rw = stats_wrapper.WrapReadWriter(rw, pstats)
|
||||
}
|
||||
|
||||
t := time.Now()
|
||||
log.Infof("%s <-> %s", conn.RemoteAddr(), address)
|
||||
|
@ -13,6 +13,8 @@ import (
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
netpkg "github.com/go-gost/x/internal/net"
|
||||
"github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func (h *relayHandler) handleForward(ctx context.Context, conn net.Conn, network string, log logger.Logger) error {
|
||||
@ -87,12 +89,20 @@ func (h *relayHandler) handleForward(ctx context.Context, conn net.Conn, network
|
||||
conn = rc
|
||||
}
|
||||
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn, conn.RemoteAddr().String(),
|
||||
clientID := ctxvalue.ClientIDFromContext(ctx)
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn,
|
||||
traffic.NetworkOption(network),
|
||||
traffic.AddrOption(target.Addr),
|
||||
traffic.ClientOption(string(ctxvalue.ClientIDFromContext(ctx))),
|
||||
traffic.ClientOption(string(clientID)),
|
||||
traffic.SrcOption(conn.RemoteAddr().String()),
|
||||
)
|
||||
if h.options.Observer != nil {
|
||||
pstats := h.stats.Stats(string(clientID))
|
||||
pstats.Add(stats.KindTotalConns, 1)
|
||||
pstats.Add(stats.KindCurrentConns, 1)
|
||||
defer pstats.Add(stats.KindCurrentConns, -1)
|
||||
rw = stats_wrapper.WrapReadWriter(rw, pstats)
|
||||
}
|
||||
|
||||
t := time.Now()
|
||||
log.Debugf("%s <-> %s", conn.RemoteAddr(), target.Addr)
|
||||
|
@ -11,10 +11,10 @@ import (
|
||||
"github.com/go-gost/core/handler"
|
||||
"github.com/go-gost/core/hop"
|
||||
md "github.com/go-gost/core/metadata"
|
||||
"github.com/go-gost/core/service"
|
||||
"github.com/go-gost/relay"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats_util "github.com/go-gost/x/internal/util/stats"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -33,7 +33,8 @@ type relayHandler struct {
|
||||
router *chain.Router
|
||||
md metadata
|
||||
options handler.Options
|
||||
ep service.Service
|
||||
stats *stats_util.HandlerStats
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
@ -44,6 +45,7 @@ func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
|
||||
return &relayHandler{
|
||||
options: options,
|
||||
stats: stats_util.NewHandlerStats(options.Service),
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +59,13 @@ func (h *relayHandler) Init(md md.Metadata) (err error) {
|
||||
h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger))
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
h.cancel = cancel
|
||||
|
||||
if h.options.Observer != nil {
|
||||
go h.observeStats(ctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -172,8 +181,8 @@ func (h *relayHandler) Handle(ctx context.Context, conn net.Conn, opts ...handle
|
||||
|
||||
// Close implements io.Closer interface.
|
||||
func (h *relayHandler) Close() error {
|
||||
if h.ep != nil {
|
||||
return h.ep.Close()
|
||||
if h.cancel != nil {
|
||||
h.cancel()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -189,3 +198,21 @@ func (h *relayHandler) checkRateLimit(addr net.Addr) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *relayHandler) observeStats(ctx context.Context) {
|
||||
if h.options.Observer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
h.options.Observer.Observe(ctx, h.stats.Events())
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,9 @@ import (
|
||||
netpkg "github.com/go-gost/x/internal/net"
|
||||
"github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats_util "github.com/go-gost/x/internal/util/stats"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -32,6 +35,8 @@ type socks4Handler struct {
|
||||
router *chain.Router
|
||||
md metadata
|
||||
options handler.Options
|
||||
stats *stats_util.HandlerStats
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
@ -42,6 +47,7 @@ func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
|
||||
return &socks4Handler{
|
||||
options: options,
|
||||
stats: stats_util.NewHandlerStats(options.Service),
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,6 +61,13 @@ func (h *socks4Handler) Init(md md.Metadata) (err error) {
|
||||
h.router = chain.NewRouter(chain.LoggerRouterOption(h.options.Logger))
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
h.cancel = cancel
|
||||
|
||||
if h.options.Observer != nil {
|
||||
go h.observeStats(ctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -114,6 +127,13 @@ func (h *socks4Handler) Handle(ctx context.Context, conn net.Conn, opts ...handl
|
||||
}
|
||||
}
|
||||
|
||||
func (h *socks4Handler) Close() error {
|
||||
if h.cancel != nil {
|
||||
h.cancel()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *socks4Handler) handleConnect(ctx context.Context, conn net.Conn, req *gosocks4.Request, log logger.Logger) error {
|
||||
addr := req.Addr.String()
|
||||
|
||||
@ -151,12 +171,20 @@ func (h *socks4Handler) handleConnect(ctx context.Context, conn net.Conn, req *g
|
||||
return err
|
||||
}
|
||||
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn, conn.RemoteAddr().String(),
|
||||
clientID := ctxvalue.ClientIDFromContext(ctx)
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn,
|
||||
traffic.NetworkOption("tcp"),
|
||||
traffic.AddrOption(addr),
|
||||
traffic.ClientOption(string(ctxvalue.ClientIDFromContext(ctx))),
|
||||
traffic.ClientOption(string(clientID)),
|
||||
traffic.SrcOption(conn.RemoteAddr().String()),
|
||||
)
|
||||
if h.options.Observer != nil {
|
||||
pstats := h.stats.Stats(string(clientID))
|
||||
pstats.Add(stats.KindTotalConns, 1)
|
||||
pstats.Add(stats.KindCurrentConns, 1)
|
||||
defer pstats.Add(stats.KindCurrentConns, -1)
|
||||
rw = stats_wrapper.WrapReadWriter(rw, pstats)
|
||||
}
|
||||
|
||||
t := time.Now()
|
||||
log.Infof("%s <-> %s", conn.RemoteAddr(), addr)
|
||||
@ -184,3 +212,21 @@ func (h *socks4Handler) checkRateLimit(addr net.Addr) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *socks4Handler) observeStats(ctx context.Context) {
|
||||
if h.options.Observer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
h.options.Observer.Observe(ctx, h.stats.Events())
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ import (
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
netpkg "github.com/go-gost/x/internal/net"
|
||||
"github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func (h *socks5Handler) handleConnect(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error {
|
||||
@ -50,12 +52,20 @@ func (h *socks5Handler) handleConnect(ctx context.Context, conn net.Conn, networ
|
||||
return err
|
||||
}
|
||||
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn, conn.RemoteAddr().String(),
|
||||
clientID := ctxvalue.ClientIDFromContext(ctx)
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn,
|
||||
traffic.NetworkOption(network),
|
||||
traffic.AddrOption(address),
|
||||
traffic.ClientOption(string(ctxvalue.ClientIDFromContext(ctx))),
|
||||
traffic.ClientOption(string(clientID)),
|
||||
traffic.SrcOption(conn.RemoteAddr().String()),
|
||||
)
|
||||
if h.options.Observer != nil {
|
||||
pstats := h.stats.Stats(string(clientID))
|
||||
pstats.Add(stats.KindTotalConns, 1)
|
||||
pstats.Add(stats.KindCurrentConns, 1)
|
||||
defer pstats.Add(stats.KindCurrentConns, -1)
|
||||
rw = stats_wrapper.WrapReadWriter(rw, pstats)
|
||||
}
|
||||
|
||||
t := time.Now()
|
||||
log.Infof("%s <-> %s", conn.RemoteAddr(), address)
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/go-gost/gosocks5"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/util/socks"
|
||||
stats_util "github.com/go-gost/x/internal/util/stats"
|
||||
"github.com/go-gost/x/registry"
|
||||
)
|
||||
|
||||
@ -29,6 +30,8 @@ type socks5Handler struct {
|
||||
router *chain.Router
|
||||
md metadata
|
||||
options handler.Options
|
||||
stats *stats_util.HandlerStats
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
@ -39,6 +42,7 @@ func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
|
||||
return &socks5Handler{
|
||||
options: options,
|
||||
stats: stats_util.NewHandlerStats(options.Service),
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +63,13 @@ func (h *socks5Handler) Init(md md.Metadata) (err error) {
|
||||
noTLS: h.md.noTLS,
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
h.cancel = cancel
|
||||
|
||||
if h.options.Observer != nil {
|
||||
go h.observeStats(ctx)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -125,6 +136,13 @@ func (h *socks5Handler) Handle(ctx context.Context, conn net.Conn, opts ...handl
|
||||
}
|
||||
}
|
||||
|
||||
func (h *socks5Handler) Close() error {
|
||||
if h.cancel != nil {
|
||||
h.cancel()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *socks5Handler) checkRateLimit(addr net.Addr) bool {
|
||||
if h.options.RateLimiter == nil {
|
||||
return true
|
||||
@ -136,3 +154,21 @@ func (h *socks5Handler) checkRateLimit(addr net.Addr) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *socks5Handler) observeStats(ctx context.Context) {
|
||||
if h.options.Observer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
h.options.Observer.Observe(ctx, h.stats.Events())
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,11 @@ import (
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/gosocks5"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/net/udp"
|
||||
"github.com/go-gost/x/internal/util/socks"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, log logger.Logger) error {
|
||||
@ -67,7 +70,17 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, log logger
|
||||
return err
|
||||
}
|
||||
|
||||
r := udp.NewRelay(socks.UDPConn(cc, h.md.udpBufferSize), pc).
|
||||
var lc net.PacketConn = cc
|
||||
clientID := ctxvalue.ClientIDFromContext(ctx)
|
||||
if h.options.Observer != nil {
|
||||
pstats := h.stats.Stats(string(clientID))
|
||||
pstats.Add(stats.KindTotalConns, 1)
|
||||
pstats.Add(stats.KindCurrentConns, 1)
|
||||
defer pstats.Add(stats.KindCurrentConns, -1)
|
||||
lc = stats_wrapper.WrapPacketConn(lc, pstats)
|
||||
}
|
||||
|
||||
r := udp.NewRelay(socks.UDPConn(lc, h.md.udpBufferSize), pc).
|
||||
WithBypass(h.options.Bypass).
|
||||
WithLogger(log)
|
||||
r.SetBufferSize(h.md.udpBufferSize)
|
||||
|
@ -7,8 +7,11 @@ import (
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/gosocks5"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/net/udp"
|
||||
"github.com/go-gost/x/internal/util/socks"
|
||||
"github.com/go-gost/x/stats"
|
||||
stats_wrapper "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network, address string, log logger.Logger) error {
|
||||
@ -56,6 +59,15 @@ func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network
|
||||
}
|
||||
log.Debugf("bind on %s OK", pc.LocalAddr())
|
||||
|
||||
clientID := ctxvalue.ClientIDFromContext(ctx)
|
||||
if h.options.Observer != nil {
|
||||
pstats := h.stats.Stats(string(clientID))
|
||||
pstats.Add(stats.KindTotalConns, 1)
|
||||
pstats.Add(stats.KindCurrentConns, 1)
|
||||
defer pstats.Add(stats.KindCurrentConns, -1)
|
||||
conn = stats_wrapper.WrapConn(conn, pstats)
|
||||
}
|
||||
|
||||
r := udp.NewRelay(socks.UDPTunServerConn(conn), pc).
|
||||
WithBypass(h.options.Bypass).
|
||||
WithLogger(log)
|
||||
|
@ -100,7 +100,7 @@ func (h *tunnelHandler) handleConnect(ctx context.Context, req *relay.Request, c
|
||||
req.WriteTo(cc)
|
||||
}
|
||||
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn, tunnelID.String(),
|
||||
rw := wrapper.WrapReadWriter(h.options.Limiter, conn,
|
||||
traffic.NetworkOption(network),
|
||||
traffic.AddrOption(dstAddr),
|
||||
traffic.ClientOption(string(ctxvalue.ClientIDFromContext(ctx))),
|
||||
|
101
hop/plugin/grpc.go
Normal file
101
hop/plugin/grpc.go
Normal file
@ -0,0 +1,101 @@
|
||||
package hop
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/hop"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/hop/proto"
|
||||
"github.com/go-gost/x/config"
|
||||
node_parser "github.com/go-gost/x/config/parsing/node"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
name string
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.HopClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a Hop plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) hop.Hop {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "hop",
|
||||
"hop": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
name: name,
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewHopClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Select(ctx context.Context, opts ...hop.SelectOption) *chain.Node {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var options hop.SelectOptions
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
r, err := p.client.Select(ctx,
|
||||
&proto.SelectRequest{
|
||||
Network: options.Network,
|
||||
Addr: options.Addr,
|
||||
Host: options.Host,
|
||||
Path: options.Path,
|
||||
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||
Src: string(ctxvalue.ClientAddrFromContext(ctx)),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.Node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var cfg config.NodeConfig
|
||||
if err := json.NewDecoder(bytes.NewReader(r.Node)).Decode(&cfg); err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
node, err := node_parser.ParseNode(p.name, &cfg, logger.Default())
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -4,103 +4,17 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/chain"
|
||||
"github.com/go-gost/core/hop"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/hop/proto"
|
||||
"github.com/go-gost/x/config"
|
||||
node_parser "github.com/go-gost/x/config/parsing/node"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
name string
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.HopClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a Hop plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) hop.Hop {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "hop",
|
||||
"hop": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
name: name,
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewHopClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Select(ctx context.Context, opts ...hop.SelectOption) *chain.Node {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var options hop.SelectOptions
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
r, err := p.client.Select(ctx,
|
||||
&proto.SelectRequest{
|
||||
Network: options.Network,
|
||||
Addr: options.Addr,
|
||||
Host: options.Host,
|
||||
Path: options.Path,
|
||||
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||
Src: string(ctxvalue.ClientAddrFromContext(ctx)),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.Node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var cfg config.NodeConfig
|
||||
if err := json.NewDecoder(bytes.NewReader(r.Node)).Decode(&cfg); err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
node, err := node_parser.ParseNode(p.name, &cfg, logger.Default())
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginRequest struct {
|
||||
Network string `json:"network"`
|
||||
Addr string `json:"addr"`
|
78
hosts/plugin/grpc.go
Normal file
78
hosts/plugin/grpc.go
Normal file
@ -0,0 +1,78 @@
|
||||
package hosts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/go-gost/core/hosts"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/hosts/proto"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.HostMapperClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a HostMapper plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) hosts.HostMapper {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "hosts",
|
||||
"hosts": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewHostMapperClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Lookup(ctx context.Context, network, host string, opts ...hosts.Option) (ips []net.IP, ok bool) {
|
||||
p.log.Debugf("lookup %s/%s", host, network)
|
||||
|
||||
if p.client == nil {
|
||||
return
|
||||
}
|
||||
|
||||
r, err := p.client.Lookup(ctx,
|
||||
&proto.LookupRequest{
|
||||
Network: network,
|
||||
Host: host,
|
||||
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return
|
||||
}
|
||||
for _, s := range r.Ips {
|
||||
if ip := net.ParseIP(s); ip != nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
}
|
||||
ok = r.Ok
|
||||
return
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -4,82 +4,15 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/hosts"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/hosts/proto"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.HostMapperClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a HostMapper plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) hosts.HostMapper {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "hosts",
|
||||
"hosts": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewHostMapperClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Lookup(ctx context.Context, network, host string, opts ...hosts.Option) (ips []net.IP, ok bool) {
|
||||
p.log.Debugf("lookup %s/%s", host, network)
|
||||
|
||||
if p.client == nil {
|
||||
return
|
||||
}
|
||||
|
||||
r, err := p.client.Lookup(ctx,
|
||||
&proto.LookupRequest{
|
||||
Network: network,
|
||||
Host: host,
|
||||
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return
|
||||
}
|
||||
for _, s := range r.Ips {
|
||||
if ip := net.ParseIP(s); ip != nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
}
|
||||
ok = r.Ok
|
||||
return
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginRequest struct {
|
||||
Network string `json:"network"`
|
||||
Host string `json:"host"`
|
89
ingress/plugin/grpc.go
Normal file
89
ingress/plugin/grpc.go
Normal file
@ -0,0 +1,89 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/ingress"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/ingress/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.IngressClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Ingress plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) ingress.Ingress {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "ingress",
|
||||
"ingress": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewIngressClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) GetRule(ctx context.Context, host string, opts ...ingress.Option) *ingress.Rule {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
r, err := p.client.GetRule(ctx,
|
||||
&proto.GetRuleRequest{
|
||||
Host: host,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
if r.Endpoint == "" {
|
||||
return nil
|
||||
}
|
||||
return &ingress.Rule{
|
||||
Hostname: host,
|
||||
Endpoint: r.Endpoint,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) SetRule(ctx context.Context, rule *ingress.Rule, opts ...ingress.Option) bool {
|
||||
if p.client == nil || rule == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
r, _ := p.client.SetRule(ctx, &proto.SetRuleRequest{
|
||||
Host: rule.Hostname,
|
||||
Endpoint: rule.Endpoint,
|
||||
})
|
||||
if r == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return r.Ok
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -4,93 +4,13 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/ingress"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/ingress/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.IngressClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Ingress plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) ingress.Ingress {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "ingress",
|
||||
"ingress": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewIngressClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) GetRule(ctx context.Context, host string, opts ...ingress.Option) *ingress.Rule {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
r, err := p.client.GetRule(ctx,
|
||||
&proto.GetRuleRequest{
|
||||
Host: host,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
if r.Endpoint == "" {
|
||||
return nil
|
||||
}
|
||||
return &ingress.Rule{
|
||||
Hostname: host,
|
||||
Endpoint: r.Endpoint,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) SetRule(ctx context.Context, rule *ingress.Rule, opts ...ingress.Option) bool {
|
||||
if p.client == nil || rule == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
r, _ := p.client.SetRule(ctx, &proto.SetRuleRequest{
|
||||
Host: rule.Hostname,
|
||||
Endpoint: rule.Endpoint,
|
||||
})
|
||||
if r == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return r.Ok
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginGetRuleRequest struct {
|
||||
Host string `json:"host"`
|
||||
}
|
62
internal/util/stats/stats.go
Normal file
62
internal/util/stats/stats.go
Normal file
@ -0,0 +1,62 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/go-gost/core/observer"
|
||||
"github.com/go-gost/x/stats"
|
||||
)
|
||||
|
||||
type HandlerStats struct {
|
||||
service string
|
||||
stats map[string]*stats.Stats
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewHandlerStats(service string) *HandlerStats {
|
||||
return &HandlerStats{
|
||||
service: service,
|
||||
stats: make(map[string]*stats.Stats),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *HandlerStats) Stats(client string) *stats.Stats {
|
||||
p.mu.RLock()
|
||||
pstats := p.stats[client]
|
||||
p.mu.RUnlock()
|
||||
if pstats != nil {
|
||||
return pstats
|
||||
}
|
||||
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
pstats = p.stats[client]
|
||||
if pstats == nil {
|
||||
pstats = &stats.Stats{}
|
||||
}
|
||||
p.stats[client] = pstats
|
||||
|
||||
return pstats
|
||||
}
|
||||
|
||||
func (p *HandlerStats) Events() (events []observer.Event) {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
for k, v := range p.stats {
|
||||
if !v.IsUpdated() {
|
||||
continue
|
||||
}
|
||||
events = append(events, stats.StatsEvent{
|
||||
Kind: "handler",
|
||||
Service: p.service,
|
||||
Client: k,
|
||||
TotalConns: v.Get(stats.KindTotalConns),
|
||||
CurrentConns: v.Get(stats.KindCurrentConns),
|
||||
InputBytes: v.Get(stats.KindInputBytes),
|
||||
OutputBytes: v.Get(stats.KindOutputBytes),
|
||||
TotalErrs: v.Get(stats.KindTotalErrs),
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
102
limiter/traffic/plugin/grpc.go
Normal file
102
limiter/traffic/plugin/grpc.go
Normal file
@ -0,0 +1,102 @@
|
||||
package traffic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/limiter/traffic"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/limiter/traffic/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
xtraffic "github.com/go-gost/x/limiter/traffic"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.LimiterClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a traffic limiter plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) traffic.TrafficLimiter {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "limiter",
|
||||
"limiter": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewLimiterClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) In(ctx context.Context, key string, opts ...traffic.Option) traffic.Limiter {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var options traffic.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
r, err := p.client.Limit(ctx,
|
||||
&proto.LimitRequest{
|
||||
Network: options.Network,
|
||||
Addr: options.Addr,
|
||||
Client: options.Client,
|
||||
Src: options.Src,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return xtraffic.NewLimiter(int(r.In))
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Out(ctx context.Context, key string, opts ...traffic.Option) traffic.Limiter {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var options traffic.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
r, err := p.client.Limit(ctx,
|
||||
&proto.LimitRequest{
|
||||
Network: options.Network,
|
||||
Addr: options.Addr,
|
||||
Client: options.Client,
|
||||
Src: options.Src,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return xtraffic.NewLimiter(int(r.Out))
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -4,105 +4,14 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/limiter/traffic"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/plugin/limiter/traffic/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
xtraffic "github.com/go-gost/x/limiter/traffic"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.LimiterClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a traffic limiter plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) traffic.TrafficLimiter {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "limiter",
|
||||
"limiter": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewLimiterClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) In(ctx context.Context, key string, opts ...traffic.Option) traffic.Limiter {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var options traffic.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
r, err := p.client.Limit(ctx,
|
||||
&proto.LimitRequest{
|
||||
Network: options.Network,
|
||||
Addr: options.Addr,
|
||||
Client: options.Client,
|
||||
Src: options.Src,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return NewLimiter(int(r.In))
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Out(ctx context.Context, key string, opts ...traffic.Option) traffic.Limiter {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var options traffic.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
r, err := p.client.Limit(ctx,
|
||||
&proto.LimitRequest{
|
||||
Network: options.Network,
|
||||
Addr: options.Addr,
|
||||
Client: options.Client,
|
||||
Src: options.Src,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return NewLimiter(int(r.Out))
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginRequest struct {
|
||||
Network string `json:"network"`
|
||||
Addr string `json:"addr"`
|
||||
@ -184,7 +93,7 @@ func (p *httpPlugin) In(ctx context.Context, key string, opts ...traffic.Option)
|
||||
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
||||
return nil
|
||||
}
|
||||
return NewLimiter(int(res.In))
|
||||
return xtraffic.NewLimiter(int(res.In))
|
||||
}
|
||||
|
||||
func (p *httpPlugin) Out(ctx context.Context, key string, opts ...traffic.Option) traffic.Limiter {
|
||||
@ -231,5 +140,5 @@ func (p *httpPlugin) Out(ctx context.Context, key string, opts ...traffic.Option
|
||||
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
||||
return nil
|
||||
}
|
||||
return NewLimiter(int(res.Out))
|
||||
return xtraffic.NewLimiter(int(res.Out))
|
||||
}
|
@ -22,7 +22,7 @@ type readWriter struct {
|
||||
key string
|
||||
}
|
||||
|
||||
func WrapReadWriter(limiter limiter.TrafficLimiter, rw io.ReadWriter, key string, opts ...limiter.Option) io.ReadWriter {
|
||||
func WrapReadWriter(limiter limiter.TrafficLimiter, rw io.ReadWriter, opts ...limiter.Option) io.ReadWriter {
|
||||
if limiter == nil {
|
||||
return rw
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
md "github.com/go-gost/core/metadata"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
@ -117,6 +118,7 @@ func (l *dnsListener) Accept() (conn net.Conn, err error) {
|
||||
select {
|
||||
case conn = <-l.cqueue:
|
||||
conn = metrics.WrapConn(l.options.Service, conn)
|
||||
conn = stats.WrapConn(conn, l.options.Stats)
|
||||
conn = admission.WrapConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapConn(l.options.TrafficLimiter, conn)
|
||||
case err, ok = <-l.errChan:
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/pion/dtls/v2"
|
||||
)
|
||||
|
||||
@ -79,6 +80,7 @@ func (l *dtlsListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/xtaci/tcpraw"
|
||||
)
|
||||
|
||||
@ -52,6 +53,7 @@ func (l *ftcpListener) Init(md md.Metadata) (err error) {
|
||||
return
|
||||
}
|
||||
conn = metrics.WrapPacketConn(l.options.Service, conn)
|
||||
conn = stats.WrapPacketConn(conn, l.options.Stats)
|
||||
conn = admission.WrapPacketConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapPacketConn(l.options.TrafficLimiter, conn)
|
||||
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
@ -66,6 +67,7 @@ func (l *grpcListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
)
|
||||
@ -87,6 +88,7 @@ func (l *h2Listener) Init(md md.Metadata) (err error) {
|
||||
l.addr = ln.Addr()
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
mdx "github.com/go-gost/x/metadata"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
@ -76,6 +77,7 @@ func (l *http2Listener) Init(md md.Metadata) (err error) {
|
||||
l.addr = ln.Addr()
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/quic-go/quic-go"
|
||||
)
|
||||
|
||||
@ -85,6 +86,7 @@ func (l *http3Listener) Accept() (conn net.Conn, err error) {
|
||||
}
|
||||
|
||||
conn = metrics.WrapConn(l.options.Service, conn)
|
||||
conn = stats.WrapConn(conn, l.options.Stats)
|
||||
conn = admission.WrapConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapConn(l.options.TrafficLimiter, conn)
|
||||
return conn, nil
|
||||
|
@ -8,9 +8,13 @@ import (
|
||||
"github.com/go-gost/core/listener"
|
||||
"github.com/go-gost/core/logger"
|
||||
md "github.com/go-gost/core/metadata"
|
||||
admission "github.com/go-gost/x/admission/wrapper"
|
||||
xnet "github.com/go-gost/x/internal/net"
|
||||
wt_util "github.com/go-gost/x/internal/util/wt"
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
wt "github.com/quic-go/webtransport-go"
|
||||
@ -95,6 +99,10 @@ func (l *wtListener) Accept() (conn net.Conn, err error) {
|
||||
var ok bool
|
||||
select {
|
||||
case conn = <-l.cqueue:
|
||||
conn = metrics.WrapConn(l.options.Service, conn)
|
||||
conn = stats.WrapConn(conn, l.options.Stats)
|
||||
conn = admission.WrapConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapConn(l.options.TrafficLimiter, conn)
|
||||
case err, ok = <-l.errChan:
|
||||
if !ok {
|
||||
err = listener.ErrClosed
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/quic-go/quic-go"
|
||||
"golang.org/x/net/icmp"
|
||||
)
|
||||
@ -57,6 +58,7 @@ func (l *icmpListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
conn = icmp_pkg.ServerConn(conn)
|
||||
conn = metrics.WrapPacketConn(l.options.Service, conn)
|
||||
conn = stats.WrapPacketConn(conn, l.options.Stats)
|
||||
conn = admission.WrapPacketConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapPacketConn(l.options.TrafficLimiter, conn)
|
||||
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/xtaci/kcp-go/v5"
|
||||
"github.com/xtaci/smux"
|
||||
"github.com/xtaci/tcpraw"
|
||||
@ -75,6 +76,7 @@ func (l *kcpListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
|
||||
conn = metrics.WrapUDPConn(l.options.Service, conn)
|
||||
conn = stats.WrapUDPConn(conn, l.options.Stats)
|
||||
conn = admission.WrapUDPConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapUDPConn(l.options.TrafficLimiter, conn)
|
||||
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -66,6 +67,7 @@ func (l *mtcpListener) Init(md md.Metadata) (err error) {
|
||||
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -65,6 +66,7 @@ func (l *mtlsListener) Init(md md.Metadata) (err error) {
|
||||
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
@ -107,6 +108,7 @@ func (l *mwsListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -9,13 +9,13 @@ import (
|
||||
"github.com/go-gost/core/logger"
|
||||
md "github.com/go-gost/core/metadata"
|
||||
admission "github.com/go-gost/x/admission/wrapper"
|
||||
xnet "github.com/go-gost/x/internal/net"
|
||||
"github.com/go-gost/x/internal/net/proxyproto"
|
||||
climiter "github.com/go-gost/x/limiter/conn/wrapper"
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
|
||||
xnet "github.com/go-gost/x/internal/net"
|
||||
"github.com/go-gost/x/internal/net/proxyproto"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -61,6 +61,7 @@ func (l *obfsListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -60,6 +61,7 @@ func (l *obfsListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -92,6 +93,7 @@ func (l *phtListener) Accept() (conn net.Conn, err error) {
|
||||
return
|
||||
}
|
||||
conn = metrics.WrapConn(l.options.Service, conn)
|
||||
conn = stats.WrapConn(conn, l.options.Stats)
|
||||
conn = admission.WrapConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapConn(l.options.TrafficLimiter, conn)
|
||||
return
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/quic-go/quic-go"
|
||||
)
|
||||
|
||||
@ -102,6 +103,7 @@ func (l *quicListener) Accept() (conn net.Conn, err error) {
|
||||
select {
|
||||
case conn = <-l.cqueue:
|
||||
conn = metrics.WrapConn(l.options.Service, conn)
|
||||
conn = stats.WrapConn(conn, l.options.Stats)
|
||||
conn = admission.WrapConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapConn(l.options.TrafficLimiter, conn)
|
||||
case err, ok = <-l.errChan:
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -65,6 +66,7 @@ func (l *redirectListener) Init(md md.Metadata) (err error) {
|
||||
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -54,6 +55,7 @@ func (l *redirectListener) Accept() (conn net.Conn, err error) {
|
||||
return
|
||||
}
|
||||
conn = metrics.WrapConn(l.options.Service, conn)
|
||||
conn = stats.WrapConn(conn, l.options.Stats)
|
||||
conn = admission.WrapConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapConn(l.options.TrafficLimiter, conn)
|
||||
return
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -84,6 +85,7 @@ func (l *rtcpListener) Accept() (conn net.Conn, err error) {
|
||||
return nil, listener.NewAcceptError(err)
|
||||
}
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -105,6 +106,7 @@ func (l *rudpListener) Accept() (conn net.Conn, err error) {
|
||||
|
||||
if pc, ok := conn.(net.PacketConn); ok {
|
||||
uc := metrics.WrapUDPConn(l.options.Service, pc)
|
||||
uc = stats.WrapUDPConn(uc, l.options.Stats)
|
||||
uc = admission.WrapUDPConn(l.options.Admission, uc)
|
||||
conn = limiter.WrapUDPConn(l.options.TrafficLimiter, uc)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -95,6 +96,7 @@ func (l *serialListener) listenLoop() {
|
||||
|
||||
c := serial.NewConn(port, l.addr, cancel)
|
||||
c = metrics.WrapConn(l.options.Service, c)
|
||||
c = stats.WrapConn(c, l.options.Stats)
|
||||
c = limiter.WrapConn(l.options.TrafficLimiter, c)
|
||||
|
||||
l.cqueue <- c
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
@ -67,6 +68,7 @@ func (l *sshListener) Init(md md.Metadata) (err error) {
|
||||
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
"golang.org/x/crypto/ssh"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
// Applicable SSH Request types for Port Forwarding - RFC 4254 7.X
|
||||
@ -75,6 +76,7 @@ func (l *sshdListener) Init(md md.Metadata) (err error) {
|
||||
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
mdx "github.com/go-gost/x/metadata"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -90,6 +91,7 @@ func (l *tapListener) listenLoop() {
|
||||
cancel: cancel,
|
||||
}
|
||||
c = metrics.WrapConn(l.options.Service, c)
|
||||
c = stats.WrapConn(c, l.options.Stats)
|
||||
c = limiter.WrapConn(l.options.TrafficLimiter, c)
|
||||
c = withMetadata(mdx.NewMetadata(map[string]any{
|
||||
"config": l.md.config,
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -63,6 +64,7 @@ func (l *tcpListener) Init(md md.Metadata) (err error) {
|
||||
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -61,6 +62,7 @@ func (l *tlsListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
mdx "github.com/go-gost/x/metadata"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -27,7 +28,7 @@ type tunListener struct {
|
||||
logger logger.Logger
|
||||
md metadata
|
||||
options listener.Options
|
||||
routes []*router.Route
|
||||
routes []*router.Route
|
||||
}
|
||||
|
||||
func NewListener(opts ...listener.Option) listener.Listener {
|
||||
@ -91,6 +92,7 @@ func (l *tunListener) listenLoop() {
|
||||
cancel: cancel,
|
||||
}
|
||||
c = metrics.WrapConn(l.options.Service, c)
|
||||
c = stats.WrapConn(c, l.options.Stats)
|
||||
c = limiter.WrapConn(l.options.TrafficLimiter, c)
|
||||
c = withMetadata(mdx.NewMetadata(map[string]any{
|
||||
"config": l.md.config,
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -56,6 +57,7 @@ func (l *udpListener) Init(md md.Metadata) (err error) {
|
||||
return
|
||||
}
|
||||
conn = metrics.WrapPacketConn(l.options.Service, conn)
|
||||
conn = stats.WrapPacketConn(conn, l.options.Stats)
|
||||
conn = admission.WrapPacketConn(l.options.Admission, conn)
|
||||
conn = limiter.WrapPacketConn(l.options.TrafficLimiter, conn)
|
||||
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -46,6 +47,7 @@ func (l *unixListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
limiter "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
stats "github.com/go-gost/x/stats/wrapper"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
@ -102,6 +103,7 @@ func (l *wsListener) Init(md md.Metadata) (err error) {
|
||||
}
|
||||
ln = proxyproto.WrapListener(l.options.ProxyProtocol, ln, 10*time.Second)
|
||||
ln = metrics.WrapListener(l.options.Service, ln)
|
||||
ln = stats.WrapListener(ln, l.options.Stats)
|
||||
ln = admission.WrapListener(l.options.Admission, ln)
|
||||
ln = limiter.WrapListener(l.options.TrafficLimiter, ln)
|
||||
ln = climiter.WrapListener(l.options.ConnLimiter, ln)
|
||||
|
98
observer/plugin/grpc.go
Normal file
98
observer/plugin/grpc.go
Normal file
@ -0,0 +1,98 @@
|
||||
package observer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/observer"
|
||||
"github.com/go-gost/plugin/observer/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"github.com/go-gost/x/service"
|
||||
"github.com/go-gost/x/stats"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.ObserverClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Observer plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) observer.Observer {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "observer",
|
||||
"observer": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewObserverClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Observe(ctx context.Context, events []observer.Event, opts ...observer.Option) error {
|
||||
if p.client == nil || len(events) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var req proto.ObserveRequest
|
||||
|
||||
for _, event := range events {
|
||||
switch event.Type() {
|
||||
case observer.EventStatus:
|
||||
ev := event.(service.ServiceEvent)
|
||||
req.Events = append(req.Events, &proto.Event{
|
||||
Kind: ev.Kind,
|
||||
Service: ev.Service,
|
||||
Type: string(event.Type()),
|
||||
Status: &proto.ServiceStatus{
|
||||
State: string(ev.State),
|
||||
Msg: ev.Msg,
|
||||
},
|
||||
})
|
||||
case observer.EventStats:
|
||||
ev := event.(stats.StatsEvent)
|
||||
req.Events = append(req.Events, &proto.Event{
|
||||
Kind: ev.Kind,
|
||||
Service: ev.Service,
|
||||
Client: ev.Client,
|
||||
Type: string(event.Type()),
|
||||
Stats: &proto.Stats{
|
||||
TotalConns: ev.TotalConns,
|
||||
CurrentConns: ev.CurrentConns,
|
||||
InputBytes: ev.InputBytes,
|
||||
OutputBytes: ev.OutputBytes,
|
||||
TotalErrs: ev.TotalErrs,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
_, err := p.client.Observe(ctx, &req)
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
134
observer/plugin/http.go
Normal file
134
observer/plugin/http.go
Normal file
@ -0,0 +1,134 @@
|
||||
package observer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/observer"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"github.com/go-gost/x/service"
|
||||
"github.com/go-gost/x/stats"
|
||||
)
|
||||
|
||||
type observeRequest struct {
|
||||
Events []event `json:"events"`
|
||||
}
|
||||
|
||||
type event struct {
|
||||
Kind string `json:"kind"`
|
||||
Service string `json:"service"`
|
||||
Client string `json:"client,omitempty"`
|
||||
Type observer.EventType `json:"type"`
|
||||
Stats *statsEvent `json:"stats,omitempty"`
|
||||
Status *statusEvent `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type statsEvent struct {
|
||||
TotalConns uint64 `json:"totalConns"`
|
||||
CurrentConns uint64 `json:"currentConns"`
|
||||
InputBytes uint64 `json:"inputBytes"`
|
||||
OutputBytes uint64 `json:"outputBytes"`
|
||||
TotalErrs uint64 `json:"totalErrs"`
|
||||
}
|
||||
|
||||
type statusEvent struct {
|
||||
State string `json:"state"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
type observeResponse struct {
|
||||
OK bool `json:"ok"`
|
||||
}
|
||||
|
||||
type httpPlugin struct {
|
||||
url string
|
||||
client *http.Client
|
||||
header http.Header
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewHTTPPlugin creates an Observer plugin based on HTTP.
|
||||
func NewHTTPPlugin(name string, url string, opts ...plugin.Option) observer.Observer {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
return &httpPlugin{
|
||||
url: url,
|
||||
client: plugin.NewHTTPClient(&options),
|
||||
header: options.Header,
|
||||
log: logger.Default().WithFields(map[string]any{
|
||||
"kind": "observer",
|
||||
"observer": name,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *httpPlugin) Observe(ctx context.Context, events []observer.Event, opts ...observer.Option) error {
|
||||
if p.client == nil || len(events) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var r observeRequest
|
||||
|
||||
for _, e := range events {
|
||||
switch e.Type() {
|
||||
case observer.EventStatus:
|
||||
ev := e.(service.ServiceEvent)
|
||||
r.Events = append(r.Events, event{
|
||||
Kind: ev.Kind,
|
||||
Service: ev.Service,
|
||||
Type: ev.Type(),
|
||||
Status: &statusEvent{
|
||||
State: string(ev.State),
|
||||
Msg: ev.Msg,
|
||||
},
|
||||
})
|
||||
case observer.EventStats:
|
||||
ev := e.(stats.StatsEvent)
|
||||
r.Events = append(r.Events, event{
|
||||
Kind: ev.Kind,
|
||||
Service: ev.Service,
|
||||
Client: ev.Client,
|
||||
Type: ev.Type(),
|
||||
Stats: &statsEvent{
|
||||
TotalConns: ev.TotalConns,
|
||||
CurrentConns: ev.CurrentConns,
|
||||
InputBytes: ev.InputBytes,
|
||||
OutputBytes: ev.OutputBytes,
|
||||
TotalErrs: ev.TotalErrs,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
v, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, p.url, bytes.NewReader(v))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.header != nil {
|
||||
req.Header = p.header.Clone()
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := p.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf(resp.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
76
recorder/plugin/grpc.go
Normal file
76
recorder/plugin/grpc.go
Normal file
@ -0,0 +1,76 @@
|
||||
package recorder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/recorder"
|
||||
"github.com/go-gost/plugin/recorder/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.RecorderClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a Recorder plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) recorder.Recorder {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "recorder",
|
||||
"recorder": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewRecorderClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Record(ctx context.Context, b []byte, opts ...recorder.RecordOption) error {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var options recorder.RecordOptions
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
md, _ := json.Marshal(options.Metadata)
|
||||
|
||||
_, err := p.client.Record(ctx,
|
||||
&proto.RecordRequest{
|
||||
Data: b,
|
||||
Metadata: md,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -6,79 +6,13 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/recorder"
|
||||
"github.com/go-gost/plugin/recorder/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.RecorderClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a Recorder plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) recorder.Recorder {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "recorder",
|
||||
"recorder": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewRecorderClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Record(ctx context.Context, b []byte, opts ...recorder.RecordOption) error {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var options recorder.RecordOptions
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
md, _ := json.Marshal(options.Metadata)
|
||||
|
||||
_, err := p.client.Record(ctx,
|
||||
&proto.RecordRequest{
|
||||
Data: b,
|
||||
Metadata: md,
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginRequest struct {
|
||||
Data []byte `json:"data"`
|
||||
Metadata []byte `json:"metadata"`
|
39
registry/observer.go
Normal file
39
registry/observer.go
Normal file
@ -0,0 +1,39 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-gost/core/observer"
|
||||
)
|
||||
|
||||
type observerRegistry struct {
|
||||
registry[observer.Observer]
|
||||
}
|
||||
|
||||
func (r *observerRegistry) Register(name string, v observer.Observer) error {
|
||||
return r.registry.Register(name, v)
|
||||
}
|
||||
|
||||
func (r *observerRegistry) Get(name string) observer.Observer {
|
||||
if name != "" {
|
||||
return &observerWrapper{name: name, r: r}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *observerRegistry) get(name string) observer.Observer {
|
||||
return r.registry.Get(name)
|
||||
}
|
||||
|
||||
type observerWrapper struct {
|
||||
name string
|
||||
r *observerRegistry
|
||||
}
|
||||
|
||||
func (w *observerWrapper) Observe(ctx context.Context, events []observer.Event, opts ...observer.Option) error {
|
||||
v := w.r.get(w.name)
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v.Observe(ctx, events, opts...)
|
||||
}
|
@ -16,6 +16,7 @@ import (
|
||||
"github.com/go-gost/core/limiter/rate"
|
||||
"github.com/go-gost/core/limiter/traffic"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/observer"
|
||||
"github.com/go-gost/core/recorder"
|
||||
reg "github.com/go-gost/core/registry"
|
||||
"github.com/go-gost/core/resolver"
|
||||
@ -47,9 +48,10 @@ var (
|
||||
connLimiterReg reg.Registry[conn.ConnLimiter] = new(connLimiterRegistry)
|
||||
rateLimiterReg reg.Registry[rate.RateLimiter] = new(rateLimiterRegistry)
|
||||
|
||||
ingressReg reg.Registry[ingress.Ingress] = new(ingressRegistry)
|
||||
routerReg reg.Registry[router.Router] = new(routerRegistry)
|
||||
sdReg reg.Registry[sd.SD] = new(sdRegistry)
|
||||
ingressReg reg.Registry[ingress.Ingress] = new(ingressRegistry)
|
||||
routerReg reg.Registry[router.Router] = new(routerRegistry)
|
||||
sdReg reg.Registry[sd.SD] = new(sdRegistry)
|
||||
observerReg reg.Registry[observer.Observer] = new(observerRegistry)
|
||||
|
||||
loggerReg reg.Registry[logger.Logger] = new(loggerRegistry)
|
||||
)
|
||||
@ -179,6 +181,10 @@ func SDRegistry() reg.Registry[sd.SD] {
|
||||
return sdReg
|
||||
}
|
||||
|
||||
func ObserverRegistry() reg.Registry[observer.Observer] {
|
||||
return observerReg
|
||||
}
|
||||
|
||||
func LoggerRegistry() reg.Registry[logger.Logger] {
|
||||
return loggerReg
|
||||
}
|
||||
|
77
resolver/plugin/grpc.go
Normal file
77
resolver/plugin/grpc.go
Normal file
@ -0,0 +1,77 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/resolver"
|
||||
"github.com/go-gost/plugin/resolver/proto"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.ResolverClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a Resolver plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) (resolver.Resolver, error) {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "resolver",
|
||||
"resolover": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewResolverClient(conn)
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Resolve(ctx context.Context, network, host string, opts ...resolver.Option) (ips []net.IP, err error) {
|
||||
p.log.Debugf("resolve %s/%s", host, network)
|
||||
|
||||
if p.client == nil {
|
||||
return
|
||||
}
|
||||
|
||||
r, err := p.client.Resolve(ctx,
|
||||
&proto.ResolveRequest{
|
||||
Network: network,
|
||||
Host: host,
|
||||
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return
|
||||
}
|
||||
for _, s := range r.Ips {
|
||||
if ip := net.ParseIP(s); ip != nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -6,81 +6,15 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/resolver"
|
||||
"github.com/go-gost/plugin/resolver/proto"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.ResolverClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates a Resolver plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) (resolver.Resolver, error) {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "resolver",
|
||||
"resolover": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewResolverClient(conn)
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Resolve(ctx context.Context, network, host string, opts ...resolver.Option) (ips []net.IP, err error) {
|
||||
p.log.Debugf("resolve %s/%s", host, network)
|
||||
|
||||
if p.client == nil {
|
||||
return
|
||||
}
|
||||
|
||||
r, err := p.client.Resolve(ctx,
|
||||
&proto.ResolveRequest{
|
||||
Network: network,
|
||||
Host: host,
|
||||
Client: string(ctxvalue.ClientIDFromContext(ctx)),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return
|
||||
}
|
||||
for _, s := range r.Ips {
|
||||
if ip := net.ParseIP(s); ip != nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginRequest struct {
|
||||
Network string `json:"network"`
|
||||
Host string `json:"host"`
|
70
router/plugin/grpc.go
Normal file
70
router/plugin/grpc.go
Normal file
@ -0,0 +1,70 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/router"
|
||||
"github.com/go-gost/plugin/router/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
xrouter "github.com/go-gost/x/router"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.RouterClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Router plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) router.Router {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "router",
|
||||
"router": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewRouterClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) GetRoute(ctx context.Context, dst net.IP, opts ...router.Option) *router.Route {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
r, err := p.client.GetRoute(ctx,
|
||||
&proto.GetRouteRequest{
|
||||
Dst: dst.String(),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return xrouter.ParseRoute(r.Net, r.Gateway)
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -3,73 +3,15 @@ package router
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/router"
|
||||
"github.com/go-gost/plugin/router/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
xrouter "github.com/go-gost/x/router"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.RouterClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an Router plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) router.Router {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "router",
|
||||
"router": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewRouterClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) GetRoute(ctx context.Context, dst net.IP, opts ...router.Option) *router.Route {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
r, err := p.client.GetRoute(ctx,
|
||||
&proto.GetRouteRequest{
|
||||
Dst: dst.String(),
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return ParseRoute(r.Net, r.Gateway)
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPluginGetRouteRequest struct {
|
||||
Dst string `json:"dst"`
|
||||
}
|
||||
@ -137,5 +79,5 @@ func (p *httpPlugin) GetRoute(ctx context.Context, dst net.IP, opts ...router.Op
|
||||
return nil
|
||||
}
|
||||
|
||||
return ParseRoute(res.Net, res.Gateway)
|
||||
return xrouter.ParseRoute(res.Net, res.Gateway)
|
||||
}
|
134
sd/plugin/grpc.go
Normal file
134
sd/plugin/grpc.go
Normal file
@ -0,0 +1,134 @@
|
||||
package sd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/sd"
|
||||
"github.com/go-gost/plugin/sd/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.SDClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an SD plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) sd.SD {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "sd",
|
||||
"sd": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewSDClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Register(ctx context.Context, service *sd.Service, opts ...sd.Option) error {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := p.client.Register(ctx,
|
||||
&proto.RegisterRequest{
|
||||
Service: &proto.Service{
|
||||
Id: service.ID,
|
||||
Name: service.Name,
|
||||
Node: service.Node,
|
||||
Network: service.Network,
|
||||
Address: service.Address,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Deregister(ctx context.Context, service *sd.Service) error {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := p.client.Deregister(ctx, &proto.DeregisterRequest{
|
||||
Service: &proto.Service{
|
||||
Id: service.ID,
|
||||
Name: service.Name,
|
||||
Node: service.Node,
|
||||
Network: service.Network,
|
||||
Address: service.Address,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Renew(ctx context.Context, service *sd.Service) error {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := p.client.Renew(ctx, &proto.RenewRequest{
|
||||
Service: &proto.Service{
|
||||
Id: service.ID,
|
||||
Name: service.Name,
|
||||
Node: service.Node,
|
||||
Network: service.Network,
|
||||
Address: service.Address,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Get(ctx context.Context, name string) ([]*sd.Service, error) {
|
||||
if p.client == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
r, err := p.client.Get(ctx, &proto.GetServiceRequest{
|
||||
Name: name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*sd.Service
|
||||
for _, v := range r.Services {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
services = append(services, &sd.Service{
|
||||
Node: v.Node,
|
||||
Name: v.Name,
|
||||
Network: v.Network,
|
||||
Address: v.Address,
|
||||
})
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,142 +1,17 @@
|
||||
package ingress
|
||||
package sd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/sd"
|
||||
"github.com/go-gost/plugin/sd/proto"
|
||||
"github.com/go-gost/x/internal/plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcPlugin struct {
|
||||
conn grpc.ClientConnInterface
|
||||
client proto.SDClient
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
// NewGRPCPlugin creates an SD plugin based on gRPC.
|
||||
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) sd.SD {
|
||||
var options plugin.Options
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
log := logger.Default().WithFields(map[string]any{
|
||||
"kind": "sd",
|
||||
"sd": name,
|
||||
})
|
||||
conn, err := plugin.NewGRPCConn(addr, &options)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
p := &grpcPlugin{
|
||||
conn: conn,
|
||||
log: log,
|
||||
}
|
||||
if conn != nil {
|
||||
p.client = proto.NewSDClient(conn)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Register(ctx context.Context, service *sd.Service, opts ...sd.Option) error {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := p.client.Register(ctx,
|
||||
&proto.RegisterRequest{
|
||||
Service: &proto.Service{
|
||||
Id: service.ID,
|
||||
Name: service.Name,
|
||||
Node: service.Node,
|
||||
Network: service.Network,
|
||||
Address: service.Address,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
p.log.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Deregister(ctx context.Context, service *sd.Service) error {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := p.client.Deregister(ctx, &proto.DeregisterRequest{
|
||||
Service: &proto.Service{
|
||||
Id: service.ID,
|
||||
Name: service.Name,
|
||||
Node: service.Node,
|
||||
Network: service.Network,
|
||||
Address: service.Address,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Renew(ctx context.Context, service *sd.Service) error {
|
||||
if p.client == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := p.client.Renew(ctx, &proto.RenewRequest{
|
||||
Service: &proto.Service{
|
||||
Id: service.ID,
|
||||
Name: service.Name,
|
||||
Node: service.Node,
|
||||
Network: service.Network,
|
||||
Address: service.Address,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Get(ctx context.Context, name string) ([]*sd.Service, error) {
|
||||
if p.client == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
r, err := p.client.Get(ctx, &proto.GetServiceRequest{
|
||||
Name: name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*sd.Service
|
||||
for _, v := range r.Services {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
services = append(services, &sd.Service{
|
||||
Node: v.Node,
|
||||
Name: v.Name,
|
||||
Network: v.Network,
|
||||
Address: v.Address,
|
||||
})
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (p *grpcPlugin) Close() error {
|
||||
if closer, ok := p.conn.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type sdService struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os/exec"
|
||||
@ -13,10 +14,12 @@ import (
|
||||
"github.com/go-gost/core/listener"
|
||||
"github.com/go-gost/core/logger"
|
||||
"github.com/go-gost/core/metrics"
|
||||
"github.com/go-gost/core/observer"
|
||||
"github.com/go-gost/core/recorder"
|
||||
"github.com/go-gost/core/service"
|
||||
ctxvalue "github.com/go-gost/x/internal/ctx"
|
||||
xmetrics "github.com/go-gost/x/metrics"
|
||||
"github.com/go-gost/x/stats"
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
||||
@ -27,6 +30,8 @@ type options struct {
|
||||
postUp []string
|
||||
preDown []string
|
||||
postDown []string
|
||||
stats *stats.Stats
|
||||
observer observer.Observer
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
@ -68,6 +73,18 @@ func PostDownOption(cmds []string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func StatsOption(stats *stats.Stats) Option {
|
||||
return func(opts *options) {
|
||||
opts.stats = stats
|
||||
}
|
||||
}
|
||||
|
||||
func ObserverOption(observer observer.Observer) Option {
|
||||
return func(opts *options) {
|
||||
opts.observer = observer
|
||||
}
|
||||
}
|
||||
|
||||
func LoggerOption(logger logger.Logger) Option {
|
||||
return func(opts *options) {
|
||||
opts.logger = logger
|
||||
@ -78,6 +95,7 @@ type defaultService struct {
|
||||
name string
|
||||
listener listener.Listener
|
||||
handler handler.Handler
|
||||
status *Status
|
||||
options options
|
||||
}
|
||||
|
||||
@ -91,7 +109,13 @@ func NewService(name string, ln listener.Listener, h handler.Handler, opts ...Op
|
||||
listener: ln,
|
||||
handler: h,
|
||||
options: options,
|
||||
status: &Status{
|
||||
createTime: time.Now(),
|
||||
events: make([]Event, 0, MaxEventSize),
|
||||
stats: options.stats,
|
||||
},
|
||||
}
|
||||
s.setState(StateRunning)
|
||||
|
||||
s.execCmds("pre-up", s.options.preUp)
|
||||
|
||||
@ -104,6 +128,14 @@ func (s *defaultService) Addr() net.Addr {
|
||||
|
||||
func (s *defaultService) Serve() error {
|
||||
s.execCmds("post-up", s.options.postUp)
|
||||
s.setState(StateReady)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
if s.status.Stats() != nil {
|
||||
go s.observeStats(ctx)
|
||||
}
|
||||
|
||||
if v := xmetrics.GetGauge(
|
||||
xmetrics.MetricServicesGauge,
|
||||
@ -126,14 +158,25 @@ func (s *defaultService) Serve() error {
|
||||
if max := 5 * time.Second; tempDelay > max {
|
||||
tempDelay = max
|
||||
}
|
||||
|
||||
s.setState(StateFailed)
|
||||
|
||||
s.options.logger.Warnf("accept: %v, retrying in %v", e, tempDelay)
|
||||
time.Sleep(tempDelay)
|
||||
continue
|
||||
}
|
||||
s.setState(StateClosed)
|
||||
s.options.logger.Errorf("accept: %v", e)
|
||||
|
||||
return e
|
||||
}
|
||||
tempDelay = 0
|
||||
|
||||
if tempDelay > 0 {
|
||||
tempDelay = 0
|
||||
s.setState(StateReady)
|
||||
}
|
||||
|
||||
s.status.stats.Add(stats.KindTotalConns, 1)
|
||||
|
||||
clientAddr := conn.RemoteAddr().String()
|
||||
clientIP := clientAddr
|
||||
@ -141,7 +184,7 @@ func (s *defaultService) Serve() error {
|
||||
clientIP = h
|
||||
}
|
||||
|
||||
ctx := ctxvalue.ContextWithSid(context.Background(), ctxvalue.Sid(xid.New().String()))
|
||||
ctx := ctxvalue.ContextWithSid(ctx, ctxvalue.Sid(xid.New().String()))
|
||||
ctx = ctxvalue.ContextWithClientAddr(ctx, ctxvalue.ClientAddr(clientAddr))
|
||||
ctx = ctxvalue.ContextWithHash(ctx, &ctxvalue.Hash{Source: clientIP})
|
||||
|
||||
@ -161,6 +204,9 @@ func (s *defaultService) Serve() error {
|
||||
}
|
||||
|
||||
go func() {
|
||||
s.status.stats.Add(stats.KindCurrentConns, 1)
|
||||
defer s.status.stats.Add(stats.KindCurrentConns, -1)
|
||||
|
||||
if v := xmetrics.GetCounter(xmetrics.MetricServiceRequestsCounter,
|
||||
metrics.Labels{"service": s.name, "client": clientIP}); v != nil {
|
||||
v.Inc()
|
||||
@ -186,11 +232,16 @@ func (s *defaultService) Serve() error {
|
||||
metrics.Labels{"service": s.name, "client": clientIP}); v != nil {
|
||||
v.Inc()
|
||||
}
|
||||
s.status.stats.Add(stats.KindTotalErrs, 1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *defaultService) Status() *Status {
|
||||
return s.status
|
||||
}
|
||||
|
||||
func (s *defaultService) Close() error {
|
||||
s.execCmds("pre-down", s.options.preDown)
|
||||
defer s.execCmds("post-down", s.options.postDown)
|
||||
@ -214,3 +265,64 @@ func (s *defaultService) execCmds(phase string, cmds []string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *defaultService) setState(state State) {
|
||||
s.status.setState(state)
|
||||
|
||||
msg := fmt.Sprintf("service %s is %s", s.name, state)
|
||||
s.status.addEvent(Event{
|
||||
Time: time.Now(),
|
||||
Message: msg,
|
||||
})
|
||||
|
||||
if obs := s.options.observer; obs != nil {
|
||||
obs.Observe(context.Background(), []observer.Event{ServiceEvent{
|
||||
Kind: "service",
|
||||
Service: s.name,
|
||||
State: state,
|
||||
Msg: msg,
|
||||
}})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *defaultService) observeStats(ctx context.Context) {
|
||||
if s.options.observer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
st := s.status.Stats()
|
||||
if !st.IsUpdated() {
|
||||
break
|
||||
}
|
||||
s.options.observer.Observe(ctx, []observer.Event{
|
||||
stats.StatsEvent{
|
||||
Kind: "service",
|
||||
Service: s.name,
|
||||
TotalConns: st.Get(stats.KindTotalConns),
|
||||
CurrentConns: st.Get(stats.KindCurrentConns),
|
||||
InputBytes: st.Get(stats.KindInputBytes),
|
||||
OutputBytes: st.Get(stats.KindOutputBytes),
|
||||
},
|
||||
})
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ServiceEvent struct {
|
||||
Kind string
|
||||
Service string
|
||||
State State
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (ServiceEvent) Type() observer.EventType {
|
||||
return observer.EventStatus
|
||||
}
|
||||
|
76
service/status.go
Normal file
76
service/status.go
Normal file
@ -0,0 +1,76 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/x/stats"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxEventSize = 20
|
||||
)
|
||||
|
||||
type State string
|
||||
|
||||
const (
|
||||
StateRunning State = "running"
|
||||
StateReady State = "ready"
|
||||
StateFailed State = "failed"
|
||||
StateClosed State = "closed"
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Time time.Time
|
||||
Message string
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
createTime time.Time
|
||||
state State
|
||||
events []Event
|
||||
stats *stats.Stats
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (p *Status) CreateTime() time.Time {
|
||||
return p.createTime
|
||||
}
|
||||
|
||||
func (p *Status) State() State {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
return p.state
|
||||
}
|
||||
|
||||
func (p *Status) setState(state State) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.state = state
|
||||
}
|
||||
|
||||
func (p *Status) Events() []Event {
|
||||
events := make([]Event, MaxEventSize)
|
||||
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
copy(events, p.events)
|
||||
return events
|
||||
}
|
||||
|
||||
func (p *Status) addEvent(event Event) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if len(p.events) == MaxEventSize {
|
||||
events := make([]Event, MaxEventSize-1, MaxEventSize)
|
||||
copy(events, p.events[1:])
|
||||
p.events = events
|
||||
}
|
||||
p.events = append(p.events, event)
|
||||
}
|
||||
|
||||
func (p *Status) Stats() *stats.Stats {
|
||||
return p.stats
|
||||
}
|
93
stats/stats.go
Normal file
93
stats/stats.go
Normal file
@ -0,0 +1,93 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/go-gost/core/observer"
|
||||
)
|
||||
|
||||
type Kind int
|
||||
|
||||
const (
|
||||
KindTotalConns Kind = 1
|
||||
KindCurrentConns Kind = 2
|
||||
KindInputBytes Kind = 3
|
||||
KindOutputBytes Kind = 4
|
||||
KindTotalErrs Kind = 5
|
||||
)
|
||||
|
||||
type Stats struct {
|
||||
updated atomic.Bool
|
||||
totalConns atomic.Uint64
|
||||
currentConns atomic.Int64
|
||||
inputBytes atomic.Uint64
|
||||
outputBytes atomic.Uint64
|
||||
totalErrs atomic.Uint64
|
||||
}
|
||||
|
||||
func (s *Stats) Add(kind Kind, n int64) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
switch kind {
|
||||
case KindTotalConns:
|
||||
if n > 0 {
|
||||
s.totalConns.Add(uint64(n))
|
||||
}
|
||||
case KindCurrentConns:
|
||||
s.currentConns.Add(n)
|
||||
case KindInputBytes:
|
||||
if n > 0 {
|
||||
s.inputBytes.Add(uint64(n))
|
||||
}
|
||||
case KindOutputBytes:
|
||||
if n > 0 {
|
||||
s.outputBytes.Add(uint64(n))
|
||||
}
|
||||
case KindTotalErrs:
|
||||
if n > 0 {
|
||||
s.totalErrs.Add(uint64(n))
|
||||
}
|
||||
}
|
||||
s.updated.Store(true)
|
||||
}
|
||||
|
||||
func (s *Stats) Get(kind Kind) uint64 {
|
||||
if s == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case KindTotalConns:
|
||||
return s.totalConns.Load()
|
||||
case KindCurrentConns:
|
||||
return uint64(s.currentConns.Load())
|
||||
case KindInputBytes:
|
||||
return s.inputBytes.Load()
|
||||
case KindOutputBytes:
|
||||
return s.outputBytes.Load()
|
||||
case KindTotalErrs:
|
||||
return s.totalErrs.Load()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *Stats) IsUpdated() bool {
|
||||
return s.updated.Swap(false)
|
||||
}
|
||||
|
||||
type StatsEvent struct {
|
||||
Kind string
|
||||
Service string
|
||||
Client string
|
||||
|
||||
TotalConns uint64
|
||||
CurrentConns uint64
|
||||
InputBytes uint64
|
||||
OutputBytes uint64
|
||||
TotalErrs uint64
|
||||
}
|
||||
|
||||
func (StatsEvent) Type() observer.EventType {
|
||||
return observer.EventStats
|
||||
}
|
222
stats/wrapper/conn.go
Normal file
222
stats/wrapper/conn.go
Normal file
@ -0,0 +1,222 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/go-gost/core/metadata"
|
||||
xnet "github.com/go-gost/x/internal/net"
|
||||
"github.com/go-gost/x/internal/net/udp"
|
||||
"github.com/go-gost/x/stats"
|
||||
)
|
||||
|
||||
var (
|
||||
errUnsupport = errors.New("unsupported operation")
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
net.Conn
|
||||
stats *stats.Stats
|
||||
}
|
||||
|
||||
func WrapConn(c net.Conn, stats *stats.Stats) net.Conn {
|
||||
if stats == nil {
|
||||
return c
|
||||
}
|
||||
|
||||
return &conn{
|
||||
Conn: c,
|
||||
stats: stats,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) Read(b []byte) (n int, err error) {
|
||||
n, err = c.Conn.Read(b)
|
||||
c.stats.Add(stats.KindInputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
func (c *conn) Write(b []byte) (n int, err error) {
|
||||
n, err = c.Conn.Write(b)
|
||||
c.stats.Add(stats.KindOutputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
func (c *conn) SyscallConn() (rc syscall.RawConn, err error) {
|
||||
if sc, ok := c.Conn.(syscall.Conn); ok {
|
||||
rc, err = sc.SyscallConn()
|
||||
return
|
||||
}
|
||||
err = errUnsupport
|
||||
return
|
||||
}
|
||||
|
||||
func (c *conn) Metadata() metadata.Metadata {
|
||||
if md, ok := c.Conn.(metadata.Metadatable); ok {
|
||||
return md.Metadata()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type packetConn struct {
|
||||
net.PacketConn
|
||||
stats *stats.Stats
|
||||
}
|
||||
|
||||
func WrapPacketConn(pc net.PacketConn, stats *stats.Stats) net.PacketConn {
|
||||
if stats == nil {
|
||||
return pc
|
||||
}
|
||||
return &packetConn{
|
||||
PacketConn: pc,
|
||||
stats: stats,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *packetConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
n, addr, err = c.PacketConn.ReadFrom(p)
|
||||
c.stats.Add(stats.KindInputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
func (c *packetConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
n, err = c.PacketConn.WriteTo(p, addr)
|
||||
c.stats.Add(stats.KindOutputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
func (c *packetConn) Metadata() metadata.Metadata {
|
||||
if md, ok := c.PacketConn.(metadata.Metadatable); ok {
|
||||
return md.Metadata()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type udpConn struct {
|
||||
net.PacketConn
|
||||
stats *stats.Stats
|
||||
}
|
||||
|
||||
func WrapUDPConn(pc net.PacketConn, stats *stats.Stats) udp.Conn {
|
||||
return &udpConn{
|
||||
PacketConn: pc,
|
||||
stats: stats,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *udpConn) RemoteAddr() net.Addr {
|
||||
if nc, ok := c.PacketConn.(xnet.RemoteAddr); ok {
|
||||
return nc.RemoteAddr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *udpConn) SetReadBuffer(n int) error {
|
||||
if nc, ok := c.PacketConn.(xnet.SetBuffer); ok {
|
||||
return nc.SetReadBuffer(n)
|
||||
}
|
||||
return errUnsupport
|
||||
}
|
||||
|
||||
func (c *udpConn) SetWriteBuffer(n int) error {
|
||||
if nc, ok := c.PacketConn.(xnet.SetBuffer); ok {
|
||||
return nc.SetWriteBuffer(n)
|
||||
}
|
||||
return errUnsupport
|
||||
}
|
||||
|
||||
func (c *udpConn) Read(b []byte) (n int, err error) {
|
||||
if nc, ok := c.PacketConn.(io.Reader); ok {
|
||||
n, err = nc.Read(b)
|
||||
c.stats.Add(stats.KindInputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
err = errUnsupport
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
n, addr, err = c.PacketConn.ReadFrom(p)
|
||||
c.stats.Add(stats.KindInputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
|
||||
if nc, ok := c.PacketConn.(udp.ReadUDP); ok {
|
||||
n, addr, err = nc.ReadFromUDP(b)
|
||||
c.stats.Add(stats.KindInputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
err = errUnsupport
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error) {
|
||||
if nc, ok := c.PacketConn.(udp.ReadUDP); ok {
|
||||
n, oobn, flags, addr, err = nc.ReadMsgUDP(b, oob)
|
||||
c.stats.Add(stats.KindInputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
err = errUnsupport
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) Write(b []byte) (n int, err error) {
|
||||
if nc, ok := c.PacketConn.(io.Writer); ok {
|
||||
n, err = nc.Write(b)
|
||||
c.stats.Add(stats.KindOutputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
err = errUnsupport
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
n, err = c.PacketConn.WriteTo(p, addr)
|
||||
c.stats.Add(stats.KindOutputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) {
|
||||
if nc, ok := c.PacketConn.(udp.WriteUDP); ok {
|
||||
n, err = nc.WriteToUDP(b, addr)
|
||||
c.stats.Add(stats.KindOutputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
err = errUnsupport
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) {
|
||||
if nc, ok := c.PacketConn.(udp.WriteUDP); ok {
|
||||
n, oobn, err = nc.WriteMsgUDP(b, oob, addr)
|
||||
c.stats.Add(stats.KindOutputBytes, int64(n))
|
||||
return
|
||||
}
|
||||
err = errUnsupport
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) SyscallConn() (rc syscall.RawConn, err error) {
|
||||
if nc, ok := c.PacketConn.(syscall.Conn); ok {
|
||||
return nc.SyscallConn()
|
||||
}
|
||||
err = errUnsupport
|
||||
return
|
||||
}
|
||||
|
||||
func (c *udpConn) SetDSCP(n int) error {
|
||||
if nc, ok := c.PacketConn.(xnet.SetDSCP); ok {
|
||||
return nc.SetDSCP(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *udpConn) Metadata() metadata.Metadata {
|
||||
if md, ok := c.PacketConn.(metadata.Metadatable); ok {
|
||||
return md.Metadata()
|
||||
}
|
||||
return nil
|
||||
}
|
38
stats/wrapper/io.go
Normal file
38
stats/wrapper/io.go
Normal file
@ -0,0 +1,38 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/go-gost/x/stats"
|
||||
)
|
||||
|
||||
// readWriter is an io.ReadWriter with Stats.
|
||||
type readWriter struct {
|
||||
io.ReadWriter
|
||||
stats *stats.Stats
|
||||
}
|
||||
|
||||
func WrapReadWriter(rw io.ReadWriter, stats *stats.Stats) io.ReadWriter {
|
||||
if stats == nil {
|
||||
return rw
|
||||
}
|
||||
|
||||
return &readWriter{
|
||||
ReadWriter: rw,
|
||||
stats: stats,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *readWriter) Read(b []byte) (n int, err error) {
|
||||
n, err = p.ReadWriter.Read(b)
|
||||
p.stats.Add(stats.KindInputBytes, int64(n))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *readWriter) Write(b []byte) (n int, err error) {
|
||||
n, err = p.ReadWriter.Write(b)
|
||||
p.stats.Add(stats.KindOutputBytes, int64(n))
|
||||
|
||||
return
|
||||
}
|
32
stats/wrapper/listener.go
Normal file
32
stats/wrapper/listener.go
Normal file
@ -0,0 +1,32 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/go-gost/x/stats"
|
||||
)
|
||||
|
||||
type listener struct {
|
||||
stats *stats.Stats
|
||||
net.Listener
|
||||
}
|
||||
|
||||
func WrapListener(ln net.Listener, stats *stats.Stats) net.Listener {
|
||||
if stats == nil {
|
||||
return ln
|
||||
}
|
||||
|
||||
return &listener{
|
||||
stats: stats,
|
||||
Listener: ln,
|
||||
}
|
||||
}
|
||||
|
||||
func (ln *listener) Accept() (net.Conn, error) {
|
||||
c, err := ln.Listener.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return WrapConn(c, ln.stats), nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user