using System.Text.Json;
using NewLife;
using NewLife.Data;
using Stardust.Data.Nodes;
using XCode;
using Stardust.Data.Platform;
namespace Stardust.Web.Mcp.Actions.Nodes;
/// <summary>查询在线节点。按Token授æƒé¡¹ç›®è¿‡æ»¤ï¼Œæ”¯æŒå…³é”®å—和分页</summary>
public class NodeListOnlineAction : McpActionBase
{
/// <summary>动作å</summary>
public override String Name => "node_list_online";
/// <summary>动作æè¿°</summary>
public override String Description => "查询当å‰åœ¨çº¿çš„节点列表,按Token授æƒçš„项目范围过滤。LLMå¯é€šè¿‡æ¤åŠ¨ä½œå‘çŽ°å¯æ“作的节点。";
/// <summary>所属模å—</summary>
public override McpModuleType Module => McpModuleType.Node;
/// <summary>è¾“å…¥å‚æ•°JSON Schema</summary>
public override JsonElement InputSchema
{
get
{
var json = """
{
"type": "object",
"properties": {
"project_id": {"type": "integer", "description": "å¯é€‰ï¼ŒæŒ‰é¡¹ç›®è¿‡æ»¤"},
"keyword": {"type": "string", "description": "å¯é€‰ï¼ŒåŒ¹é…节点åç§°/SessionID"},
"category": {"type": "string", "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 projectId = GetInt32(@params, "project_id");
var keyword = GetString(@params, "keyword");
var category = GetString(@params, "category");
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;
// 获å–Token授æƒçš„项目ID列表(null表示全部项目授æƒï¼‰
var authorizedProjectIds = Stardust.Data.Platform.McpTokenResource.GetAuthorizedProjectIds(context.TokenId);
// è‹¥è°ƒç”¨æ–¹ä¼ äº†project_idï¼Œæ ¡éªŒå…¶æ˜¯å¦åœ¨æŽˆæƒèŒƒå›´å†…
if (projectId > 0 && authorizedProjectIds != null && !authorizedProjectIds.Contains(projectId))
throw new McpException(-32003, $"Forbidden: project_id={projectId} is not authorized for this token");
var pageParam = new PageParameter { PageIndex = page, PageSize = pageSize };
var start = DateTime.MinValue;
var end = DateTime.Now;
// 如果有授æƒé¡¹ç›®åˆ—表且未指定具体项目,则跨项目查询åŽè¿‡æ»¤
IList<NodeOnline> list;
if (projectId > 0)
{
list = NodeOnline.Search(projectId, 0, 0, 0, category, start, end, keyword, pageParam);
}
else if (authorizedProjectIds == null)
{
// 全部项目授æƒ
list = NodeOnline.Search(-1, 0, 0, 0, category, start, end, keyword, pageParam);
}
else
{
// 跨多个授æƒé¡¹ç›®æŸ¥è¯¢ï¼Œåˆå¹¶ç»“æžœ
list = new List<NodeOnline>();
foreach (var pid in authorizedProjectIds)
{
var sub = NodeOnline.Search(pid, 0, 0, 0, category, start, end, keyword, new PageParameter { PageIndex = 1, PageSize = 100 });
foreach (var n in sub)
{
if (list.Count >= pageSize * page) break;
list.Add(n);
}
}
list = list.Skip((page - 1) * pageSize).Take(pageSize).ToList();
pageParam.TotalCount = list.Count;
}
var records = list.Select(n => new
{
id = n.ID,
node_id = n.NodeID,
project_id = n.ProjectId,
name = n.Name,
ip = n.IP,
category = n.Category,
session_id = n.SessionID,
update_time = n.UpdateTime,
product_code = n.ProductCode,
}).ToList();
return Task.FromResult<Object>(new
{
total = pageParam.TotalCount,
page,
page_size = pageSize,
records,
});
}
}
|