Ver Fonte

:art: Kernel API supports load plugins https://github.com/siyuan-note/siyuan/issues/8044

Liang Ding há 2 anos atrás
pai
commit
75c9dcf407
4 ficheiros alterados com 163 adições e 1 exclusões
  1. 1 1
      app/src/plugin/loader.ts
  2. 33 0
      kernel/api/plugin.go
  3. 2 0
      kernel/api/router.go
  4. 127 0
      kernel/model/plugin.go

+ 1 - 1
app/src/plugin/loader.ts

@@ -17,7 +17,7 @@ const runCode = (code: string, sourceURL: string) => {
 }
 }
 
 
 export const loadPlugins = (app: App) => {
 export const loadPlugins = (app: App) => {
-    fetchPost("/api/plugin/loadPlugins", {}, response => {
+    fetchPost("/api/petal/loadPetals", {}, response => {
         let css = "";
         let css = "";
         response.data.forEach((item: { id: string, name: string, jsCode: string, cssCode: string, lang: IObject }) => {
         response.data.forEach((item: { id: string, name: string, jsCode: string, cssCode: string, lang: IObject }) => {
             const moduleObj = {}
             const moduleObj = {}

+ 33 - 0
kernel/api/plugin.go

@@ -0,0 +1,33 @@
+// SiYuan - Build Your Eternal Digital Garden
+// Copyright (c) 2020-present, b3log.org
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+package api
+
+import (
+	"net/http"
+
+	"github.com/88250/gulu"
+	"github.com/gin-gonic/gin"
+	"github.com/siyuan-note/siyuan/kernel/model"
+)
+
+func loadPetals(c *gin.Context) {
+	ret := gulu.Ret.NewResult()
+	defer c.JSON(http.StatusOK, ret)
+
+	petals := model.LoadPetals()
+	ret.Data = petals
+}

+ 2 - 0
kernel/api/router.go

@@ -343,4 +343,6 @@ func ServeAPI(ginServer *gin.Engine) {
 
 
 	ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, model.CheckReadonly, chatGPT)
 	ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, model.CheckReadonly, chatGPT)
 	ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckReadonly, chatGPTWithAction)
 	ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, model.CheckReadonly, chatGPTWithAction)
+
+	ginServer.Handle("POST", "/api/petal/loadPetals", model.CheckAuth, model.CheckReadonly, loadPetals)
 }
 }

+ 127 - 0
kernel/model/plugin.go

@@ -0,0 +1,127 @@
+// SiYuan - Build Your Eternal Digital Garden
+// Copyright (c) 2020-present, b3log.org
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+package model
+
+import (
+	"crypto/sha1"
+	"fmt"
+	"path/filepath"
+
+	"github.com/88250/gulu"
+	"github.com/siyuan-note/filelock"
+	"github.com/siyuan-note/logging"
+	"github.com/siyuan-note/siyuan/kernel/bazaar"
+	"github.com/siyuan-note/siyuan/kernel/util"
+)
+
+// Petal represents a plugin's management status.
+type Petal struct {
+	ID      string `json:"id"`      // Plugin ID
+	Name    string `json:"name"`    // Plugin name
+	Enabled bool   `json:"enabled"` // Whether enabled
+
+	JS   string                 `json:"js"`   // JS code
+	CSS  string                 `json:"css"`  // CSS code
+	I18n map[string]interface{} `json:"i18n"` // i18n text
+}
+
+func LoadPetals() (ret []*Petal) {
+	petalDir := filepath.Join(util.DataDir, "storage", "petal")
+	confPath := filepath.Join(petalDir, "petals.json")
+
+	ret = []*Petal{}
+	if !gulu.File.IsExist(confPath) {
+		data, err := gulu.JSON.MarshalIndentJSON(ret, "", "\t")
+		if nil != err {
+			logging.LogErrorf("marshal petals failed: %s", err)
+			return
+		}
+		if err = filelock.WriteFile(confPath, data); nil != err {
+			logging.LogErrorf("write petals [%s] failed: %s", confPath, err)
+			return
+		}
+		return
+	}
+
+	data, err := filelock.ReadFile(confPath)
+	if nil != err {
+		logging.LogErrorf("read petal file [%s] failed: %s", confPath, err)
+		return
+	}
+
+	if err = gulu.JSON.UnmarshalJSON(data, &ret); nil != err {
+		logging.LogErrorf("unmarshal petals failed: %s", err)
+		return
+	}
+
+	plugins := bazaar.InstalledPlugins()
+	for _, plugin := range plugins {
+		id := hash(plugin.URL)
+		petal := getPetalByID(id, ret)
+		if nil == petal {
+			continue
+		}
+
+		pluginDir := filepath.Join(util.DataDir, "plugins", plugin.Name)
+		data, err := filelock.ReadFile(filepath.Join(pluginDir, "index.js"))
+		if nil != err {
+			logging.LogErrorf("read plugin [%s] js failed: %s", plugin.Name, err)
+			continue
+		}
+		petal.JS = string(data)
+
+		cssPath := filepath.Join(pluginDir, "index.css")
+		if gulu.File.IsExist(cssPath) {
+			data, err := filelock.ReadFile(cssPath)
+			if nil != err {
+				logging.LogErrorf("read plugin [%s] css failed: %s", plugin.Name, err)
+			} else {
+				petal.CSS = string(data)
+			}
+		}
+
+		i18nPath := filepath.Join(pluginDir, "i18n", Conf.Lang)
+		if gulu.File.IsExist(i18nPath) {
+			data, err := filelock.ReadFile(i18nPath)
+			if nil != err {
+				logging.LogErrorf("read plugin [%s] i18n failed: %s", plugin.Name, err)
+			} else {
+				petal.I18n = map[string]interface{}{}
+				if err = gulu.JSON.UnmarshalJSON(data, &petal.I18n); nil != err {
+					logging.LogErrorf("unmarshal plugin [%s] i18n failed: %s", plugin.Name, err)
+				}
+			}
+		}
+
+		ret = append(ret, petal)
+	}
+	return
+}
+
+func getPetalByID(id string, petals []*Petal) (ret *Petal) {
+	for _, p := range petals {
+		if id == p.ID {
+			ret = p
+			break
+		}
+	}
+	return
+}
+
+func hash(str string) string {
+	return fmt.Sprintf("%x", sha1.Sum([]byte(str)))
+}