mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 08:54:55 +08:00
@@ -273,6 +273,58 @@ type TranslationTaskUpdateParams struct {
|
||||
ProviderRunID string `json:"provider_run_id,omitempty"`
|
||||
}
|
||||
|
||||
// TranslationTaskListParams filters the Rust-owned translation task queue.
|
||||
// The result shape is intentionally left as Rust JSON so Go does not duplicate
|
||||
// the translation task schema.
|
||||
type TranslationTaskListParams struct {
|
||||
Offset *uint64 `json:"offset,omitempty"`
|
||||
Limit *uint64 `json:"limit,omitempty"`
|
||||
TaskID string `json:"task_id,omitempty"`
|
||||
ReleaseID string `json:"release_id,omitempty"`
|
||||
Destination string `json:"destination,omitempty"`
|
||||
PathPattern string `json:"path_pattern,omitempty"`
|
||||
ArchiveEntry string `json:"archive_entry,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
WorkerStatus string `json:"worker_status,omitempty"`
|
||||
ParseStatus string `json:"parse_status,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
HasReason *bool `json:"has_reason,omitempty"`
|
||||
HasFailureReason *bool `json:"has_failure_reason,omitempty"`
|
||||
}
|
||||
|
||||
// TranslationWorkerRunParams starts one Rust-owned provider worker task.
|
||||
// Pointer numeric fields preserve explicit zeroes so Rust can reject invalid
|
||||
// dashboard input instead of receiving omitted defaults.
|
||||
type TranslationWorkerRunParams struct {
|
||||
Provider string `json:"provider,omitempty"`
|
||||
FixturePath string `json:"fixture_path,omitempty"`
|
||||
Concurrency *uint64 `json:"concurrency,omitempty"`
|
||||
MaxAttempts *uint64 `json:"max_attempts,omitempty"`
|
||||
LeaseSeconds *uint64 `json:"lease_seconds,omitempty"`
|
||||
RetryBackoffSeconds *uint64 `json:"retry_backoff_seconds,omitempty"`
|
||||
MaxTasks *uint64 `json:"max_tasks,omitempty"`
|
||||
WorkerID string `json:"worker_id,omitempty"`
|
||||
}
|
||||
|
||||
// TranslationWorkerConfig mirrors the accepted worker config returned by Rust.
|
||||
type TranslationWorkerConfig struct {
|
||||
Provider string `json:"provider"`
|
||||
FixturePath string `json:"fixture_path,omitempty"`
|
||||
Concurrency uint64 `json:"concurrency"`
|
||||
MaxAttempts uint64 `json:"max_attempts"`
|
||||
LeaseSeconds uint64 `json:"lease_seconds"`
|
||||
RetryBackoffSeconds uint64 `json:"retry_backoff_seconds"`
|
||||
MaxTasks *uint64 `json:"max_tasks,omitempty"`
|
||||
WorkerID string `json:"worker_id"`
|
||||
}
|
||||
|
||||
// TranslationWorkerRunResult is returned when translation.worker.run is queued.
|
||||
type TranslationWorkerRunResult struct {
|
||||
TaskID string `json:"task_id"`
|
||||
Kind string `json:"kind"`
|
||||
Worker TranslationWorkerConfig `json:"worker"`
|
||||
}
|
||||
|
||||
// TranslationProofread marks the current localized workflow as manual
|
||||
// proofreading. Rust owns the persisted localized state.
|
||||
func (c *Client) TranslationProofread(ctx context.Context) (json.RawMessage, error) {
|
||||
@@ -502,6 +554,20 @@ func (c *Client) TranslationTaskUpdate(ctx context.Context, params TranslationTa
|
||||
return c.rawData(ctx, "translation.task.update", params)
|
||||
}
|
||||
|
||||
func (c *Client) TranslationTasks(ctx context.Context, params TranslationTaskListParams) (json.RawMessage, error) {
|
||||
return c.rawData(ctx, "translation.tasks", params)
|
||||
}
|
||||
|
||||
func (c *Client) TranslationHandoff(ctx context.Context) (json.RawMessage, error) {
|
||||
return c.rawData(ctx, "translation.handoff", nil)
|
||||
}
|
||||
|
||||
func (c *Client) TranslationWorkerRun(ctx context.Context, params TranslationWorkerRunParams) (*TranslationWorkerRunResult, error) {
|
||||
var out TranslationWorkerRunResult
|
||||
_, err := c.Call(ctx, "translation.worker.run", params, &out)
|
||||
return &out, err
|
||||
}
|
||||
|
||||
func (c *Client) CatalogStatus(ctx context.Context) (json.RawMessage, error) {
|
||||
return c.rawData(ctx, "catalog.status", nil)
|
||||
}
|
||||
|
||||
@@ -336,6 +336,94 @@ func TestScheduleRunSendsScopeAndMaxRuns(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslationTasksSendsQueryParams(t *testing.T) {
|
||||
offset := uint64(10)
|
||||
limit := uint64(25)
|
||||
hasReason := true
|
||||
hasFailureReason := false
|
||||
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
|
||||
if req.Method != "translation.tasks" {
|
||||
t.Fatalf("method = %s", req.Method)
|
||||
}
|
||||
var params TranslationTaskListParams
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
t.Fatalf("decode params: %v", err)
|
||||
}
|
||||
if params.Offset == nil || *params.Offset != offset ||
|
||||
params.Limit == nil || *params.Limit != limit ||
|
||||
params.TaskID != "textunit/v-current/Scenario" ||
|
||||
params.ReleaseID != "v-current" ||
|
||||
params.Destination != "MediaResources/GameData/Scenario.zip" ||
|
||||
params.PathPattern != "Scenario" ||
|
||||
params.ArchiveEntry != "ScenarioExcelTable.json" ||
|
||||
params.Status != "queued_offline" ||
|
||||
params.WorkerStatus != "failed" ||
|
||||
params.ParseStatus != "ok" ||
|
||||
params.Format != "json" ||
|
||||
params.HasReason == nil || *params.HasReason != hasReason ||
|
||||
params.HasFailureReason == nil || *params.HasFailureReason != hasFailureReason {
|
||||
t.Fatalf("params = %#v", params)
|
||||
}
|
||||
return testResponse{
|
||||
Result: testEnvelope{
|
||||
OK: true,
|
||||
Status: "ok",
|
||||
RequestID: "req-test-translation-tasks",
|
||||
Data: map[string]any{"tasks": []any{}},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
raw, err := client.TranslationTasks(context.Background(), TranslationTaskListParams{
|
||||
Offset: &offset,
|
||||
Limit: &limit,
|
||||
TaskID: "textunit/v-current/Scenario",
|
||||
ReleaseID: "v-current",
|
||||
Destination: "MediaResources/GameData/Scenario.zip",
|
||||
PathPattern: "Scenario",
|
||||
ArchiveEntry: "ScenarioExcelTable.json",
|
||||
Status: "queued_offline",
|
||||
WorkerStatus: "failed",
|
||||
ParseStatus: "ok",
|
||||
Format: "json",
|
||||
HasReason: &hasReason,
|
||||
HasFailureReason: &hasFailureReason,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("TranslationTasks error: %v", err)
|
||||
}
|
||||
if !json.Valid(raw) {
|
||||
t.Fatalf("invalid raw JSON: %s", string(raw))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslationHandoffUsesRustMethod(t *testing.T) {
|
||||
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
|
||||
if req.Method != "translation.handoff" {
|
||||
t.Fatalf("method = %s", req.Method)
|
||||
}
|
||||
if string(req.Params) != "null" {
|
||||
t.Fatalf("params = %s, want null", req.Params)
|
||||
}
|
||||
return testResponse{
|
||||
Result: testEnvelope{
|
||||
OK: true,
|
||||
Status: "ok",
|
||||
RequestID: "req-test-translation-handoff",
|
||||
Data: map[string]any{"jobs": []any{}},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
raw, err := client.TranslationHandoff(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("TranslationHandoff error: %v", err)
|
||||
}
|
||||
if !json.Valid(raw) {
|
||||
t.Fatalf("invalid raw JSON: %s", string(raw))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslationTaskUpdateSendsWorkerParams(t *testing.T) {
|
||||
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
|
||||
if req.Method != "translation.task.update" {
|
||||
@@ -375,6 +463,75 @@ func TestTranslationTaskUpdateSendsWorkerParams(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslationWorkerRunSendsProviderConfig(t *testing.T) {
|
||||
var concurrency uint64 = 8
|
||||
var maxAttempts uint64 = 4
|
||||
var leaseSeconds uint64 = 60
|
||||
var retryBackoff uint64 = 0
|
||||
var maxTasks uint64 = 2
|
||||
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
|
||||
if req.Method != "translation.worker.run" {
|
||||
t.Fatalf("method = %s", req.Method)
|
||||
}
|
||||
var params TranslationWorkerRunParams
|
||||
if err := json.Unmarshal(req.Params, ¶ms); err != nil {
|
||||
t.Fatalf("decode params: %v", err)
|
||||
}
|
||||
if params.Provider != "mock" ||
|
||||
params.FixturePath != "/tmp/mock-provider.json" ||
|
||||
params.Concurrency == nil || *params.Concurrency != concurrency ||
|
||||
params.MaxAttempts == nil || *params.MaxAttempts != maxAttempts ||
|
||||
params.LeaseSeconds == nil || *params.LeaseSeconds != leaseSeconds ||
|
||||
params.RetryBackoffSeconds == nil || *params.RetryBackoffSeconds != retryBackoff ||
|
||||
params.MaxTasks == nil || *params.MaxTasks != maxTasks ||
|
||||
params.WorkerID != "dashboard-worker" {
|
||||
t.Fatalf("params = %#v", params)
|
||||
}
|
||||
return testResponse{
|
||||
Result: testEnvelope{
|
||||
OK: true,
|
||||
Status: "accepted",
|
||||
RequestID: "req-test-translation-worker",
|
||||
Data: map[string]any{
|
||||
"task_id": "task-worker-1",
|
||||
"kind": "translation.worker.run",
|
||||
"worker": map[string]any{
|
||||
"provider": "mock",
|
||||
"fixture_path": "/tmp/mock-provider.json",
|
||||
"concurrency": concurrency,
|
||||
"max_attempts": maxAttempts,
|
||||
"lease_seconds": leaseSeconds,
|
||||
"retry_backoff_seconds": retryBackoff,
|
||||
"max_tasks": maxTasks,
|
||||
"worker_id": "dashboard-worker",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
result, err := client.TranslationWorkerRun(context.Background(), TranslationWorkerRunParams{
|
||||
Provider: "mock",
|
||||
FixturePath: "/tmp/mock-provider.json",
|
||||
Concurrency: &concurrency,
|
||||
MaxAttempts: &maxAttempts,
|
||||
LeaseSeconds: &leaseSeconds,
|
||||
RetryBackoffSeconds: &retryBackoff,
|
||||
MaxTasks: &maxTasks,
|
||||
WorkerID: "dashboard-worker",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("TranslationWorkerRun error: %v", err)
|
||||
}
|
||||
if result.TaskID != "task-worker-1" ||
|
||||
result.Kind != "translation.worker.run" ||
|
||||
result.Worker.Concurrency != concurrency ||
|
||||
result.Worker.RetryBackoffSeconds != retryBackoff ||
|
||||
result.Worker.MaxTasks == nil || *result.Worker.MaxTasks != maxTasks {
|
||||
t.Fatalf("unexpected result: %#v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranslationProofreadUsesRustMethod(t *testing.T) {
|
||||
client := newTestClient(t, func(t *testing.T, req testRequest) testResponse {
|
||||
if req.Method != "translation.proofread" {
|
||||
|
||||
Reference in New Issue
Block a user