fix(api): 补齐 bat-api 控制与后端 RPC

This commit is contained in:
2026-07-31 17:01:03 +08:00
parent 20ddd67947
commit 6af7706190
17 changed files with 793 additions and 51 deletions
+83 -6
View File
@@ -190,14 +190,57 @@ type taskIDParam struct {
TaskID string `json:"task_id"`
}
type TextUnitQueryParams struct {
Offset int `json:"offset,omitempty"`
Limit int `json:"limit,omitempty"`
Destination string `json:"destination,omitempty"`
PathPattern string `json:"path_pattern,omitempty"`
ArchiveEntry string `json:"archive_entry,omitempty"`
PathID *int64 `json:"path_id,omitempty"`
ClassID *int `json:"class_id,omitempty"`
FieldPath string `json:"field_path,omitempty"`
Format string `json:"format,omitempty"`
}
type UnityFSTextAssetPatchParams struct {
BundlePath string `json:"bundle_path"`
SerializedFilePath string `json:"serialized_file_path"`
PathID int64 `json:"path_id"`
ReplacementPath string `json:"replacement_path"`
TargetPath string `json:"target_path"`
ExpectedName *string `json:"expected_name,omitempty"`
}
type UnityFSStringFieldPatchParams struct {
BundlePath string `json:"bundle_path"`
SerializedFilePath string `json:"serialized_file_path"`
PathID int64 `json:"path_id"`
FieldPath string `json:"field_path"`
ReplacementText *string `json:"replacement_text,omitempty"`
ReplacementPath string `json:"replacement_path,omitempty"`
TargetPath string `json:"target_path"`
ExpectedValue *string `json:"expected_value,omitempty"`
}
type UnityFSFieldPatchParams struct {
BundlePath string `json:"bundle_path"`
SerializedFilePath string `json:"serialized_file_path"`
PathID int64 `json:"path_id"`
FieldPath string `json:"field_path"`
Replacement json.RawMessage `json:"replacement"`
TargetPath string `json:"target_path"`
ExpectedValue json.RawMessage `json:"expected_value,omitempty"`
}
// Ack is returned by accepted daemon control methods.
type Ack struct {
Command string `json:"command"`
Status string `json:"status"`
Message string `json:"message"`
StateDir string `json:"state_dir"`
SocketPath string `json:"socket_path"`
Force *bool `json:"force,omitempty"`
Command string `json:"command"`
Status string `json:"status"`
Message string `json:"message"`
StateDir string `json:"state_dir"`
SocketPath string `json:"socket_path"`
ControllerPID *int `json:"controller_pid,omitempty"`
Force *bool `json:"force,omitempty"`
}
// TaskAccepted is returned when an async backend task is queued.
@@ -324,6 +367,12 @@ func (c *Client) DaemonStop(ctx context.Context) (*Ack, error) {
return &out, err
}
func (c *Client) DaemonRestart(ctx context.Context) (*Ack, error) {
var out Ack
_, err := c.Call(ctx, "daemon.restart", nil, &out)
return &out, err
}
func (c *Client) DaemonReload(ctx context.Context) (*Ack, error) {
var out Ack
_, err := c.Call(ctx, "daemon.reload", nil, &out)
@@ -396,6 +445,34 @@ func (c *Client) CatalogRefresh(ctx context.Context, force bool) (*TaskAccepted,
return &out, err
}
func (c *Client) ParseStatus(ctx context.Context) (json.RawMessage, error) {
return c.rawData(ctx, "parse.status", nil)
}
func (c *Client) ParseTextUnits(ctx context.Context, query TextUnitQueryParams) (json.RawMessage, error) {
return c.rawData(ctx, "parse.text_units", query)
}
func (c *Client) ParseErrors(ctx context.Context, query TextUnitQueryParams) (json.RawMessage, error) {
return c.rawData(ctx, "parse.errors", query)
}
func (c *Client) LocalizedStatus(ctx context.Context) (json.RawMessage, error) {
return c.rawData(ctx, "localized.status", nil)
}
func (c *Client) UnityFSPatchTextAsset(ctx context.Context, params UnityFSTextAssetPatchParams) (json.RawMessage, error) {
return c.rawData(ctx, "unityfs.patch_text_asset", params)
}
func (c *Client) UnityFSPatchStringField(ctx context.Context, params UnityFSStringFieldPatchParams) (json.RawMessage, error) {
return c.rawData(ctx, "unityfs.patch_string_field", params)
}
func (c *Client) UnityFSPatchField(ctx context.Context, params UnityFSFieldPatchParams) (json.RawMessage, error) {
return c.rawData(ctx, "unityfs.patch_field", params)
}
func (c *Client) TaskStatus(ctx context.Context, taskID string) (*TaskRecord, error) {
var out TaskRecord
_, err := c.Call(ctx, "task.status", taskIDParam{TaskID: taskID}, &out)
+114
View File
@@ -88,6 +88,120 @@ func TestResourceRepairQueuesTask(t *testing.T) {
}
}
func TestDaemonRestartSendsControlMethod(t *testing.T) {
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
if req.Method != "daemon.restart" {
t.Fatalf("method = %s", req.Method)
}
return testResponse{
Result: testEnvelope{
OK: true,
Status: "accepted",
RequestID: "req-test-restart",
Data: map[string]any{
"command": "restart",
"status": "accepted",
"message": "restart accepted",
"state_dir": "/tmp/bat-pid",
"socket_path": "/tmp/bat-pid/bat.sock",
"controller_pid": 4242,
},
},
}
})
ack, err := client.DaemonRestart(context.Background())
if err != nil {
t.Fatalf("DaemonRestart error: %v", err)
}
if ack.Command != "restart" || ack.ControllerPID == nil || *ack.ControllerPID != 4242 {
t.Fatalf("unexpected ack: %#v", ack)
}
}
func TestParseTextUnitsSendsQuery(t *testing.T) {
pathID := int64(7)
classID := 114
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
if req.Method != "parse.text_units" {
t.Fatalf("method = %s", req.Method)
}
var params TextUnitQueryParams
if err := json.Unmarshal(req.Params, &params); err != nil {
t.Fatalf("decode params: %v", err)
}
if params.Offset != 3 || params.Limit != 5 || params.Destination != "*Table*" || params.PathID == nil || *params.PathID != pathID || params.ClassID == nil || *params.ClassID != classID {
t.Fatalf("params = %#v", params)
}
return testResponse{
Result: testEnvelope{
OK: true,
Status: "ok",
RequestID: "req-test-parse",
Data: map[string]any{
"available": true,
"entries": []any{},
},
},
}
})
raw, err := client.ParseTextUnits(context.Background(), TextUnitQueryParams{
Offset: 3,
Limit: 5,
Destination: "*Table*",
PathID: &pathID,
ClassID: &classID,
})
if err != nil {
t.Fatalf("ParseTextUnits error: %v", err)
}
if !json.Valid(raw) {
t.Fatalf("invalid raw JSON: %s", string(raw))
}
}
func TestUnityFSPatchFieldSendsTaggedReplacement(t *testing.T) {
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
if req.Method != "unityfs.patch_field" {
t.Fatalf("method = %s", req.Method)
}
var params UnityFSFieldPatchParams
if err := json.Unmarshal(req.Params, &params); err != nil {
t.Fatalf("decode params: %v", err)
}
if params.BundlePath != "/tmp/source.bundle" || params.FieldPath != "m_Name" || string(params.Replacement) != `{"kind":"string","value":"new text"}` {
t.Fatalf("params = %#v replacement=%s", params, string(params.Replacement))
}
return testResponse{
Result: testEnvelope{
OK: true,
Status: "ok",
RequestID: "req-test-unityfs",
Data: map[string]any{
"command": "unityfs.patch_field",
"status": "completed",
},
},
}
})
raw, err := client.UnityFSPatchField(context.Background(), UnityFSFieldPatchParams{
BundlePath: "/tmp/source.bundle",
SerializedFilePath: "CAB-test",
PathID: 1,
FieldPath: "m_Name",
Replacement: json.RawMessage(`{"kind":"string","value":"new text"}`),
TargetPath: "/tmp/target.bundle",
})
if err != nil {
t.Fatalf("UnityFSPatchField error: %v", err)
}
if !json.Valid(raw) {
t.Fatalf("invalid raw JSON: %s", string(raw))
}
}
func TestResourceListSendsPagination(t *testing.T) {
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
if req.Method != "resource.list" {