plugins.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package controllers
  2. import (
  3. "errors"
  4. "net/http"
  5. "strings"
  6. "github.com/gin-gonic/gin"
  7. "github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager"
  8. "github.com/langgenius/dify-plugin-daemon/internal/service"
  9. "github.com/langgenius/dify-plugin-daemon/internal/types/app"
  10. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
  11. "github.com/langgenius/dify-plugin-daemon/internal/types/exception"
  12. )
  13. func GetAsset(c *gin.Context) {
  14. pluginManager := plugin_manager.Manager()
  15. asset, err := pluginManager.GetAsset(c.Param("id"))
  16. if err != nil {
  17. c.JSON(http.StatusInternalServerError, exception.InternalServerError(err).ToResponse())
  18. return
  19. }
  20. c.Data(http.StatusOK, "application/octet-stream", asset)
  21. }
  22. func UploadPlugin(app *app.Config) gin.HandlerFunc {
  23. return func(c *gin.Context) {
  24. difyPkgFileHeader, err := c.FormFile("dify_pkg")
  25. if err != nil {
  26. c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())
  27. return
  28. }
  29. tenantId := c.Param("tenant_id")
  30. if tenantId == "" {
  31. c.JSON(http.StatusOK, exception.BadRequestError(errors.New("Tenant ID is required")).ToResponse())
  32. return
  33. }
  34. if difyPkgFileHeader.Size > app.MaxPluginPackageSize {
  35. c.JSON(http.StatusOK, exception.BadRequestError(errors.New("File size exceeds the maximum limit")).ToResponse())
  36. return
  37. }
  38. verifySignature := c.PostForm("verify_signature") == "true"
  39. difyPkgFile, err := difyPkgFileHeader.Open()
  40. if err != nil {
  41. c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())
  42. return
  43. }
  44. defer difyPkgFile.Close()
  45. c.JSON(http.StatusOK, service.UploadPluginPkg(app, c, tenantId, difyPkgFile, verifySignature))
  46. }
  47. }
  48. func UploadBundle(app *app.Config) gin.HandlerFunc {
  49. return func(c *gin.Context) {
  50. difyBundleFileHeader, err := c.FormFile("dify_bundle")
  51. if err != nil {
  52. c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())
  53. return
  54. }
  55. tenantId := c.Param("tenant_id")
  56. if tenantId == "" {
  57. c.JSON(http.StatusOK, exception.BadRequestError(errors.New("Tenant ID is required")).ToResponse())
  58. return
  59. }
  60. if difyBundleFileHeader.Size > app.MaxBundlePackageSize {
  61. c.JSON(http.StatusOK, exception.BadRequestError(errors.New("File size exceeds the maximum limit")).ToResponse())
  62. return
  63. }
  64. verifySignature := c.PostForm("verify_signature") == "true"
  65. difyBundleFile, err := difyBundleFileHeader.Open()
  66. if err != nil {
  67. c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())
  68. return
  69. }
  70. defer difyBundleFile.Close()
  71. c.JSON(http.StatusOK, service.UploadPluginBundle(app, c, tenantId, difyBundleFile, verifySignature))
  72. }
  73. }
  74. func UpgradePlugin(app *app.Config) gin.HandlerFunc {
  75. return func(c *gin.Context) {
  76. BindRequest(c, func(request struct {
  77. TenantID string `uri:"tenant_id" validate:"required"`
  78. OriginalPluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `json:"original_plugin_unique_identifier" validate:"required,plugin_unique_identifier"`
  79. NewPluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `json:"new_plugin_unique_identifier" validate:"required,plugin_unique_identifier"`
  80. Source string `json:"source" validate:"required"`
  81. Meta map[string]any `json:"meta" validate:"omitempty"`
  82. }) {
  83. c.JSON(http.StatusOK, service.UpgradePlugin(
  84. app,
  85. request.TenantID,
  86. request.Source,
  87. request.Meta,
  88. request.OriginalPluginUniqueIdentifier,
  89. request.NewPluginUniqueIdentifier,
  90. ))
  91. })
  92. }
  93. }
  94. func InstallPluginFromIdentifiers(app *app.Config) gin.HandlerFunc {
  95. return func(c *gin.Context) {
  96. BindRequest(c, func(request struct {
  97. TenantID string `uri:"tenant_id" validate:"required"`
  98. PluginUniqueIdentifiers []plugin_entities.PluginUniqueIdentifier `json:"plugin_unique_identifiers" validate:"required,max=64,dive,plugin_unique_identifier"`
  99. Source string `json:"source" validate:"required"`
  100. Meta map[string]any `json:"meta" validate:"omitempty"`
  101. }) {
  102. if request.Meta == nil {
  103. request.Meta = map[string]any{}
  104. }
  105. c.JSON(http.StatusOK, service.InstallPluginFromIdentifiers(
  106. app, request.TenantID, request.PluginUniqueIdentifiers, request.Source, request.Meta,
  107. ))
  108. })
  109. }
  110. }
  111. func FetchPluginInstallationTasks(c *gin.Context) {
  112. BindRequest(c, func(request struct {
  113. TenantID string `uri:"tenant_id" validate:"required"`
  114. Page int `form:"page" validate:"required,min=1"`
  115. PageSize int `form:"page_size" validate:"required,min=1,max=256"`
  116. }) {
  117. c.JSON(http.StatusOK, service.FetchPluginInstallationTasks(request.TenantID, request.Page, request.PageSize))
  118. })
  119. }
  120. func FetchPluginInstallationTask(c *gin.Context) {
  121. BindRequest(c, func(request struct {
  122. TenantID string `uri:"tenant_id" validate:"required"`
  123. TaskID string `uri:"id" validate:"required"`
  124. }) {
  125. c.JSON(http.StatusOK, service.FetchPluginInstallationTask(request.TenantID, request.TaskID))
  126. })
  127. }
  128. func DeletePluginInstallationTask(c *gin.Context) {
  129. BindRequest(c, func(request struct {
  130. TenantID string `uri:"tenant_id" validate:"required"`
  131. TaskID string `uri:"id" validate:"required"`
  132. }) {
  133. c.JSON(http.StatusOK, service.DeletePluginInstallationTask(request.TenantID, request.TaskID))
  134. })
  135. }
  136. func DeleteAllPluginInstallationTasks(c *gin.Context) {
  137. BindRequest(c, func(request struct {
  138. TenantID string `uri:"tenant_id" validate:"required"`
  139. }) {
  140. c.JSON(http.StatusOK, service.DeleteAllPluginInstallationTasks(request.TenantID))
  141. })
  142. }
  143. func DeletePluginInstallationItemFromTask(c *gin.Context) {
  144. BindRequest(c, func(request struct {
  145. TenantID string `uri:"tenant_id" validate:"required"`
  146. TaskID string `uri:"id" validate:"required"`
  147. Identifier string `uri:"identifier" validate:"required"`
  148. }) {
  149. identifierString := strings.TrimLeft(request.Identifier, "/")
  150. identifier, err := plugin_entities.NewPluginUniqueIdentifier(identifierString)
  151. if err != nil {
  152. c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())
  153. return
  154. }
  155. c.JSON(http.StatusOK, service.DeletePluginInstallationItemFromTask(request.TenantID, request.TaskID, identifier))
  156. })
  157. }
  158. func FetchPluginManifest(c *gin.Context) {
  159. BindRequest(c, func(request struct {
  160. TenantID string `uri:"tenant_id" validate:"required"`
  161. PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `form:"plugin_unique_identifier" validate:"required,plugin_unique_identifier"`
  162. }) {
  163. c.JSON(http.StatusOK, service.FetchPluginManifest(request.TenantID, request.PluginUniqueIdentifier))
  164. })
  165. }
  166. func UninstallPlugin(c *gin.Context) {
  167. BindRequest(c, func(request struct {
  168. TenantID string `uri:"tenant_id" validate:"required"`
  169. PluginInstallationID string `json:"plugin_installation_id" validate:"required"`
  170. }) {
  171. c.JSON(http.StatusOK, service.UninstallPlugin(request.TenantID, request.PluginInstallationID))
  172. })
  173. }
  174. func FetchPluginFromIdentifier(c *gin.Context) {
  175. BindRequest(c, func(request struct {
  176. PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `form:"plugin_unique_identifier" validate:"required,plugin_unique_identifier"`
  177. }) {
  178. c.JSON(http.StatusOK, service.FetchPluginFromIdentifier(request.PluginUniqueIdentifier))
  179. })
  180. }
  181. func ListPlugins(c *gin.Context) {
  182. BindRequest(c, func(request struct {
  183. TenantID string `uri:"tenant_id" validate:"required"`
  184. Page int `form:"page" validate:"required,min=1"`
  185. PageSize int `form:"page_size" validate:"required,min=1,max=256"`
  186. }) {
  187. c.JSON(http.StatusOK, service.ListPlugins(request.TenantID, request.Page, request.PageSize))
  188. })
  189. }
  190. func BatchFetchPluginInstallationByIDs(c *gin.Context) {
  191. BindRequest(c, func(request struct {
  192. TenantID string `uri:"tenant_id" validate:"required"`
  193. PluginIDs []string `json:"plugin_ids" validate:"required,max=256"`
  194. }) {
  195. c.JSON(http.StatusOK, service.BatchFetchPluginInstallationByIDs(request.TenantID, request.PluginIDs))
  196. })
  197. }
  198. func FetchMissingPluginInstallations(c *gin.Context) {
  199. BindRequest(c, func(request struct {
  200. TenantID string `uri:"tenant_id" validate:"required"`
  201. PluginUniqueIdentifiers []plugin_entities.PluginUniqueIdentifier `json:"plugin_unique_identifiers" validate:"required,max=256,dive,plugin_unique_identifier"`
  202. }) {
  203. c.JSON(http.StatusOK, service.FetchMissingPluginInstallations(request.TenantID, request.PluginUniqueIdentifiers))
  204. })
  205. }