plugins.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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. Metas []map[string]any `json:"metas" validate:"omitempty"`
  101. }) {
  102. if request.Metas == nil {
  103. request.Metas = []map[string]any{}
  104. }
  105. if len(request.Metas) != len(request.PluginUniqueIdentifiers) {
  106. c.JSON(http.StatusOK, exception.BadRequestError(errors.New("the number of metas must be equal to the number of plugin unique identifiers")).ToResponse())
  107. return
  108. }
  109. for i := range request.Metas {
  110. if request.Metas[i] == nil {
  111. request.Metas[i] = map[string]any{}
  112. }
  113. }
  114. c.JSON(http.StatusOK, service.InstallPluginFromIdentifiers(
  115. app, request.TenantID, request.PluginUniqueIdentifiers, request.Source, request.Metas,
  116. ))
  117. })
  118. }
  119. }
  120. func FetchPluginInstallationTasks(c *gin.Context) {
  121. BindRequest(c, func(request struct {
  122. TenantID string `uri:"tenant_id" validate:"required"`
  123. Page int `form:"page" validate:"required,min=1"`
  124. PageSize int `form:"page_size" validate:"required,min=1,max=256"`
  125. }) {
  126. c.JSON(http.StatusOK, service.FetchPluginInstallationTasks(request.TenantID, request.Page, request.PageSize))
  127. })
  128. }
  129. func FetchPluginInstallationTask(c *gin.Context) {
  130. BindRequest(c, func(request struct {
  131. TenantID string `uri:"tenant_id" validate:"required"`
  132. TaskID string `uri:"id" validate:"required"`
  133. }) {
  134. c.JSON(http.StatusOK, service.FetchPluginInstallationTask(request.TenantID, request.TaskID))
  135. })
  136. }
  137. func DeletePluginInstallationTask(c *gin.Context) {
  138. BindRequest(c, func(request struct {
  139. TenantID string `uri:"tenant_id" validate:"required"`
  140. TaskID string `uri:"id" validate:"required"`
  141. }) {
  142. c.JSON(http.StatusOK, service.DeletePluginInstallationTask(request.TenantID, request.TaskID))
  143. })
  144. }
  145. func DeleteAllPluginInstallationTasks(c *gin.Context) {
  146. BindRequest(c, func(request struct {
  147. TenantID string `uri:"tenant_id" validate:"required"`
  148. }) {
  149. c.JSON(http.StatusOK, service.DeleteAllPluginInstallationTasks(request.TenantID))
  150. })
  151. }
  152. func DeletePluginInstallationItemFromTask(c *gin.Context) {
  153. BindRequest(c, func(request struct {
  154. TenantID string `uri:"tenant_id" validate:"required"`
  155. TaskID string `uri:"id" validate:"required"`
  156. Identifier string `uri:"identifier" validate:"required"`
  157. }) {
  158. identifierString := strings.TrimLeft(request.Identifier, "/")
  159. identifier, err := plugin_entities.NewPluginUniqueIdentifier(identifierString)
  160. if err != nil {
  161. c.JSON(http.StatusOK, exception.BadRequestError(err).ToResponse())
  162. return
  163. }
  164. c.JSON(http.StatusOK, service.DeletePluginInstallationItemFromTask(request.TenantID, request.TaskID, identifier))
  165. })
  166. }
  167. func FetchPluginManifest(c *gin.Context) {
  168. BindRequest(c, func(request struct {
  169. TenantID string `uri:"tenant_id" validate:"required"`
  170. PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `form:"plugin_unique_identifier" validate:"required,plugin_unique_identifier"`
  171. }) {
  172. c.JSON(http.StatusOK, service.FetchPluginManifest(request.TenantID, request.PluginUniqueIdentifier))
  173. })
  174. }
  175. func UninstallPlugin(c *gin.Context) {
  176. BindRequest(c, func(request struct {
  177. TenantID string `uri:"tenant_id" validate:"required"`
  178. PluginInstallationID string `json:"plugin_installation_id" validate:"required"`
  179. }) {
  180. c.JSON(http.StatusOK, service.UninstallPlugin(request.TenantID, request.PluginInstallationID))
  181. })
  182. }
  183. func FetchPluginFromIdentifier(c *gin.Context) {
  184. BindRequest(c, func(request struct {
  185. PluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier `form:"plugin_unique_identifier" validate:"required,plugin_unique_identifier"`
  186. }) {
  187. c.JSON(http.StatusOK, service.FetchPluginFromIdentifier(request.PluginUniqueIdentifier))
  188. })
  189. }
  190. func ListPlugins(c *gin.Context) {
  191. BindRequest(c, func(request struct {
  192. TenantID string `uri:"tenant_id" validate:"required"`
  193. Page int `form:"page" validate:"required,min=1"`
  194. PageSize int `form:"page_size" validate:"required,min=1,max=256"`
  195. }) {
  196. c.JSON(http.StatusOK, service.ListPlugins(request.TenantID, request.Page, request.PageSize))
  197. })
  198. }
  199. func BatchFetchPluginInstallationByIDs(c *gin.Context) {
  200. BindRequest(c, func(request struct {
  201. TenantID string `uri:"tenant_id" validate:"required"`
  202. PluginIDs []string `json:"plugin_ids" validate:"required,max=256"`
  203. }) {
  204. c.JSON(http.StatusOK, service.BatchFetchPluginInstallationByIDs(request.TenantID, request.PluginIDs))
  205. })
  206. }
  207. func FetchMissingPluginInstallations(c *gin.Context) {
  208. BindRequest(c, func(request struct {
  209. TenantID string `uri:"tenant_id" validate:"required"`
  210. PluginUniqueIdentifiers []plugin_entities.PluginUniqueIdentifier `json:"plugin_unique_identifiers" validate:"required,max=256,dive,plugin_unique_identifier"`
  211. }) {
  212. c.JSON(http.StatusOK, service.FetchMissingPluginInstallations(request.TenantID, request.PluginUniqueIdentifiers))
  213. })
  214. }