Преглед на файлове

feat:插件模式尝鲜

songzhibin97 преди 3 години
родител
ревизия
461e01cb05
променени са 4 файла, в които са добавени 159 реда и са изтрити 28 реда
  1. 33 28
      server/main.go
  2. 16 0
      server/router/example/plugin.go
  3. 41 0
      server/utils/plugin/plugin.go
  4. 69 0
      server/utils/plugin/plugin_uinx.go

+ 33 - 28
server/main.go

@@ -1,33 +1,38 @@
 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 - 0
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 - 0
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 - 0
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
+}