| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 | package controllersimport (	"errors"	"net/http"	"strings"	"github.com/gin-gonic/gin"	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager"	"github.com/langgenius/dify-plugin-daemon/internal/service"	"github.com/langgenius/dify-plugin-daemon/internal/types/app"	"github.com/langgenius/dify-plugin-daemon/internal/types/exception"	"github.com/langgenius/dify-plugin-daemon/pkg/entities/plugin_entities")func GetAsset(c *gin.Context) {	pluginManager := plugin_manager.Manager()	asset, err := pluginManager.GetAsset(c.Param("id"))	if err != nil {		c.JSON(http.StatusInternalServerError, exception.InternalServerError(err).ToResponse())		return	}	c.Data(http.StatusOK, "application/octet-stream", asset)}func UploadPlugin(app *app.Config) gin.HandlerFunc {	return func(c *gin.Context) {		difyPkgFileHeader, err := c.FormFile("dify_pkg")		if err != nil {			c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())			return		}		tenantId := c.Param("tenant_id")		if tenantId == "" {			c.JSON(http.StatusOK, exception.BadRequestError(errors.New("Tenant ID is required")).ToResponse())			return		}		if difyPkgFileHeader.Size > app.MaxPluginPackageSize {			c.JSON(http.StatusOK, exception.BadRequestError(errors.New("File size exceeds the maximum limit")).ToResponse())			return		}		verifySignature := c.PostForm("verify_signature") == "true"		difyPkgFile, err := difyPkgFileHeader.Open()		if err != nil {			c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())			return		}		defer difyPkgFile.Close()		c.JSON(http.StatusOK, service.UploadPluginPkg(app, c, tenantId, difyPkgFile, verifySignature))	}}func UploadBundle(app *app.Config) gin.HandlerFunc {	return func(c *gin.Context) {		difyBundleFileHeader, err := c.FormFile("dify_bundle")		if err != nil {			c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())			return		}		tenantId := c.Param("tenant_id")		if tenantId == "" {			c.JSON(http.StatusOK, exception.BadRequestError(errors.New("Tenant ID is required")).ToResponse())			return		}		if difyBundleFileHeader.Size > app.MaxBundlePackageSize {			c.JSON(http.StatusOK, exception.BadRequestError(errors.New("File size exceeds the maximum limit")).ToResponse())			return		}		verifySignature := c.PostForm("verify_signature") == "true"		difyBundleFile, err := difyBundleFileHeader.Open()		if err != nil {			c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())			return		}		defer difyBundleFile.Close()		c.JSON(http.StatusOK, service.UploadPluginBundle(app, c, tenantId, difyBundleFile, verifySignature))	}}func UpgradePlugin(app *app.Config) gin.HandlerFunc {	return func(c *gin.Context) {		BindRequest(c, func(request struct {			TenantID                       string                                 `uri:"tenant_id" validate:"required"`			OriginalPluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `json:"original_plugin_unique_identifier" validate:"required,plugin_unique_identifier"`			NewPluginUniqueIdentifier      plugin_entities.PluginUniqueIdentifier `json:"new_plugin_unique_identifier" validate:"required,plugin_unique_identifier"`			Source                         string                                 `json:"source" validate:"required"`			Meta                           map[string]any                         `json:"meta" validate:"omitempty"`		}) {			c.JSON(http.StatusOK, service.UpgradePlugin(				app,				request.TenantID,				request.Source,				request.Meta,				request.OriginalPluginUniqueIdentifier,				request.NewPluginUniqueIdentifier,			))		})	}}func InstallPluginFromIdentifiers(app *app.Config) gin.HandlerFunc {	return func(c *gin.Context) {		BindRequest(c, func(request struct {			TenantID                string                                   `uri:"tenant_id" validate:"required"`			PluginUniqueIdentifiers []plugin_entities.PluginUniqueIdentifier `json:"plugin_unique_identifiers" validate:"required,max=64,dive,plugin_unique_identifier"`			Source                  string                                   `json:"source" validate:"required"`			Metas                   []map[string]any                         `json:"metas" validate:"omitempty"`		}) {			if request.Metas == nil {				request.Metas = []map[string]any{}			}			if len(request.Metas) != len(request.PluginUniqueIdentifiers) {				c.JSON(http.StatusOK, exception.BadRequestError(errors.New("the number of metas must be equal to the number of plugin unique identifiers")).ToResponse())				return			}			for i := range request.Metas {				if request.Metas[i] == nil {					request.Metas[i] = map[string]any{}				}			}			c.JSON(http.StatusOK, service.InstallPluginFromIdentifiers(				app, request.TenantID, request.PluginUniqueIdentifiers, request.Source, request.Metas,			))		})	}}func FetchPluginInstallationTasks(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID string `uri:"tenant_id" validate:"required"`		Page     int    `form:"page" validate:"required,min=1"`		PageSize int    `form:"page_size" validate:"required,min=1,max=256"`	}) {		c.JSON(http.StatusOK, service.FetchPluginInstallationTasks(request.TenantID, request.Page, request.PageSize))	})}func FetchPluginInstallationTask(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID string `uri:"tenant_id" validate:"required"`		TaskID   string `uri:"id" validate:"required"`	}) {		c.JSON(http.StatusOK, service.FetchPluginInstallationTask(request.TenantID, request.TaskID))	})}func DeletePluginInstallationTask(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID string `uri:"tenant_id" validate:"required"`		TaskID   string `uri:"id" validate:"required"`	}) {		c.JSON(http.StatusOK, service.DeletePluginInstallationTask(request.TenantID, request.TaskID))	})}func DeleteAllPluginInstallationTasks(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID string `uri:"tenant_id" validate:"required"`	}) {		c.JSON(http.StatusOK, service.DeleteAllPluginInstallationTasks(request.TenantID))	})}func DeletePluginInstallationItemFromTask(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID   string `uri:"tenant_id" validate:"required"`		TaskID     string `uri:"id" validate:"required"`		Identifier string `uri:"identifier" validate:"required"`	}) {		identifierString := strings.TrimLeft(request.Identifier, "/")		identifier, err := plugin_entities.NewPluginUniqueIdentifier(identifierString)		if err != nil {			c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())			return		}		c.JSON(http.StatusOK, service.DeletePluginInstallationItemFromTask(request.TenantID, request.TaskID, identifier))	})}func FetchPluginManifest(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID               string                                 `uri:"tenant_id" validate:"required"`		PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `form:"plugin_unique_identifier" validate:"required,plugin_unique_identifier"`	}) {		c.JSON(http.StatusOK, service.FetchPluginManifest(request.PluginUniqueIdentifier))	})}func UninstallPlugin(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID             string `uri:"tenant_id" validate:"required"`		PluginInstallationID string `json:"plugin_installation_id" validate:"required"`	}) {		c.JSON(http.StatusOK, service.UninstallPlugin(request.TenantID, request.PluginInstallationID))	})}func FetchPluginFromIdentifier(c *gin.Context) {	BindRequest(c, func(request struct {		PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `form:"plugin_unique_identifier" validate:"required,plugin_unique_identifier"`	}) {		c.JSON(http.StatusOK, service.FetchPluginFromIdentifier(request.PluginUniqueIdentifier))	})}func ListPlugins(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID string `uri:"tenant_id" validate:"required"`		Page     int    `form:"page" validate:"required,min=1"`		PageSize int    `form:"page_size" validate:"required,min=1,max=256"`	}) {		c.JSON(http.StatusOK, service.ListPlugins(request.TenantID, request.Page, request.PageSize))	})}func BatchFetchPluginInstallationByIDs(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID  string   `uri:"tenant_id" validate:"required"`		PluginIDs []string `json:"plugin_ids" validate:"required,max=256"`	}) {		c.JSON(http.StatusOK, service.BatchFetchPluginInstallationByIDs(request.TenantID, request.PluginIDs))	})}func FetchMissingPluginInstallations(c *gin.Context) {	BindRequest(c, func(request struct {		TenantID                string                                   `uri:"tenant_id" validate:"required"`		PluginUniqueIdentifiers []plugin_entities.PluginUniqueIdentifier `json:"plugin_unique_identifiers" validate:"required,max=256,dive,plugin_unique_identifier"`	}) {		c.JSON(http.StatusOK, service.FetchMissingPluginInstallations(request.TenantID, request.PluginUniqueIdentifiers))	})}
 |