节点在线、应用在线、配置在线使用令牌查询
大石头 authored at 2021-12-16 19:49:30
4.04 KiB
Stardust
using System.Text.Json;
using NewLife;
using NewLife.Data;
using Stardust.Data;
using XCode;
using Stardust.Data.Platform;

namespace Stardust.Web.Mcp.Actions.Apps;

/// <summary>搜索应用服务。按服务名/客户端/应用过滤,返回服务提供者列表</summary>
public class AppSearchServiceAction : McpActionBase
{
    /// <summary>动作名</summary>
    public override String Name => "app_search_service";

    /// <summary>动作描述</summary>
    public override String Description => "搜索应用注册的服务提供者(按服务名/客户端/应用ID过滤),返回服务地址、版本、健康状态等。公开查询,无需资源授权。";

    /// <summary>所属模块</summary>
    public override McpModuleType Module => McpModuleType.App;

    /// <summary>所需资源授权。null表示无资源依赖(公开查询)</summary>
    public override ResourceRequirement? RequiredResource => null;

    /// <summary>输入参数JSON Schema</summary>
    public override JsonElement InputSchema
    {
        get
        {
            var json = """
            {
              "type": "object",
              "properties": {
                "keyword": {"type": "string", "description": "可选,匹配服务名/客户端"},
                "app_id": {"type": "integer", "description": "可选,按应用过滤"},
                "service_id": {"type": "integer", "description": "可选,按服务ID过滤"},
                "client": {"type": "string", "description": "可选,按客户端标识过滤"},
                "enable": {"type": "boolean", "description": "可选,按启用状态过滤"},
                "page": {"type": "integer", "description": "页码,默认1"},
                "page_size": {"type": "integer", "description": "每页条数,默认20,最大100"}
              }
            }
            """;
            using var doc = JsonDocument.Parse(json);
            return doc.RootElement.Clone();
        }
    }

    /// <summary>调用动作</summary>
    public override Task<Object> InvokeAsync(JsonElement @params, McpContext context)
    {
        var keyword = GetString(@params, "keyword");
        var appId = GetInt32(@params, "app_id");
        var serviceId = GetInt32(@params, "service_id");
        var client = GetString(@params, "client");
        Boolean? enable = null;
        if (@params.TryGetProperty("enable", out var e) && e.ValueKind == JsonValueKind.False) enable = false;
        else if (e.ValueKind == JsonValueKind.True) enable = true;

        var page = GetInt32(@params, "page"); if (page <= 0) page = 1;
        var pageSize = GetInt32(@params, "page_size"); if (pageSize <= 0) pageSize = 20; if (pageSize > 100) pageSize = 100;

        // 资源授权过滤:若指定 app_id,校验其授权范围
        var authorizedProjectIds = Stardust.Data.Platform.McpTokenResource.GetAuthorizedProjectIds(context.TokenId);
        if (appId > 0 && authorizedProjectIds != null)
        {
            var app = App.FindById(appId);
            if (app == null || !authorizedProjectIds.Contains(app.ProjectId))
                throw new McpException(-32003, $"Forbidden: app_id={appId} is not authorized for this token");
        }

        var pageParam = new PageParameter { PageIndex = page, PageSize = pageSize };
        var list = AppService.Search(appId, serviceId, client, enable, keyword, pageParam);

        var records = list.Select(s => new
        {
            id = s.Id,
            app_id = s.AppId,
            service_id = s.ServiceId,
            service_name = s.ServiceName,
            client = s.Client,
            node_id = s.NodeId,
            enable = s.Enable,
            healthy = s.Healthy,
            version = s.Version,
            address = s.Address,
            weight = s.Weight,
            scope = s.Scope,
            tag = s.Tag,
            update_time = s.UpdateTime,
        }).ToList();

        return Task.FromResult<Object>(new
        {
            total = pageParam.TotalCount,
            page,
            page_size = pageSize,
            records,
        });
    }
}