Browse Source

feat:插件模式尝鲜

main
songzhibin97 3 years ago
parent
commit
461e01cb05
  1. 61
      server/main.go
  2. 16
      server/router/example/plugin.go
  3. 41
      server/utils/plugin/plugin.go
  4. 69
      server/utils/plugin/plugin_uinx.go

61
server/main.go

@ -1,33 +1,38 @@
package main package main
import (
"gin-vue-admin/core"
"gin-vue-admin/global"
"gin-vue-admin/initialize"
)
//import (
// "gin-vue-admin/core"
// "gin-vue-admin/global"
// "gin-vue-admin/initialize"
//)
//
////go:generate go env -w GO111MODULE=on
////go:generate go env -w GOPROXY=https://goproxy.cn,direct
////go:generate go mod tidy
////go:generate go mod download
//
//// @title Swagger Example API
//// @version 0.0.1
//// @description This is a sample Server pets
//// @securityDefinitions.apikey ApiKeyAuth
//// @in header
//// @name x-token
//// @BasePath /
//func main() {
// global.GVA_VP = core.Viper() // 初始化Viper
// global.GVA_LOG = core.Zap() // 初始化zap日志库
// global.GVA_DB = initialize.Gorm() // gorm连接数据库
// initialize.Timer()
// if global.GVA_DB != nil {
// initialize.MysqlTables(global.GVA_DB) // 初始化表
// // 程序结束前关闭数据库链接
// db, _ := global.GVA_DB.DB()
// defer db.Close()
// }
// core.RunWindowsServer()
//}
//go:generate go env -w GO111MODULE=on
//go:generate go env -w GOPROXY=https://goproxy.cn,direct
//go:generate go mod tidy
//go:generate go mod download
var Plugin plugin
// @title Swagger Example API
// @version 0.0.1
// @description This is a sample Server pets
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name x-token
// @BasePath /
func main() {
global.GVA_VP = core.Viper() // 初始化Viper
global.GVA_LOG = core.Zap() // 初始化zap日志库
global.GVA_DB = initialize.Gorm() // gorm连接数据库
initialize.Timer()
if global.GVA_DB != nil {
initialize.MysqlTables(global.GVA_DB) // 初始化表
// 程序结束前关闭数据库链接
db, _ := global.GVA_DB.DB()
defer db.Close()
}
core.RunWindowsServer()
type plugin struct {
} }

16
server/router/example/plugin.go

@ -0,0 +1,16 @@
package example
import "github.com/gin-gonic/gin"
type Plugin struct {
}
func (*Plugin) Register(group *gin.RouterGroup) {
group.GET("hello", func(context *gin.Context) {
context.JSON(200, "hello world")
})
}
func (*Plugin) RouterPath() string {
return "group"
}

41
server/utils/plugin/plugin.go

@ -0,0 +1,41 @@
package plugin
import (
"plugin"
"sync"
"github.com/gin-gonic/gin"
)
const (
OnlyFuncName = "Plugin"
)
var ManagementPlugin = managementPlugin{mp: make(map[string]*plugin.Plugin)}
type managementPlugin struct {
mp map[string]*plugin.Plugin
sync.Mutex
}
func (m *managementPlugin) SetPlugin(key string, p *plugin.Plugin) {
m.Lock()
defer m.Unlock()
m.mp[key] = p
}
func (m *managementPlugin) GetPlugin(key string) (p *plugin.Plugin, ok bool) {
m.Lock()
defer m.Unlock()
p, ok = m.mp[key]
return
}
// Plugin 插件模式接口化
type Plugin interface {
// Register 注册路由
Register(group *gin.RouterGroup)
// RouterPath 用户返回注册路由
RouterPath() string
}

69
server/utils/plugin/plugin_uinx.go

@ -0,0 +1,69 @@
//+build !windows
package plugin
import (
"errors"
"fmt"
"io/fs"
"io/ioutil"
"os"
"path/filepath"
"plugin"
)
// LoadPlugin 加载插件 传入path
func LoadPlugin(path string) error {
path, err := filepath.Abs(path)
if err != nil {
return err
}
fileInfo, err := os.Stat(path)
if err != nil {
return err
}
if fileInfo.IsDir() {
fileSlice, err := ioutil.ReadDir(path)
if err != nil {
return err
}
for _, ff := range fileSlice {
if !ff.IsDir() && filepath.Ext(ff.Name()) == ".so" {
if err = loadPlugin(path, ff); err != nil {
return err
}
} else if ff.IsDir() {
_ = LoadPlugin(filepath.Join(path, ff.Name()))
}
}
return nil
} else {
return loadPlugin(path, fileInfo)
}
}
func loadPlugin(path string, f fs.FileInfo) error {
if filepath.Ext(f.Name()) == ".so" {
fPath := filepath.Join(path, f.Name())
// 加载插件
p, err := plugin.Open(fPath)
if err != nil {
fmt.Println("loadPlugin err ", err)
return err
}
// 判断是否满足协议
// 要满足 OnlyFuncName && 实现 Plugin 接口
if v, err := p.Lookup(OnlyFuncName); err != nil {
fmt.Println("loadPlugin err ", err)
return err
} else if _, ok := v.(Plugin); !ok {
fmt.Println("loadPlugin err ", fmt.Sprintf("path:%s 没有实现 %s 接口", filepath.Base(fPath), OnlyFuncName))
return errors.New("没有实现指定接口")
} else {
}
fmt.Println("loadPlugin add ", filepath.Base(fPath))
ManagementPlugin.SetPlugin(filepath.Base(fPath), p)
}
return nil
}
Loading…
Cancel
Save