- rebuild-venom.ps1:npm run build 后自动调 /api/sub/declare-page/,主服务器登记入口同时清空该产品资源缓存,重建产物立即生效(无需等 24h) - 声明端点支持请求体传 ApiKey/Secret(缺省回落环境变量),便于脚本按次传凭据
136 lines
5.3 KiB
Python
136 lines
5.3 KiB
Python
"""模块:GVSDServiceServer 视图
|
||
|
||
健康检查 / MSYNC 状态 / Venom 定制页远端组件 / 声明定制页(API Key + 密钥)
|
||
"""
|
||
|
||
import logging
|
||
from pathlib import Path
|
||
|
||
from django.conf import settings
|
||
from django.http import HttpResponse
|
||
from rest_framework.response import Response
|
||
from rest_framework.views import APIView
|
||
|
||
from .remote_pages import VENOM_REMOTE_ENTRY_JS
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def _ok(data=None, msg='success'):
|
||
return {'code': 200, 'msg': msg, 'data': data}
|
||
|
||
|
||
def _err(msg, code=400):
|
||
return {'code': code, 'msg': msg, 'data': None}
|
||
|
||
|
||
class HomeView(APIView):
|
||
def get(self, request):
|
||
return Response(_ok({
|
||
'Server': 'GVSDServiceServer',
|
||
'ServiceName': settings.MSYNC_SERVICE_NAME,
|
||
'RemoteEntry': settings.VENOM_REMOTE_ENTRY,
|
||
}))
|
||
|
||
|
||
class HealthView(APIView):
|
||
def get(self, request):
|
||
msync = getattr(settings, 'MSYNC_CLIENT', None)
|
||
return Response(_ok({
|
||
'Server': 'GVSDServiceServer',
|
||
'Status': 'running',
|
||
'MSync': {
|
||
'Connected': bool(msync and msync.IsConnected),
|
||
'Authenticated': bool(msync and msync.IsAuthenticated),
|
||
'Registered': bool(msync and msync.IsRegistered),
|
||
'ServiceName': msync.ServiceName if msync else settings.MSYNC_SERVICE_NAME,
|
||
'ServiceDomain': msync.ServiceDomain if msync else settings.MSYNC_SERVICE_DOMAIN,
|
||
'MasterURL': msync.MasterURL if msync else settings.MSYNC_MASTER_URL,
|
||
},
|
||
'Subscription': {
|
||
'HasApiKey': bool(settings.SUBSCRIPTION_API_KEY),
|
||
'HasSecret': bool(settings.SUBSCRIPTION_SECRET),
|
||
'MasterURL': settings.GVSDSDK_MSYNC_MASTER_URL,
|
||
},
|
||
}))
|
||
|
||
|
||
class MSyncStatusView(APIView):
|
||
def get(self, request):
|
||
msync = getattr(settings, 'MSYNC_CLIENT', None)
|
||
if not msync:
|
||
return Response(_err('MSYNC 未初始化(未配置 MSYNC_SERVICE_SECRET)', 500), status=500)
|
||
try:
|
||
peers = msync.DiscoverAll()
|
||
except Exception as e:
|
||
peers = {'Error': str(e)}
|
||
return Response(_ok({
|
||
'ServiceName': msync.ServiceName,
|
||
'ServiceDomain': msync.ServiceDomain,
|
||
'MasterURL': msync.MasterURL,
|
||
'Authenticated': msync.IsAuthenticated,
|
||
'Registered': msync.IsRegistered,
|
||
'Connected': msync.IsConnected,
|
||
'PeerServices': peers,
|
||
}))
|
||
|
||
|
||
class VenomRemoteEntryView(APIView):
|
||
"""Venom 定制页的远端入口(ES module,由主服务代理缓存后交给 GERP 宿主渲染)
|
||
|
||
内容来自 venom_ui 的 Vite 构建产物(venom_ui/dist/venom-entry.js);
|
||
未构建时回退到占位提示模块,避免 404/500。
|
||
|
||
浏览器不再直连本服务:主服务按产品的 RemoteEntry 回源到本端点并缓存
|
||
(见 gvsds 订阅应用 `GET /API/Subscription/RemoteAsset/<GroupUUID>/<Path>`),
|
||
因此这里无需再放行 CORS。
|
||
"""
|
||
|
||
def get(self, request):
|
||
dist_file = Path(settings.BASE_DIR) / 'venom_ui' / 'dist' / 'venom-entry.js'
|
||
if dist_file.is_file():
|
||
content = dist_file.read_text(encoding='utf-8')
|
||
else:
|
||
content = VENOM_REMOTE_ENTRY_JS
|
||
response = HttpResponse(content, content_type='text/javascript; charset=utf-8')
|
||
response['Cache-Control'] = 'no-store'
|
||
return response
|
||
|
||
|
||
class DeclarePageView(APIView):
|
||
"""用「产品 API Key + 密钥」调用主服务器,声明本产品定制页的远端入口
|
||
|
||
POST /api/sub/declare-page/ {ApiKey?, Secret?, RemoteEntry?, RemoteModule?}
|
||
—— 先 Ping 验证鉴权,再 DeclareCustomPage 登记远端入口。
|
||
|
||
凭据优先取请求体(便于 rebuild-venom.ps1 一键重建+声明时按次传入),
|
||
缺省回落到本服务环境变量(SUBSCRIPTION_API_KEY / SUBSCRIPTION_SECRET)。
|
||
主服务器登记入口的同时会清空该产品的资源缓存,故重新声明 = 重建产物立即生效。
|
||
"""
|
||
|
||
def post(self, request):
|
||
from gvsdsdk.subscription import SubscriptionClient, SubscriptionClientError
|
||
|
||
api_key = (request.data.get('ApiKey') or settings.SUBSCRIPTION_API_KEY or '').strip()
|
||
secret = (request.data.get('Secret') or settings.SUBSCRIPTION_SECRET or '').strip()
|
||
if not api_key or not secret:
|
||
return Response(
|
||
_err('缺少订阅凭据:请在请求体传 ApiKey/Secret,或注入环境变量 '
|
||
'SUBSCRIPTION_API_KEY / SUBSCRIPTION_SECRET', 500),
|
||
status=500,
|
||
)
|
||
|
||
entry = (request.data.get('RemoteEntry') or settings.VENOM_REMOTE_ENTRY or '').strip()
|
||
module = (request.data.get('RemoteModule') or 'default').strip() or 'default'
|
||
client = SubscriptionClient(api_key, secret, MasterURL=settings.GVSDSDK_MSYNC_MASTER_URL)
|
||
try:
|
||
ping = client.Ping()
|
||
page = client.DeclareCustomPage(entry, module)
|
||
except SubscriptionClientError as e:
|
||
logger.error('声明定制页失败: %s', e)
|
||
return Response(_err(str(e), 502), status=502)
|
||
logger.info('定制页入口已登记: %s', entry)
|
||
return Response(_ok({
|
||
'Ping': ping, 'Page': page, 'RemoteEntry': entry, 'RemoteModule': module,
|
||
}))
|