这几天发现了一个特别有趣的东西,只要照着规定好的插件模板写,不懂go语法的人也可以交互go代码,大大提高了go代码的可扩展性,易用性。
- 范例代码
main.go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"log"
)
func main(){
//加载文件夹下所有插件
plugins:=loadPlugins("./jsfilters")
r:=gin.New()
r.Use(func(context *gin.Context) {
exchange:=NewExchange(context.Request)
//遍历调用所有插件主函数
for _,p:=range plugins{
p.Filter(exchange)
}
context.Next()
})
r.Handle("GET","/", func(context *gin.Context) {
//打印header头
fmt.Println(context.Request.Header.Get("Name"))
fmt.Println(context.Request.Header.Get("Age"))
context.JSON(200,gin.H{"result":"ok"})
})
err := r.Run(":8080")
if err!=nil{
log.Panic(err)
}
}
helper.go
(交互逻辑代码)
package main
import (
"github.com/robertkrimen/otto"
"io/ioutil"
"log"
"net/http"
"path"
)
func readFile(file string) string {
b,err:=ioutil.ReadFile(file)
if err!=nil{
return ""
}
return string(b)
}
type This struct {
}
type Exchange struct {
Request *http.Request
}
func NewExchange(request *http.Request) *Exchange {
return &Exchange{Request:request}
}
type FilterPlugin struct {
Name string
Main otto.Value
}
//调用插件对象里的mian方法
func(self *FilterPlugin) Filter(exchange *Exchange){
this,_:=otto.ToValue(nil)
_,err:=self.Main.Call(this,exchange) //调用 闭包 ,传递上下文参数
if err!=nil{
log.Println(err)
}
}
func loadPlugin(js *otto.Otto) *FilterPlugin {
//获取插件名称
filter_name,err:=js.Call("name",nil)
if err!=nil{
log.Println(err)
return nil
}
//获取插件主函数
filter_main,err:=js.Call("main",nil)
if err!=nil || !filter_main.IsFunction(){
log.Println(err)
return nil
}
//返回插件对象
return &FilterPlugin{Name:filter_name.String(),Main:filter_main}
}
//加载文件夹下所有插件
func loadPlugins(dirname string) []*FilterPlugin {
//插件对象切片
ret:=make([]*FilterPlugin,0)
//读取文件夹
fileInfos, _ := ioutil.ReadDir(dirname)
//遍历文件
for _, file := range fileInfos {
if !file.IsDir() && path.Ext(file.Name())==".js"{
//如果是JS文件
js:=otto.New()
//运行
_,err:=js.Run(readFile(dirname+"/"+file.Name()))
if err!=nil{
log.Println(err)
continue
}
if p:=loadPlugin(js);p!=nil{
//获取到插件对象,则追加到数组
ret=append(ret,p)
}
}
}
return ret
}
JS模板1
function main() {
return function (exchange) {
//设置header头
exchange.Request.Header.Set("Name","shenyi")
}
}
//插件名
function name() {
return 'Test'
}
JS模板2
function main() {
return function (exchange) {
//设置header头
exchange.Request.Header.Set("Age",19)
}
}
//插件名
function name() {
return 'Abc'
}
- 测试,运行
main.go
,访问http://localhost:8080