setup_endpoint.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. package service
  2. import (
  3. "fmt"
  4. "github.com/langgenius/dify-plugin-daemon/internal/core/dify_invocation"
  5. "github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager"
  6. "github.com/langgenius/dify-plugin-daemon/internal/db"
  7. "github.com/langgenius/dify-plugin-daemon/internal/service/install_service"
  8. "github.com/langgenius/dify-plugin-daemon/internal/types/entities"
  9. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
  10. "github.com/langgenius/dify-plugin-daemon/internal/types/models"
  11. "github.com/langgenius/dify-plugin-daemon/internal/utils/cache/helper"
  12. "github.com/langgenius/dify-plugin-daemon/internal/utils/encryption"
  13. )
  14. func SetupEndpoint(
  15. tenant_id string,
  16. user_id string,
  17. pluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier,
  18. name string,
  19. settings map[string]any,
  20. ) *entities.Response {
  21. // try find plugin installation
  22. installation, err := db.GetOne[models.PluginInstallation](
  23. db.Equal("tenant_id", tenant_id),
  24. db.Equal("plugin_unique_identifier", pluginUniqueIdentifier.String()),
  25. )
  26. if err != nil {
  27. return entities.NewErrorResponse(-404, fmt.Sprintf("failed to find plugin installation: %v", err))
  28. }
  29. // try get plugin
  30. pluginDeclaration, err := helper.CombinedGetPluginDeclaration(
  31. pluginUniqueIdentifier,
  32. tenant_id,
  33. plugin_entities.PluginRuntimeType(installation.RuntimeType),
  34. )
  35. if err != nil {
  36. return entities.NewErrorResponse(-404, fmt.Sprintf("failed to find plugin: %v", err))
  37. }
  38. if !pluginDeclaration.Resource.Permission.AllowRegisterEndpoint() {
  39. return entities.NewErrorResponse(-403, "permission denied")
  40. }
  41. if pluginDeclaration.Endpoint == nil {
  42. return entities.NewErrorResponse(-404, "plugin does not have an endpoint")
  43. }
  44. // check settings
  45. if err := plugin_entities.ValidateProviderConfigs(settings, pluginDeclaration.Endpoint.Settings); err != nil {
  46. return entities.NewErrorResponse(-400, fmt.Sprintf("failed to validate settings: %v", err))
  47. }
  48. endpoint, err := install_service.InstallEndpoint(
  49. pluginUniqueIdentifier,
  50. installation.ID,
  51. tenant_id,
  52. user_id,
  53. name,
  54. map[string]any{},
  55. )
  56. if err != nil {
  57. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to setup endpoint: %v", err))
  58. }
  59. manager := plugin_manager.Manager()
  60. if manager == nil {
  61. return entities.NewErrorResponse(-500, "failed to get plugin manager")
  62. }
  63. // encrypt settings
  64. encryptedSettings, err := manager.BackwardsInvocation().InvokeEncrypt(
  65. &dify_invocation.InvokeEncryptRequest{
  66. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  67. TenantId: tenant_id,
  68. UserId: user_id,
  69. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  70. },
  71. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  72. Opt: dify_invocation.ENCRYPT_OPT_ENCRYPT,
  73. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  74. Identity: endpoint.ID,
  75. Data: settings,
  76. Config: pluginDeclaration.Endpoint.Settings,
  77. },
  78. },
  79. )
  80. if err != nil {
  81. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to encrypt settings: %v", err))
  82. }
  83. if err := install_service.UpdateEndpoint(endpoint, name, encryptedSettings); err != nil {
  84. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to update endpoint: %v", err))
  85. }
  86. return entities.NewSuccessResponse(true)
  87. }
  88. func RemoveEndpoint(endpoint_id string, tenant_id string) *entities.Response {
  89. endpoint, err := db.GetOne[models.Endpoint](
  90. db.Equal("id", endpoint_id),
  91. db.Equal("tenant_id", tenant_id),
  92. )
  93. if err != nil {
  94. return entities.NewErrorResponse(-404, fmt.Sprintf("failed to find endpoint: %v", err))
  95. }
  96. err = install_service.UninstallEndpoint(&endpoint)
  97. if err != nil {
  98. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to remove endpoint: %v", err))
  99. }
  100. manager := plugin_manager.Manager()
  101. if manager == nil {
  102. return entities.NewErrorResponse(-500, "failed to get plugin manager")
  103. }
  104. // clear credentials cache
  105. if _, err := manager.BackwardsInvocation().InvokeEncrypt(&dify_invocation.InvokeEncryptRequest{
  106. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  107. TenantId: tenant_id,
  108. UserId: "",
  109. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  110. },
  111. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  112. Opt: dify_invocation.ENCRYPT_OPT_CLEAR,
  113. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  114. Identity: endpoint.ID,
  115. },
  116. }); err != nil {
  117. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to clear credentials cache: %v", err))
  118. }
  119. return entities.NewSuccessResponse(true)
  120. }
  121. func UpdateEndpoint(endpoint_id string, tenant_id string, user_id string, name string, settings map[string]any) *entities.Response {
  122. // get endpoint
  123. endpoint, err := db.GetOne[models.Endpoint](
  124. db.Equal("id", endpoint_id),
  125. db.Equal("tenant_id", tenant_id),
  126. )
  127. if err != nil {
  128. return entities.NewErrorResponse(-404, fmt.Sprintf("failed to find endpoint: %v", err))
  129. }
  130. // get plugin installation
  131. installation, err := db.GetOne[models.PluginInstallation](
  132. db.Equal("plugin_id", endpoint.PluginID),
  133. db.Equal("tenant_id", tenant_id),
  134. )
  135. if err != nil {
  136. return entities.NewErrorResponse(-404, fmt.Sprintf("failed to find plugin installation: %v", err))
  137. }
  138. pluginUniqueIdentifier, err := plugin_entities.NewPluginUniqueIdentifier(
  139. installation.PluginUniqueIdentifier,
  140. )
  141. if err != nil {
  142. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to parse plugin unique identifier: %v", err))
  143. }
  144. // get plugin
  145. pluginDeclaration, err := helper.CombinedGetPluginDeclaration(
  146. pluginUniqueIdentifier,
  147. tenant_id,
  148. plugin_entities.PluginRuntimeType(installation.RuntimeType),
  149. )
  150. if err != nil {
  151. return entities.NewErrorResponse(-404, fmt.Sprintf("failed to find plugin: %v", err))
  152. }
  153. if pluginDeclaration.Endpoint == nil {
  154. return entities.NewErrorResponse(-404, "plugin does not have an endpoint")
  155. }
  156. // decrypt original settings
  157. manager := plugin_manager.Manager()
  158. if manager == nil {
  159. return entities.NewErrorResponse(-500, "failed to get plugin manager")
  160. }
  161. originalSettings, err := manager.BackwardsInvocation().InvokeEncrypt(
  162. &dify_invocation.InvokeEncryptRequest{
  163. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  164. TenantId: tenant_id,
  165. UserId: user_id,
  166. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  167. },
  168. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  169. Opt: dify_invocation.ENCRYPT_OPT_DECRYPT,
  170. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  171. Identity: endpoint.ID,
  172. Data: endpoint.Settings,
  173. Config: pluginDeclaration.Endpoint.Settings,
  174. },
  175. },
  176. )
  177. if err != nil {
  178. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to decrypt settings: %v", err))
  179. }
  180. maskedSettings := encryption.MaskConfigCredentials(originalSettings, pluginDeclaration.Endpoint.Settings)
  181. // check if settings is changed, replace the value is the same as masked_settings
  182. for setting_name, value := range settings {
  183. if maskedSettings[setting_name] == value {
  184. settings[setting_name] = originalSettings[setting_name]
  185. }
  186. }
  187. // check settings
  188. if err := plugin_entities.ValidateProviderConfigs(settings, pluginDeclaration.Endpoint.Settings); err != nil {
  189. return entities.NewErrorResponse(-400, fmt.Sprintf("failed to validate settings: %v", err))
  190. }
  191. // encrypt settings
  192. encryptedSettings, err := manager.BackwardsInvocation().InvokeEncrypt(
  193. &dify_invocation.InvokeEncryptRequest{
  194. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  195. TenantId: tenant_id,
  196. UserId: user_id,
  197. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  198. },
  199. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  200. Opt: dify_invocation.ENCRYPT_OPT_ENCRYPT,
  201. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  202. Identity: endpoint.ID,
  203. Data: settings,
  204. Config: pluginDeclaration.Endpoint.Settings,
  205. },
  206. },
  207. )
  208. if err != nil {
  209. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to encrypt settings: %v", err))
  210. }
  211. // update endpoint
  212. if err := install_service.UpdateEndpoint(&endpoint, name, encryptedSettings); err != nil {
  213. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to update endpoint: %v", err))
  214. }
  215. // clear credentials cache
  216. if _, err := manager.BackwardsInvocation().InvokeEncrypt(&dify_invocation.InvokeEncryptRequest{
  217. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  218. TenantId: tenant_id,
  219. UserId: user_id,
  220. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  221. },
  222. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  223. Opt: dify_invocation.ENCRYPT_OPT_CLEAR,
  224. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  225. Identity: endpoint.ID,
  226. Data: settings,
  227. Config: pluginDeclaration.Endpoint.Settings,
  228. },
  229. }); err != nil {
  230. return entities.NewErrorResponse(-500, fmt.Sprintf("failed to clear credentials cache: %v", err))
  231. }
  232. return entities.NewSuccessResponse(true)
  233. }