mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
refactor(runner): add builtin action provider interface
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
package work.slhaf.partner.module.modules.action.builtin;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface BuiltinActionProvider {
|
||||||
|
List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions();
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import work.slhaf.partner.core.action.ActionCapability;
|
|||||||
import work.slhaf.partner.core.action.entity.MetaActionInfo;
|
import work.slhaf.partner.core.action.entity.MetaActionInfo;
|
||||||
import work.slhaf.partner.core.action.exception.MetaActionNotFoundException;
|
import work.slhaf.partner.core.action.exception.MetaActionNotFoundException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -23,8 +24,6 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone {
|
|||||||
@InjectCapability
|
@InjectCapability
|
||||||
private ActionCapability actionCapability;
|
private ActionCapability actionCapability;
|
||||||
|
|
||||||
private final BuiltinCommandActionManager builtinCommandActionManager = new BuiltinCommandActionManager();
|
|
||||||
|
|
||||||
@Init
|
@Init
|
||||||
public void init() {
|
public void init() {
|
||||||
definitions.clear();
|
definitions.clear();
|
||||||
@@ -36,14 +35,10 @@ public class BuiltinActionRegistry extends AbstractAgentModule.Standalone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected List<BuiltinActionDefinition> buildDefaultActionDefinitions() {
|
protected List<BuiltinActionDefinition> buildDefaultActionDefinitions() {
|
||||||
return List.of(
|
List<BuiltinActionDefinition> builtinActionDefinitions = new ArrayList<>();
|
||||||
builtinCommandActionManager.buildCommandExecuteDefinition(),
|
BuiltinActionProvider commandActionProvider = new BuiltinCommandActionProvider();
|
||||||
builtinCommandActionManager.buildCommandStartDefinition(),
|
builtinActionDefinitions.addAll(commandActionProvider.provideBuiltinActions());
|
||||||
builtinCommandActionManager.buildCommandInspectDefinition(),
|
return builtinActionDefinitions;
|
||||||
builtinCommandActionManager.buildCommandReadDefinition(),
|
|
||||||
builtinCommandActionManager.buildCommandCancelDefinition(),
|
|
||||||
builtinCommandActionManager.buildCommandOverviewDefinition()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defineBuiltinAction(String name, MetaActionInfo metaActionInfo, Function<Map<String, Object>, String> invoker) {
|
public void defineBuiltinAction(String name, MetaActionInfo metaActionInfo, Function<Map<String, Object>, String> invoker) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import java.util.function.Function;
|
|||||||
|
|
||||||
import static work.slhaf.partner.core.action.ActionCore.BUILTIN_LOCATION;
|
import static work.slhaf.partner.core.action.ActionCore.BUILTIN_LOCATION;
|
||||||
|
|
||||||
class BuiltinCommandActionManager {
|
class BuiltinCommandActionProvider implements BuiltinActionProvider {
|
||||||
|
|
||||||
private static final String COMMAND_LOCATION = BUILTIN_LOCATION + "::" + "command";
|
private static final String COMMAND_LOCATION = BUILTIN_LOCATION + "::" + "command";
|
||||||
private static final String COMMAND_ARG_PREFIX = "arg";
|
private static final String COMMAND_ARG_PREFIX = "arg";
|
||||||
@@ -25,12 +25,24 @@ class BuiltinCommandActionManager {
|
|||||||
private final ConcurrentHashMap<String, CommandHandle> commandHandles = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, CommandHandle> commandHandles = new ConcurrentHashMap<>();
|
||||||
private final CommandExecutionService commandExecutionService = CommandExecutionService.INSTANCE;
|
private final CommandExecutionService commandExecutionService = CommandExecutionService.INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BuiltinActionRegistry.BuiltinActionDefinition> provideBuiltinActions() {
|
||||||
|
return List.of(
|
||||||
|
buildCommandExecuteDefinition(),
|
||||||
|
buildCommandStartDefinition(),
|
||||||
|
buildCommandInspectDefinition(),
|
||||||
|
buildCommandReadDefinition(),
|
||||||
|
buildCommandCancelDefinition(),
|
||||||
|
buildCommandOverviewDefinition()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用于直接执行的 Builtin MetaAction
|
* 用于直接执行的 Builtin MetaAction
|
||||||
*
|
*
|
||||||
* @return 内建 MetaAction 定义数据,参数为常规命令列表,返回值为该命令的响应内容
|
* @return 内建 MetaAction 定义数据,参数为常规命令列表,返回值为该命令的响应内容
|
||||||
*/
|
*/
|
||||||
BuiltinActionRegistry.BuiltinActionDefinition buildCommandExecuteDefinition() {
|
private BuiltinActionRegistry.BuiltinActionDefinition buildCommandExecuteDefinition() {
|
||||||
Set<String> tags = new HashSet<>(basicTags);
|
Set<String> tags = new HashSet<>(basicTags);
|
||||||
tags.add("Command Execution");
|
tags.add("Command Execution");
|
||||||
MetaActionInfo info = new MetaActionInfo(
|
MetaActionInfo info = new MetaActionInfo(
|
||||||
@@ -61,7 +73,7 @@ class BuiltinCommandActionManager {
|
|||||||
*
|
*
|
||||||
* @return 内建 MetaAction 定义数据,参数为命令列表及进程描述,返回值为进程句柄 id
|
* @return 内建 MetaAction 定义数据,参数为命令列表及进程描述,返回值为进程句柄 id
|
||||||
*/
|
*/
|
||||||
BuiltinActionRegistry.BuiltinActionDefinition buildCommandStartDefinition() {
|
private BuiltinActionRegistry.BuiltinActionDefinition buildCommandStartDefinition() {
|
||||||
Set<String> tags = new HashSet<>(basicTags);
|
Set<String> tags = new HashSet<>(basicTags);
|
||||||
tags.add("Command Session");
|
tags.add("Command Session");
|
||||||
MetaActionInfo info = new MetaActionInfo(
|
MetaActionInfo info = new MetaActionInfo(
|
||||||
@@ -106,7 +118,7 @@ class BuiltinCommandActionManager {
|
|||||||
*
|
*
|
||||||
* @return 内建 MetaAction 定义数据,参数为进程 id,返回值为摘要内容(CommandInspectData)
|
* @return 内建 MetaAction 定义数据,参数为进程 id,返回值为摘要内容(CommandInspectData)
|
||||||
*/
|
*/
|
||||||
BuiltinActionRegistry.BuiltinActionDefinition buildCommandInspectDefinition() {
|
private BuiltinActionRegistry.BuiltinActionDefinition buildCommandInspectDefinition() {
|
||||||
Set<String> tags = new HashSet<>(basicTags);
|
Set<String> tags = new HashSet<>(basicTags);
|
||||||
tags.add("Command Session");
|
tags.add("Command Session");
|
||||||
MetaActionInfo info = new MetaActionInfo(
|
MetaActionInfo info = new MetaActionInfo(
|
||||||
@@ -143,7 +155,7 @@ class BuiltinCommandActionManager {
|
|||||||
*
|
*
|
||||||
* @return 内建 MetaAction 定义数据,参数为进程 id 与读取流(stdout/stderr),返回值为读取内容(CommandReadData)
|
* @return 内建 MetaAction 定义数据,参数为进程 id 与读取流(stdout/stderr),返回值为读取内容(CommandReadData)
|
||||||
*/
|
*/
|
||||||
BuiltinActionRegistry.BuiltinActionDefinition buildCommandReadDefinition() {
|
private BuiltinActionRegistry.BuiltinActionDefinition buildCommandReadDefinition() {
|
||||||
Set<String> tags = new HashSet<>(basicTags);
|
Set<String> tags = new HashSet<>(basicTags);
|
||||||
tags.add("Command Session");
|
tags.add("Command Session");
|
||||||
tags.add("Command Read");
|
tags.add("Command Read");
|
||||||
@@ -206,7 +218,7 @@ class BuiltinCommandActionManager {
|
|||||||
*
|
*
|
||||||
* @return 内建 MetaAction 定义数据,参数为进程 id,返回值为是否成功取消
|
* @return 内建 MetaAction 定义数据,参数为进程 id,返回值为是否成功取消
|
||||||
*/
|
*/
|
||||||
BuiltinActionRegistry.BuiltinActionDefinition buildCommandCancelDefinition() {
|
private BuiltinActionRegistry.BuiltinActionDefinition buildCommandCancelDefinition() {
|
||||||
Set<String> tags = new HashSet<>(basicTags);
|
Set<String> tags = new HashSet<>(basicTags);
|
||||||
tags.add("Command Session");
|
tags.add("Command Session");
|
||||||
tags.add("Command Cancel");
|
tags.add("Command Cancel");
|
||||||
@@ -253,7 +265,7 @@ class BuiltinCommandActionManager {
|
|||||||
*
|
*
|
||||||
* @return 内建 MetaAction 定义数据,无参数,返回值为后台进程集合(CommandOverviewItem)
|
* @return 内建 MetaAction 定义数据,无参数,返回值为后台进程集合(CommandOverviewItem)
|
||||||
*/
|
*/
|
||||||
BuiltinActionRegistry.BuiltinActionDefinition buildCommandOverviewDefinition() {
|
private BuiltinActionRegistry.BuiltinActionDefinition buildCommandOverviewDefinition() {
|
||||||
Set<String> tags = new HashSet<>(basicTags);
|
Set<String> tags = new HashSet<>(basicTags);
|
||||||
tags.add("Command Session");
|
tags.add("Command Session");
|
||||||
tags.add("Command Overview");
|
tags.add("Command Overview");
|
||||||
@@ -5,15 +5,21 @@ import com.alibaba.fastjson2.JSONObject;
|
|||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
class BuiltinCommandActionManagerTest {
|
class BuiltinCommandActionProviderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testStartInspectReadAndOverview() throws Exception {
|
void testStartInspectReadAndOverview() throws Exception {
|
||||||
BuiltinCommandActionManager manager = new BuiltinCommandActionManager();
|
BuiltinCommandActionProvider provider = new BuiltinCommandActionProvider();
|
||||||
|
List<BuiltinActionRegistry.BuiltinActionDefinition> definitions = provider.provideBuiltinActions();
|
||||||
|
BuiltinActionRegistry.BuiltinActionDefinition start = requireDefinition(definitions, "builtin::command::start");
|
||||||
|
BuiltinActionRegistry.BuiltinActionDefinition inspectDefinition = requireDefinition(definitions, "builtin::command::inspect");
|
||||||
|
BuiltinActionRegistry.BuiltinActionDefinition readDefinition = requireDefinition(definitions, "builtin::command::read");
|
||||||
|
BuiltinActionRegistry.BuiltinActionDefinition overviewDefinition = requireDefinition(definitions, "builtin::command::overview");
|
||||||
|
|
||||||
String startResult = manager.buildCommandStartDefinition().invoker().apply(Map.of(
|
String startResult = start.invoker().apply(Map.of(
|
||||||
"desc", "demo-session",
|
"desc", "demo-session",
|
||||||
"arg", "sh",
|
"arg", "sh",
|
||||||
"arg1", "-lc",
|
"arg1", "-lc",
|
||||||
@@ -22,7 +28,7 @@ class BuiltinCommandActionManagerTest {
|
|||||||
String executionId = JSONObject.parseObject(startResult).getString("executionId");
|
String executionId = JSONObject.parseObject(startResult).getString("executionId");
|
||||||
Assertions.assertNotNull(executionId);
|
Assertions.assertNotNull(executionId);
|
||||||
|
|
||||||
JSONObject inspect = waitForInspectExit(manager, executionId);
|
JSONObject inspect = waitForInspectExit(inspectDefinition, executionId);
|
||||||
Assertions.assertEquals("demo-session", inspect.getString("desc"));
|
Assertions.assertEquals("demo-session", inspect.getString("desc"));
|
||||||
Assertions.assertEquals(0, inspect.getInteger("exitCode"));
|
Assertions.assertEquals(0, inspect.getInteger("exitCode"));
|
||||||
Assertions.assertTrue(inspect.getInteger("stdoutSize") > 0);
|
Assertions.assertTrue(inspect.getInteger("stdoutSize") > 0);
|
||||||
@@ -30,7 +36,7 @@ class BuiltinCommandActionManagerTest {
|
|||||||
Assertions.assertTrue(inspect.getString("stdoutSummary").contains("hello"));
|
Assertions.assertTrue(inspect.getString("stdoutSummary").contains("hello"));
|
||||||
Assertions.assertTrue(inspect.getString("stderrSummary").contains("oops"));
|
Assertions.assertTrue(inspect.getString("stderrSummary").contains("oops"));
|
||||||
|
|
||||||
JSONObject read = JSONObject.parseObject(manager.buildCommandReadDefinition().invoker().apply(Map.of(
|
JSONObject read = JSONObject.parseObject(readDefinition.invoker().apply(Map.of(
|
||||||
"id", executionId,
|
"id", executionId,
|
||||||
"limit", 5
|
"limit", 5
|
||||||
)));
|
)));
|
||||||
@@ -40,7 +46,7 @@ class BuiltinCommandActionManagerTest {
|
|||||||
Assertions.assertTrue(read.getBooleanValue("contentTruncated"));
|
Assertions.assertTrue(read.getBooleanValue("contentTruncated"));
|
||||||
Assertions.assertEquals("hello", read.getString("content"));
|
Assertions.assertEquals("hello", read.getString("content"));
|
||||||
|
|
||||||
JSONObject overview = JSONObject.parseObject(manager.buildCommandOverviewDefinition().invoker().apply(Map.of()));
|
JSONObject overview = JSONObject.parseObject(overviewDefinition.invoker().apply(Map.of()));
|
||||||
JSONArray result = overview.getJSONArray("result");
|
JSONArray result = overview.getJSONArray("result");
|
||||||
Assertions.assertTrue(result.stream().map(item -> (JSONObject) item)
|
Assertions.assertTrue(result.stream().map(item -> (JSONObject) item)
|
||||||
.anyMatch(item -> executionId.equals(item.getString("executionId"))));
|
.anyMatch(item -> executionId.equals(item.getString("executionId"))));
|
||||||
@@ -48,9 +54,13 @@ class BuiltinCommandActionManagerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCancelStopsBackgroundCommand() throws Exception {
|
void testCancelStopsBackgroundCommand() throws Exception {
|
||||||
BuiltinCommandActionManager manager = new BuiltinCommandActionManager();
|
BuiltinCommandActionProvider provider = new BuiltinCommandActionProvider();
|
||||||
|
List<BuiltinActionRegistry.BuiltinActionDefinition> definitions = provider.provideBuiltinActions();
|
||||||
|
BuiltinActionRegistry.BuiltinActionDefinition start = requireDefinition(definitions, "builtin::command::start");
|
||||||
|
BuiltinActionRegistry.BuiltinActionDefinition cancelDefinition = requireDefinition(definitions, "builtin::command::cancel");
|
||||||
|
BuiltinActionRegistry.BuiltinActionDefinition inspectDefinition = requireDefinition(definitions, "builtin::command::inspect");
|
||||||
|
|
||||||
String startResult = manager.buildCommandStartDefinition().invoker().apply(Map.of(
|
String startResult = start.invoker().apply(Map.of(
|
||||||
"desc", "sleep-session",
|
"desc", "sleep-session",
|
||||||
"arg", "sh",
|
"arg", "sh",
|
||||||
"arg1", "-lc",
|
"arg1", "-lc",
|
||||||
@@ -58,20 +68,30 @@ class BuiltinCommandActionManagerTest {
|
|||||||
));
|
));
|
||||||
String executionId = JSONObject.parseObject(startResult).getString("executionId");
|
String executionId = JSONObject.parseObject(startResult).getString("executionId");
|
||||||
|
|
||||||
JSONObject cancel = JSONObject.parseObject(manager.buildCommandCancelDefinition().invoker().apply(Map.of(
|
JSONObject cancel = JSONObject.parseObject(cancelDefinition.invoker().apply(Map.of(
|
||||||
"id", executionId
|
"id", executionId
|
||||||
)));
|
)));
|
||||||
Assertions.assertEquals(executionId, cancel.getString("executionId"));
|
Assertions.assertEquals(executionId, cancel.getString("executionId"));
|
||||||
Assertions.assertTrue(cancel.getBooleanValue("ok"));
|
Assertions.assertTrue(cancel.getBooleanValue("ok"));
|
||||||
|
|
||||||
JSONObject inspect = waitForInspectExit(manager, executionId);
|
JSONObject inspect = waitForInspectExit(inspectDefinition, executionId);
|
||||||
Assertions.assertNotNull(inspect.get("endAt"));
|
Assertions.assertNotNull(inspect.get("endAt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private JSONObject waitForInspectExit(BuiltinCommandActionManager manager, String executionId) throws Exception {
|
private BuiltinActionRegistry.BuiltinActionDefinition requireDefinition(
|
||||||
|
List<BuiltinActionRegistry.BuiltinActionDefinition> definitions,
|
||||||
|
String actionKey
|
||||||
|
) {
|
||||||
|
return definitions.stream()
|
||||||
|
.filter(definition -> actionKey.equals(definition.actionKey()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new AssertionError("definition not found: " + actionKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject waitForInspectExit(BuiltinActionRegistry.BuiltinActionDefinition inspectDefinition, String executionId) throws Exception {
|
||||||
long deadline = System.currentTimeMillis() + 3000;
|
long deadline = System.currentTimeMillis() + 3000;
|
||||||
while (System.currentTimeMillis() < deadline) {
|
while (System.currentTimeMillis() < deadline) {
|
||||||
JSONObject inspect = JSONObject.parseObject(manager.buildCommandInspectDefinition().invoker().apply(Map.of(
|
JSONObject inspect = JSONObject.parseObject(inspectDefinition.invoker().apply(Map.of(
|
||||||
"id", executionId
|
"id", executionId
|
||||||
)));
|
)));
|
||||||
if (inspect.get("exitCode") != null) {
|
if (inspect.get("exitCode") != null) {
|
||||||
Reference in New Issue
Block a user