Skip to content

Commit 461e01c

Browse files
committed
feat:插件模式尝鲜
1 parent 964dd1f commit 461e01c

File tree

4 files changed

+159
-28
lines changed

4 files changed

+159
-28
lines changed

server/main.go

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
11
package main
22

3-
import (
4-
"gin-vue-admin/core"
5-
"gin-vue-admin/global"
6-
"gin-vue-admin/initialize"
7-
)
3+
//import (
4+
// "gin-vue-admin/core"
5+
// "gin-vue-admin/global"
6+
// "gin-vue-admin/initialize"
7+
//)
8+
//
9+
////go:generate go env -w GO111MODULE=on
10+
////go:generate go env -w GOPROXY=https://goproxy.cn,direct
11+
////go:generate go mod tidy
12+
////go:generate go mod download
13+
//
14+
//// @title Swagger Example API
15+
//// @version 0.0.1
16+
//// @description This is a sample Server pets
17+
//// @securityDefinitions.apikey ApiKeyAuth
18+
//// @in header
19+
//// @name x-token
20+
//// @BasePath /
21+
//func main() {
22+
// global.GVA_VP = core.Viper() // 初始化Viper
23+
// global.GVA_LOG = core.Zap() // 初始化zap日志库
24+
// global.GVA_DB = initialize.Gorm() // gorm连接数据库
25+
// initialize.Timer()
26+
// if global.GVA_DB != nil {
27+
// initialize.MysqlTables(global.GVA_DB) // 初始化表
28+
// // 程序结束前关闭数据库链接
29+
// db, _ := global.GVA_DB.DB()
30+
// defer db.Close()
31+
// }
32+
// core.RunWindowsServer()
33+
//}
834

9-
//go:generate go env -w GO111MODULE=on
10-
//go:generate go env -w GOPROXY=https://goproxy.cn,direct
11-
//go:generate go mod tidy
12-
//go:generate go mod download
35+
var Plugin plugin
1336

14-
// @title Swagger Example API
15-
// @version 0.0.1
16-
// @description This is a sample Server pets
17-
// @securityDefinitions.apikey ApiKeyAuth
18-
// @in header
19-
// @name x-token
20-
// @BasePath /
21-
func main() {
22-
global.GVA_VP = core.Viper() // 初始化Viper
23-
global.GVA_LOG = core.Zap() // 初始化zap日志库
24-
global.GVA_DB = initialize.Gorm() // gorm连接数据库
25-
initialize.Timer()
26-
if global.GVA_DB != nil {
27-
initialize.MysqlTables(global.GVA_DB) // 初始化表
28-
// 程序结束前关闭数据库链接
29-
db, _ := global.GVA_DB.DB()
30-
defer db.Close()
31-
}
32-
core.RunWindowsServer()
37+
type plugin struct {
3338
}

server/router/example/plugin.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package example
2+
3+
import "github.com/gin-gonic/gin"
4+
5+
type Plugin struct {
6+
}
7+
8+
func (*Plugin) Register(group *gin.RouterGroup) {
9+
group.GET("hello", func(context *gin.Context) {
10+
context.JSON(200, "hello world")
11+
})
12+
}
13+
14+
func (*Plugin) RouterPath() string {
15+
return "group"
16+
}

server/utils/plugin/plugin.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package plugin
2+
3+
import (
4+
"plugin"
5+
"sync"
6+
7+
"github.com/gin-gonic/gin"
8+
)
9+
10+
const (
11+
OnlyFuncName = "Plugin"
12+
)
13+
14+
var ManagementPlugin = managementPlugin{mp: make(map[string]*plugin.Plugin)}
15+
16+
type managementPlugin struct {
17+
mp map[string]*plugin.Plugin
18+
sync.Mutex
19+
}
20+
21+
func (m *managementPlugin) SetPlugin(key string, p *plugin.Plugin) {
22+
m.Lock()
23+
defer m.Unlock()
24+
m.mp[key] = p
25+
}
26+
27+
func (m *managementPlugin) GetPlugin(key string) (p *plugin.Plugin, ok bool) {
28+
m.Lock()
29+
defer m.Unlock()
30+
p, ok = m.mp[key]
31+
return
32+
}
33+
34+
// Plugin 插件模式接口化
35+
type Plugin interface {
36+
// Register 注册路由
37+
Register(group *gin.RouterGroup)
38+
39+
// RouterPath 用户返回注册路由
40+
RouterPath() string
41+
}

server/utils/plugin/plugin_uinx.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//+build !windows
2+
3+
package plugin
4+
5+
import (
6+
"errors"
7+
"fmt"
8+
"io/fs"
9+
"io/ioutil"
10+
"os"
11+
"path/filepath"
12+
"plugin"
13+
)
14+
15+
// LoadPlugin 加载插件 传入path
16+
func LoadPlugin(path string) error {
17+
path, err := filepath.Abs(path)
18+
if err != nil {
19+
return err
20+
}
21+
fileInfo, err := os.Stat(path)
22+
if err != nil {
23+
return err
24+
}
25+
if fileInfo.IsDir() {
26+
fileSlice, err := ioutil.ReadDir(path)
27+
if err != nil {
28+
return err
29+
}
30+
for _, ff := range fileSlice {
31+
if !ff.IsDir() && filepath.Ext(ff.Name()) == ".so" {
32+
if err = loadPlugin(path, ff); err != nil {
33+
return err
34+
}
35+
} else if ff.IsDir() {
36+
_ = LoadPlugin(filepath.Join(path, ff.Name()))
37+
}
38+
}
39+
return nil
40+
} else {
41+
return loadPlugin(path, fileInfo)
42+
}
43+
}
44+
45+
func loadPlugin(path string, f fs.FileInfo) error {
46+
if filepath.Ext(f.Name()) == ".so" {
47+
fPath := filepath.Join(path, f.Name())
48+
// 加载插件
49+
p, err := plugin.Open(fPath)
50+
if err != nil {
51+
fmt.Println("loadPlugin err ", err)
52+
return err
53+
}
54+
// 判断是否满足协议
55+
// 要满足 OnlyFuncName && 实现 Plugin 接口
56+
if v, err := p.Lookup(OnlyFuncName); err != nil {
57+
fmt.Println("loadPlugin err ", err)
58+
return err
59+
} else if _, ok := v.(Plugin); !ok {
60+
fmt.Println("loadPlugin err ", fmt.Sprintf("path:%s 没有实现 %s 接口", filepath.Base(fPath), OnlyFuncName))
61+
return errors.New("没有实现指定接口")
62+
} else {
63+
64+
}
65+
fmt.Println("loadPlugin add ", filepath.Base(fPath))
66+
ManagementPlugin.SetPlugin(filepath.Base(fPath), p)
67+
}
68+
return nil
69+
}

0 commit comments

Comments
 (0)