go 1.8插件使用自定义界面
我想使用基于go插件的自定义界面,但我发现它不受支持 过滤器的定义 此软件包位于我的go应用程序项目中 加载插件文件 这是我的go应用程序项目中加载插件的代码go 1.8插件使用自定义界面,go,plugins,Go,Plugins,我想使用基于go插件的自定义界面,但我发现它不受支持 过滤器的定义 此软件包位于我的go应用程序项目中 加载插件文件 这是我的go应用程序项目中加载插件的代码 package main import ( "C" "strings" "time" "github.com/CodisLabs/codis/pkg/utils/log" "github.com/fagongzi/gateway/pkg/filter" "github.com/valya
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]
}
这是插件的定义,在我的插件项目中。插件项目和go app项目是不同的项目
我发现了错误:
您可以在此项目中找到代码https://github.com/fagongzi/gateway/tree/go18-plugin-support.
filter.filter
在pkg/filter包中在proxy/factory.go中加载插件文件
插件go文件
位于另一个项目中自定义接口工作正常 但有一点很重要:您只能从插件外部定义的插件中查找值(您不能引用插件中定义的类型)。这也适用于“复合类型”的每个组件,例如,您只能类型断言其参数和结果类型也在插件外部定义的函数类型 1.使用插件外部的通用包 一种解决方案是在插件之外的包中定义接口,插件和应用程序都可以导入并引用它 在包
过滤器中定义它:
package filter
type Filter interface {
Name() string
Age() int
}
package main
import (
"fmt"
"filter"
)
type plgFilter struct{}
func (plgFilter) Name() string { return "Bob" }
func (plgFilter) Age() int { return 23 }
func GetFilter() (f filter.Filter, err error) {
f = plgFilter{}
fmt.Printf("[plugin GetFilter] Returning filter: %T %v\n", f, f)
return
}
package main
import (
"fmt"
"filter"
"plugin"
)
func main() {
p, err := plugin.Open("pg/pg.so")
if err != nil {
panic(err)
}
GetFilter, err := p.Lookup("GetFilter")
if err != nil {
panic(err)
}
filter, err := GetFilter.(func() (filter.Filter, error))()
fmt.Printf("GetFilter result: %T %v %v\n", filter, filter, err)
fmt.Println("\tName:", filter.Name())
fmt.Println("\tAge:", filter.Age())
}
插件位于packagepq
中,并导入packagefilter
:
package filter
type Filter interface {
Name() string
Age() int
}
package main
import (
"fmt"
"filter"
)
type plgFilter struct{}
func (plgFilter) Name() string { return "Bob" }
func (plgFilter) Age() int { return 23 }
func GetFilter() (f filter.Filter, err error) {
f = plgFilter{}
fmt.Printf("[plugin GetFilter] Returning filter: %T %v\n", f, f)
return
}
package main
import (
"fmt"
"filter"
"plugin"
)
func main() {
p, err := plugin.Open("pg/pg.so")
if err != nil {
panic(err)
}
GetFilter, err := p.Lookup("GetFilter")
if err != nil {
panic(err)
}
filter, err := GetFilter.(func() (filter.Filter, error))()
fmt.Printf("GetFilter result: %T %v %v\n", filter, filter, err)
fmt.Println("\tName:", filter.Name())
fmt.Println("\tAge:", filter.Age())
}
主应用程序也会导入(相同)包过滤器
,加载插件,查找GetFilter()
,调用它,并使用返回的过滤器
:
package filter
type Filter interface {
Name() string
Age() int
}
package main
import (
"fmt"
"filter"
)
type plgFilter struct{}
func (plgFilter) Name() string { return "Bob" }
func (plgFilter) Age() int { return 23 }
func GetFilter() (f filter.Filter, err error) {
f = plgFilter{}
fmt.Printf("[plugin GetFilter] Returning filter: %T %v\n", f, f)
return
}
package main
import (
"fmt"
"filter"
"plugin"
)
func main() {
p, err := plugin.Open("pg/pg.so")
if err != nil {
panic(err)
}
GetFilter, err := p.Lookup("GetFilter")
if err != nil {
panic(err)
}
filter, err := GetFilter.(func() (filter.Filter, error))()
fmt.Printf("GetFilter result: %T %v %v\n", filter, filter, err)
fmt.Println("\tName:", filter.Name())
fmt.Println("\tAge:", filter.Age())
}
输出:
[plugin GetFilter] Returning filter: main.plgFilter {}
GetFilter result: main.plgFilter {} <nil>
Name: Bob
Age: 23
[plugin GetFilterIface] Returning filter: main.plgFilter {}
GetFilterIface result: main.plgFilter {} <nil>
Name: Bob
Age: 23
和主应用程序:
package main
import (
"fmt"
"plugin"
)
func main() {
p, err := plugin.Open("pg/pg.so")
if err != nil {
panic(err)
}
GetFilterIface, err := p.Lookup("GetFilterIface")
if err != nil {
panic(err)
}
filterIface, err := GetFilterIface.(func() (interface{}, error))()
fmt.Printf("GetFilterIface result: %T %v %v\n", filterIface, filterIface, err)
myfilter := filterIface.(MyFilter)
fmt.Println("\tName:", myfilter.Name())
fmt.Println("\tAge:", myfilter.Age())
}
type MyFilter interface {
Name() string
Age() int
}
输出:
[plugin GetFilter] Returning filter: main.plgFilter {}
GetFilter result: main.plgFilter {} <nil>
Name: Bob
Age: 23
[plugin GetFilterIface] Returning filter: main.plgFilter {}
GetFilterIface result: main.plgFilter {} <nil>
Name: Bob
Age: 23
[plugin getFilterFace]返回过滤器:main.plgFilter{}
GetFilterInterface结果:main.plgFilter{}
姓名:鲍勃
年龄:23
另请参见相关问题:您使用的是哪种系统?目前Linux上只支持插件。非常感谢您的回答,但这并不能解决问题,因为我描述了不清楚的原因。现在我正在编辑这个问题,事实上我的解决方案与您的解决方案1类似。@ZhangXu我没有看到任何您声称存在的过滤器包:。你把导入/包路径搞混了。嗨,对不起,它在分支中。我还向golang()打开了一个问题,这可能是一个供应商软件包问题。我将在释放时验证它。插件代码定义在package main中,插件加载在main中。如果插件是从main以外的另一个包加载的,那么这仍然有效吗?换句话说,插件包名是否需要与加载的包名匹配(在您给出的示例中为main)?@chmike插件必须具有packagemain
,并且可以从任何地方加载。但是一个可运行的应用程序还必须有一个包main
,包main
的main()
函数是该应用程序的入口点。插件的main
和应用的main
是两个不同的包。