Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
661 views
in Technique[技术] by (71.8m points)

go 1.8 plugin use custom interface

I want to use custom interface based on go plugin, but I found it's not support.

Definition of filter.Filter

package filter

import (
    "net/http"

    "github.com/valyala/fasthttp"
)

// Context filter context
type Context interface {
    SetStartAt(startAt int64)
    SetEndAt(endAt int64)
    GetStartAt() int64
    GetEndAt() int64

    GetProxyServerAddr() string
    GetProxyOuterRequest() *fasthttp.Request
    GetProxyResponse() *fasthttp.Response
    NeedMerge() bool

    GetOriginRequestCtx() *fasthttp.RequestCtx

    GetMaxQPS() int

    ValidateProxyOuterRequest() bool

    InBlacklist(ip string) bool
    InWhitelist(ip string) bool

    IsCircuitOpen() bool
    IsCircuitHalf() bool

    GetOpenToCloseFailureRate() int
    GetHalfTrafficRate() int
    GetHalfToOpenSucceedRate() int
    GetOpenToCloseCollectSeconds() int

    ChangeCircuitStatusToClose()
    ChangeCircuitStatusToOpen()

    RecordMetricsForRequest()
    RecordMetricsForResponse()
    RecordMetricsForFailure()
    RecordMetricsForReject()

    GetRecentlyRequestSuccessedCount(sec int) int
    GetRecentlyRequestCount(sec int) int
    GetRecentlyRequestFailureCount(sec int) int
}

// Filter filter interface
type Filter interface {
    Name() string

    Pre(c Context) (statusCode int, err error)
    Post(c Context) (statusCode int, err error)
    PostErr(c Context)
}

// BaseFilter base filter support default implemention
type BaseFilter struct{}

// Pre execute before proxy
func (f BaseFilter) Pre(c Context) (statusCode int, err error) {
    return http.StatusOK, nil
}

// Post execute after proxy
func (f BaseFilter) Post(c Context) (statusCode int, err error) {
    return http.StatusOK, nil
}

// PostErr execute proxy has errors
func (f BaseFilter) PostErr(c Context) {

}

This pkg is in my go app project.

load plugin file

package proxy

import (
    "errors"
    "plugin"
    "strings"

    "github.com/fagongzi/gateway/pkg/conf"
    "github.com/fagongzi/gateway/pkg/filter"
)

var (
    // ErrKnownFilter known filter error
    ErrKnownFilter = errors.New("unknow filter")
)

const (
    // FilterHTTPAccess access log filter
    FilterHTTPAccess = "HTTP-ACCESS"
    // FilterHeader header filter
    FilterHeader = "HEAD" // process header fiter
    // FilterXForward xforward fiter
    FilterXForward = "XFORWARD"
    // FilterBlackList blacklist filter
    FilterBlackList = "BLACKLIST"
    // FilterWhiteList whitelist filter
    FilterWhiteList = "WHITELIST"
    // FilterAnalysis analysis filter
    FilterAnalysis = "ANALYSIS"
    // FilterRateLimiting limit filter
    FilterRateLimiting = "RATE-LIMITING"
    // FilterCircuitBreake circuit breake filter
    FilterCircuitBreake = "CIRCUIT-BREAKE"
    // FilterValidation validation request filter
    FilterValidation = "VALIDATION"
)

func newFilter(filterSpec *conf.FilterSpec) (filter.Filter, error) {
    if filterSpec.External {
        return newExternalFilter(filterSpec)
    }

    input := strings.ToUpper(filterSpec.Name)

    switch input {
    case FilterHTTPAccess:
        return newAccessFilter(), nil
    case FilterHeader:
        return newHeadersFilter(), nil
    case FilterXForward:
        return newXForwardForFilter(), nil
    case FilterAnalysis:
        return newAnalysisFilter(), nil
    case FilterBlackList:
        return newBlackListFilter(), nil
    case FilterWhiteList:
        return newWhiteListFilter(), nil
    case FilterRateLimiting:
        return newRateLimitingFilter(), nil
    case FilterCircuitBreake:
        return newCircuitBreakeFilter(), nil
    case FilterValidation:
        return newValidationFilter(), nil
    default:
        return nil, ErrKnownFilter
    }
}

func newExternalFilter(filterSpec *conf.FilterSpec) (filter.Filter, error) {
    p, err := plugin.Open(filterSpec.ExternalPluginFile)
    if err != nil {
        return nil, err
    }

    s, err := p.Lookup("NewExternalFilter")
    if err != nil {
        return nil, err
    }

    sf := s.(func() (filter.Filter, error))
    return sf()
}

This is the code of load plugin in my go app project

package main

import (
    "C"
    "strings"
    "time"

    "github.com/CodisLabs/codis/pkg/utils/log"
    "github.com/fagongzi/gateway/pkg/filter"
    "github.com/valyala/fasthttp"
)

// AccessFilter record the http access log
// log format: $remoteip "$method $path" $code "$agent" $svr $cost
type AccessFilter struct {
}

// NewExternalFilter create a External filter
func NewExternalFilter() (filter.Filter, error) {
    return &AccessFilter{}, nil
}

// Name return name of this filter
func (f *AccessFilter) Name() string {
    return "HTTP-ACCESS"
}

// Pre pre process
func (f *AccessFilter) Pre(c filter.Context) (statusCode int, err error) {
    return 200, nil
}

// Post execute after proxy
func (f *AccessFilter) Post(c filter.Context) (statusCode int, err error) {
    cost := (c.GetStartAt() - c.GetEndAt())

    log.Infof("%s %s "%s" %d "%s" %s %s",
        GetRealClientIP(c.GetOriginRequestCtx()),
        c.GetOriginRequestCtx().Method(),
        c.GetProxyOuterRequest().RequestURI(),
        c.GetProxyResponse().StatusCode(),
        c.GetOriginRequestCtx().UserAgent(),
        c.GetProxyServerAddr(),
        time.Duration(cost))

    return 200, nil
}

// PostErr post error process
func (f *AccessFilter) PostErr(c filter.Context) {

}

// GetRealClientIP get read client ip
func GetRealClientIP(ctx *fasthttp.RequestCtx) string {
    xforward := ctx.Request.Header.Peek("X-Forwarded-For")
    if nil == xforward {
        return strings.SplitN(ctx.RemoteAddr().String(), ":", 2)[0]
    }

    return strings.SplitN(string(xforward), ",", 2)[0]
}

This is the definition of plugin, it's in my plugin project. The plugin project and go app project are different projects.

I found errors:

panic: interface conversion: plugin.Symbol is func() (filter.Filter, error), not func() (filter.Filter, error)

You can find code in this project https://github.com/fagongzi/gateway/tree/go18-plugin-support.

  1. filter.Filter is in pkg/filter package.
  2. load plugin file in proxy/factory.go
  3. plugin go file is in another project.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...