fix api object

This commit is contained in:
aliamerj
2025-08-27 12:46:20 +03:00
parent d1aec58108
commit 556c4c7777
6 changed files with 672 additions and 203 deletions
@@ -98,10 +98,11 @@ func (h *Handler) ListJobs(w http.ResponseWriter, r *http.Request) {
return
}
respBody := make([]*api.Job, 0, len(jobs))
respBody := make([]*api.JobResponse, 0, len(jobs))
for _, job := range jobs {
resp, err := toSingleJobResponse(job)
if err != nil {
log.WithContext(ctx).Errorf("failed xxx: %v", err)
util.WriteError(ctx, err, w)
return
}
@@ -518,27 +519,25 @@ func toPeerListItemResponse(peer *nbpeer.Peer, groupsInfo []api.GroupMinimum, dn
}
}
func toSingleJobResponse(job *types.Job) (*api.Job, error) {
var parameters map[string]any
if err := job.DecodeParameters(&parameters); err != nil {
func toSingleJobResponse(job *types.Job) (*api.JobResponse, error) {
var workloadResponse api.WorkloadResponse
if err := job.BuildWorkloadResponse(&workloadResponse); err != nil {
return nil, err
}
return &api.Job{
var failed *string
if job.FailedReason != "" {
failed = &job.FailedReason
}
return &api.JobResponse{
Id: job.ID,
Status: (*api.JobStatus)(&job.Status),
CompletedAt: job.CompletedAt,
CreatedAt: job.CreatedAt,
FailedReason: &job.FailedReason,
CompletedAt: job.CompletedAt,
TriggeredBy: job.TriggeredBy,
Workload: struct {
Parameters *map[string]any "json:\"parameters,omitempty\""
Result *string "json:\"result,omitempty\""
Type *api.JobWorkloadType "json:\"type,omitempty\""
}{
Type: (*api.JobWorkloadType)(&job.Type),
Parameters: &parameters,
Result: &job.Result,
},
Status: api.JobResponseStatus(job.Status),
FailedReason: failed,
Workload: workloadResponse,
}, nil
}
+78 -73
View File
@@ -21,6 +21,7 @@ type JobType string
const (
JobTypeBundle JobType = "bundle"
JobTypeOther JobType = "other"
// add more job types here
)
@@ -51,109 +52,113 @@ type Job struct {
FailedReason string
// Result can contain job output (JSON, URL, etc.)
Result string
Result json.RawMessage `gorm:"type:json"`
// Parameters is a JSON blob storing job configuration (untyped)
Parameters json.RawMessage `gorm:"type:json"`
}
// JobParametersBundle represents parameters for bundle/debug jobs
type JobParametersBundle struct {
BundleFor bool `json:"bundle_for"`
BundleForTime int `json:"bundle_for_time"` // minutes
LogFileCount int `json:"log_file_count"`
Anonymize bool `json:"anonymize"`
}
// NewJob creates a new job with default fields and validation
func NewJob(triggeredBy, accountID, peerID string, req *api.JobRequest) (*Job, error) {
if req.Workload.Type == nil {
return nil, fmt.Errorf("Job type required")
if req == nil {
return nil, fmt.Errorf("job request cannot be nil")
}
if req.Workload.Parameters == nil {
return nil, fmt.Errorf("Job parameters required")
// Determine job type
jobTypeStr, err := req.Workload.Discriminator()
if err != nil {
return nil, fmt.Errorf("could not determine job type: %w", err)
}
jobType := JobType(jobTypeStr)
var params []byte
switch jobType {
case JobTypeBundle:
bundle, err := req.Workload.AsBundleWorkloadRequest()
if err != nil {
return nil, fmt.Errorf("invalid parameters for bundle job: %w", err)
}
if err := validateDebugBundleJobParams(bundle); err != nil {
return nil, err
}
params, err = json.Marshal(bundle.Parameters)
if err != nil {
return nil, fmt.Errorf("failed to marshal workload parameters: %w", err)
}
default:
return nil, fmt.Errorf("unsupported job type: %s", jobType)
}
job := &Job{
return &Job{
ID: uuid.New().String(),
TriggeredBy: triggeredBy,
PeerID: peerID,
AccountID: accountID,
Type: JobType(*req.Workload.Type),
Type: jobType,
Status: JobStatusPending,
Parameters: params,
CreatedAt: time.Now().UTC(),
}
// Encode parameters
if err := job.encodeParameters(*req.Workload.Parameters); err != nil {
return nil, fmt.Errorf("failed to encode job parameters: %w", err)
}
// Validate job
if err := job.validateJobRequest(); err != nil {
return nil, err
}
return job, nil
Result: []byte("{}"),
}, nil
}
// DecodeParameters decodes raw parameters into a target struct
func (j *Job) DecodeParameters(target any) error {
if len(j.Parameters) == 0 {
return nil
}
return json.Unmarshal(j.Parameters, target)
}
// EncodeParameters replaces raw parameters with marshaled JSON
func (j *Job) encodeParameters(params map[string]any) error {
if params == nil {
return fmt.Errorf("parameters cannot be empty")
}
data, err := json.Marshal(params)
if err != nil {
return err
}
j.Parameters = data
return nil
}
func (j *Job) validateJobRequest() error {
if j == nil {
return fmt.Errorf("job cannot be nil")
}
if len(j.Parameters) == 0 {
return fmt.Errorf("job parameters must be provided")
}
func (j *Job) BuildWorkloadResponse(wl *api.WorkloadResponse) error {
switch j.Type {
case JobTypeBundle:
if err := j.validateDebugBundleJobParams(); err != nil {
return err
}
return j.buildBundleWorkload(wl)
case JobTypeOther:
return j.buildOtherWorkload(wl)
default:
return fmt.Errorf("unsupported job type: %s", j.Type)
return fmt.Errorf("unknown job type: %v", j.Type)
}
return nil
}
func (j *Job) validateDebugBundleJobParams() error {
var params JobParametersBundle
if err := j.DecodeParameters(&params); err != nil {
func (j *Job) buildBundleWorkload(wl *api.WorkloadResponse) error {
var p api.BundleParameters
if err := json.Unmarshal(j.Parameters, &p); err != nil {
return fmt.Errorf("invalid parameters for bundle job: %w", err)
}
// validate bundle_for_time <= 5 minutes
if params.BundleForTime < 0 || params.BundleForTime > 5 {
return fmt.Errorf("bundle_for_time must be between 0 and 5, got %d", params.BundleForTime)
var r api.BundleResult
if err := json.Unmarshal(j.Result, &r); err != nil {
return fmt.Errorf("invalid result for bundle job: %w", err)
}
return wl.FromBundleWorkloadResponse(api.BundleWorkloadResponse{
Type: api.WorkloadTypeBundle,
Parameters: p,
Result: r,
})
}
func (j *Job) buildOtherWorkload(wl *api.WorkloadResponse) error {
var p api.OtherParameters
if err := json.Unmarshal(j.Parameters, &p); err != nil {
return fmt.Errorf("invalid parameters for bundle job: %w", err)
}
var r api.OtherResult
if err := json.Unmarshal(j.Result, &r); err != nil {
return fmt.Errorf("invalid result for bundle job: %w", err)
}
return wl.FromOtherWorkloadResponse(api.OtherWorkloadResponse{
Type: api.WorkloadTypeOther,
Parameters: p,
Result: r,
})
}
func validateDebugBundleJobParams(bundle api.BundleWorkloadRequest) error {
// validate bundle_for_time <= 5 minutes
if bundle.Parameters.BundleForTime < 0 || bundle.Parameters.BundleForTime > 5 {
return fmt.Errorf("bundle_for_time must be between 0 and 5, got %d", bundle.Parameters.BundleForTime)
}
// validate log-file-count ≥ 1 and ≤ 1000
if params.LogFileCount < 1 || params.LogFileCount > 1000 {
return fmt.Errorf("log-file-count must be between 1 and 1000, got %d", params.LogFileCount)
if bundle.Parameters.LogFileCount < 1 || bundle.Parameters.LogFileCount > 1000 {
return fmt.Errorf("log-file-count must be between 1 and 1000, got %d", bundle.Parameters.LogFileCount)
}
return nil
}