dify/api/core/helper/marketplace.py
-LAN- e5ad372df9
feat: simplify marketplace plugin identifier format
- Drop checksum from marketplace_plugin_unique_identifier
- Use simpler org/name:version format instead of org/name:version@checksum
- Update download endpoint to /api/v1/plugins/{org}/{name}/{version}/download
- Maintain backward compatibility by stripping checksums when present
2025-09-04 01:09:55 +08:00

69 lines
2.5 KiB
Python

from collections.abc import Sequence
import httpx
from yarl import URL
from configs import dify_config
from core.helper.download import download_with_size_limit
from core.plugin.entities.marketplace import MarketplacePluginDeclaration
marketplace_api_url = URL(str(dify_config.MARKETPLACE_API_URL))
def get_plugin_pkg_url(plugin_unique_identifier: str) -> str:
# Parse org/name:version format (without checksum)
if "/" in plugin_unique_identifier and ":" in plugin_unique_identifier:
# Remove checksum if present (format: org/name:version@checksum)
if "@" in plugin_unique_identifier:
plugin_unique_identifier = plugin_unique_identifier.split("@")[0]
# Parse org/name:version
org_and_name, version = plugin_unique_identifier.rsplit(":", 1)
org, name = org_and_name.split("/", 1)
# Use new endpoint format
return str(marketplace_api_url / f"api/v1/plugins/{org}/{name}/{version}/download")
# Fallback to old format with query param
return str((marketplace_api_url / "api/v1/plugins/download").with_query(unique_identifier=plugin_unique_identifier))
def download_plugin_pkg(plugin_unique_identifier: str):
return download_with_size_limit(get_plugin_pkg_url(plugin_unique_identifier), dify_config.PLUGIN_MAX_PACKAGE_SIZE)
def batch_fetch_plugin_manifests(plugin_ids: list[str]) -> Sequence[MarketplacePluginDeclaration]:
if len(plugin_ids) == 0:
return []
url = str(marketplace_api_url / "api/v1/plugins/batch")
response = httpx.post(url, json={"plugin_ids": plugin_ids})
response.raise_for_status()
return [MarketplacePluginDeclaration(**plugin) for plugin in response.json()["data"]["plugins"]]
def batch_fetch_plugin_manifests_ignore_deserialization_error(
plugin_ids: list[str],
) -> Sequence[MarketplacePluginDeclaration]:
if len(plugin_ids) == 0:
return []
url = str(marketplace_api_url / "api/v1/plugins/batch")
response = httpx.post(url, json={"plugin_ids": plugin_ids})
response.raise_for_status()
result: list[MarketplacePluginDeclaration] = []
for plugin in response.json()["data"]["plugins"]:
try:
result.append(MarketplacePluginDeclaration(**plugin))
except Exception:
pass
return result
def record_install_plugin_event(plugin_unique_identifier: str):
url = str(marketplace_api_url / "api/v1/stats/plugins/install_count")
response = httpx.post(url, json={"unique_identifier": plugin_unique_identifier})
response.raise_for_status()