Yeuoly 10 月之前
父節點
當前提交
b52cbe0815

+ 6 - 0
internal/server/controllers/base.go

@@ -46,6 +46,12 @@ func BindRequestWithPluginUniqueIdentifier[T any](r *gin.Context, success func(
 			return
 			return
 		}
 		}
 
 
+		if err := plugin_entities.PluginUniqueIdentifier(plugin_unique_identifier).Validate(); err != nil {
+			resp := entities.NewErrorResponse(-400, err.Error())
+			r.JSON(400, resp)
+			return
+		}
+
 		success(req, plugin_entities.PluginUniqueIdentifier(plugin_unique_identifier))
 		success(req, plugin_entities.PluginUniqueIdentifier(plugin_unique_identifier))
 	})
 	})
 }
 }

+ 1 - 1
internal/server/controllers/endpoint.go

@@ -9,7 +9,7 @@ import (
 func SetupEndpoint(ctx *gin.Context) {
 func SetupEndpoint(ctx *gin.Context) {
 	BindRequest(ctx, func(
 	BindRequest(ctx, func(
 		request struct {
 		request struct {
-			PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `json:"plugin_unique_identifier" binding:"required"`
+			PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `json:"plugin_unique_identifier" binding:"required,plugin_unique_identifier"`
 			TenantID               string                                 `json:"tenant_id" binding:"required"`
 			TenantID               string                                 `json:"tenant_id" binding:"required"`
 			UserID                 string                                 `json:"user_id" binding:"required"`
 			UserID                 string                                 `json:"user_id" binding:"required"`
 			Settings               map[string]any                         `json:"settings" binding:"omitempty"`
 			Settings               map[string]any                         `json:"settings" binding:"omitempty"`

+ 5 - 4
internal/server/controllers/plugins.go

@@ -55,10 +55,11 @@ func InstallPluginFromPkg(app *app.Config) gin.HandlerFunc {
 
 
 func InstallPluginFromIdentifier(app *app.Config) gin.HandlerFunc {
 func InstallPluginFromIdentifier(app *app.Config) gin.HandlerFunc {
 	return func(c *gin.Context) {
 	return func(c *gin.Context) {
-		BindRequestWithPluginUniqueIdentifier(c, func(request struct {
-			TenantID string `json:"tenant_id" binding:"required"`
-		}, identifier plugin_entities.PluginUniqueIdentifier) {
-			// TODO
+		BindRequest(c, func(request struct {
+			TenantID               string                                 `json:"tenant_id" binding:"required"`
+			PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `json:"plugin_unique_identifier" binding:"required,plugin_unique_identifier"`
+		}) {
+			service.InstallPluginFromIdentifier(c, request.TenantID, request.PluginUniqueIdentifier)
 		})
 		})
 	}
 	}
 }
 }

+ 1 - 1
internal/server/http_server.go

@@ -102,7 +102,7 @@ func (app *App) pluginGroup(group *gin.RouterGroup, config *app.Config) {
 
 
 	group.GET("/asset/:id", controllers.GetAsset)
 	group.GET("/asset/:id", controllers.GetAsset)
 	group.POST("/install/pkg", controllers.InstallPluginFromPkg(config))
 	group.POST("/install/pkg", controllers.InstallPluginFromPkg(config))
-	group.POST("/install/id", controllers.InstallPluginFromIdentifier(config))
+	group.POST("/install/identifier", controllers.InstallPluginFromIdentifier(config))
 	group.POST("/uninstall", controllers.UninstallPlugin)
 	group.POST("/uninstall", controllers.UninstallPlugin)
 	group.GET("/list", controllers.ListPlugins)
 	group.GET("/list", controllers.ListPlugins)
 }
 }

+ 33 - 0
internal/service/install.go

@@ -7,7 +7,11 @@ import (
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_packager/decoder"
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_packager/decoder"
+	"github.com/langgenius/dify-plugin-daemon/internal/db"
 	"github.com/langgenius/dify-plugin-daemon/internal/types/entities"
 	"github.com/langgenius/dify-plugin-daemon/internal/types/entities"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/models"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/models/curd"
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/stream"
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/stream"
 )
 )
 
 
@@ -34,3 +38,32 @@ func InstallPluginFromPkg(c *gin.Context, tenant_id string, dify_pkg_file multip
 		3600,
 		3600,
 	)
 	)
 }
 }
+
+func InstallPluginFromIdentifier(
+	c *gin.Context,
+	tenant_id string,
+	plugin_unique_identifier plugin_entities.PluginUniqueIdentifier,
+) *entities.Response {
+	// check if identifier exists
+	plugin, err := db.GetOne[models.Plugin](
+		db.Equal("plugin_unique_identifier", plugin_unique_identifier.String()),
+	)
+	if err == db.ErrDatabaseNotFound {
+		return entities.NewErrorResponse(-404, "Plugin not found")
+	}
+	if err != nil {
+		return entities.NewErrorResponse(-500, err.Error())
+	}
+
+	declaration, err := plugin.GetDeclaration()
+	if err != nil {
+		return entities.NewErrorResponse(-500, err.Error())
+	}
+
+	// install to this workspace
+	if _, _, err := curd.CreatePlugin(tenant_id, plugin_unique_identifier, plugin.InstallType, declaration); err != nil {
+		return entities.NewErrorResponse(-500, err.Error())
+	}
+
+	return entities.NewSuccessResponse(plugin)
+}

+ 29 - 1
internal/types/entities/plugin_entities/identity.go

@@ -1,9 +1,25 @@
 package plugin_entities
 package plugin_entities
 
 
-import "strings"
+import (
+	"regexp"
+	"strings"
+
+	"github.com/go-playground/validator/v10"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/validators"
+)
 
 
 type PluginUniqueIdentifier string
 type PluginUniqueIdentifier string
 
 
+var (
+	// pluginUniqueIdentifierRegexp is a regular expression to validate the plugin unique identifier.
+	// It must be in the format of "plugin_id:version@checksum".
+	// all lowercase. the length of plugin_id must be less than 128, and for version part, it must be ^\d{1,4}(\.\d{1,4}){1,3}(-\w{1,16})?$
+	// for checksum, it must be a 32-character hexadecimal string.
+	pluginUniqueIdentifierRegexp = regexp.MustCompile(
+		`^[a-z0-9_-]{1,128}:[0-9]{1,4}(\.[0-9]{1,4}){1,3}(-\w{1,16})?@[a-f0-9]{32}$`,
+	)
+)
+
 func (p PluginUniqueIdentifier) PluginID() string {
 func (p PluginUniqueIdentifier) PluginID() string {
 	// try find @
 	// try find @
 	split := strings.Split(p.String(), "@")
 	split := strings.Split(p.String(), "@")
@@ -16,3 +32,15 @@ func (p PluginUniqueIdentifier) PluginID() string {
 func (p PluginUniqueIdentifier) String() string {
 func (p PluginUniqueIdentifier) String() string {
 	return string(p)
 	return string(p)
 }
 }
+
+func (p PluginUniqueIdentifier) Validate() error {
+	return validators.GlobalEntitiesValidator.Var(p, "plugin_unique_identifier")
+}
+
+func isValidPluginUniqueIdentifier(fl validator.FieldLevel) bool {
+	return pluginUniqueIdentifierRegexp.MatchString(fl.Field().String())
+}
+
+func init() {
+	validators.GlobalEntitiesValidator.RegisterValidation("plugin_unique_identifier", isValidPluginUniqueIdentifier)
+}