-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtasks.go
More file actions
110 lines (97 loc) · 3.43 KB
/
tasks.go
File metadata and controls
110 lines (97 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package csclient
import (
"context"
"fmt"
"time"
)
// GetTask retrieves detailed information about a specific task
func (c *Client) GetTask(ctx context.Context, taskID string) (*TaskDetailDto, error) {
var task TaskDetailDto
path := fmt.Sprintf("/api/v1/tasks/%s", taskID)
if err := c.doRequest(ctx, "GET", path, nil, &task, true); err != nil {
return nil, fmt.Errorf("failed to get task: %w", err)
}
return &task, nil
}
// ListTasks retrieves all tasks
func (c *Client) ListTasks(ctx context.Context) ([]TaskSummaryDto, error) {
var tasks []TaskSummaryDto
if err := c.doRequest(ctx, "GET", "/api/v1/tasks", nil, &tasks, true); err != nil {
return nil, fmt.Errorf("failed to list tasks: %w", err)
}
return tasks, nil
}
// GetBeaconTasksSummary retrieves task summaries for a specific beacon
func (c *Client) GetBeaconTasksSummary(ctx context.Context, bid string) ([]TaskSummaryDto, error) {
var tasks []TaskSummaryDto
path := fmt.Sprintf("/api/v1/beacons/%s/tasks/summary", bid)
if err := c.doRequest(ctx, "GET", path, nil, &tasks, true); err != nil {
return nil, fmt.Errorf("failed to get beacon tasks: %w", err)
}
return tasks, nil
}
// GetBeaconTasksDetail retrieves detailed tasks for a specific beacon
func (c *Client) GetBeaconTasksDetail(ctx context.Context, bid string) ([]TaskDetailDto, error) {
var tasks []TaskDetailDto
path := fmt.Sprintf("/api/v1/beacons/%s/tasks/detail", bid)
if err := c.doRequest(ctx, "GET", path, nil, &tasks, true); err != nil {
return nil, fmt.Errorf("failed to get beacon task details: %w", err)
}
return tasks, nil
}
// WaitForTaskAck polls a task briefly to see if it completes quickly.
// If the task transitions to a terminal state (COMPLETED/OUTPUT_RECEIVED/FAILED) within
// the timeout, it returns that result. If the task stays IN_PROGRESS after the timeout,
// it returns the last known task state with a nil error (fire-and-forget acknowledgment).
// This is designed for commands that may never produce output (e.g., mkdir, cd, sleep, etc.).
func (c *Client) WaitForTaskAck(ctx context.Context, taskID string, timeout time.Duration) (*TaskDetailDto, error) {
deadline := time.Now().Add(timeout)
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-ticker.C:
task, err := c.GetTask(ctx, taskID)
if err != nil {
return nil, err
}
// If terminal state, return immediately
if task.TaskStatus == TaskStatusCompleted ||
task.TaskStatus == TaskStatusOutputReceived ||
task.TaskStatus == TaskStatusFailed {
return task, nil
}
// If past deadline and still IN_PROGRESS, treat as acknowledged
if time.Now().After(deadline) {
return task, nil
}
}
}
}
// WaitForTaskCompletion polls a task until it completes or times out
func (c *Client) WaitForTaskCompletion(ctx context.Context, taskID string, timeout time.Duration) (*TaskDetailDto, error) {
deadline := time.Now().Add(timeout)
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-ticker.C:
if time.Now().After(deadline) {
return nil, fmt.Errorf("timeout waiting for task completion")
}
task, err := c.GetTask(ctx, taskID)
if err != nil {
return nil, err
}
if task.TaskStatus == TaskStatusCompleted ||
task.TaskStatus == TaskStatusOutputReceived ||
task.TaskStatus == TaskStatusFailed {
return task, nil
}
}
}
}