github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-cluster/pkg/api/reporter.go (about) 1 // Copyright 2025 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package api 5 6 import ( 7 "context" 8 "net/url" 9 "strings" 10 "time" 11 ) 12 13 type ReporterClient struct { 14 baseURL string 15 } 16 17 func NewReporterClient(url string) *ReporterClient { 18 return &ReporterClient{baseURL: strings.TrimRight(url, "/")} 19 } 20 21 type NextReportResp struct { 22 Report *SessionReport `json:"report"` 23 } 24 25 const LKMLReporter = "lkml" 26 27 func (client ReporterClient) GetNextReport(ctx context.Context, reporter string) (*NextReportResp, error) { 28 v := url.Values{} 29 v.Add("reporter", reporter) 30 return postJSON[any, NextReportResp](ctx, client.baseURL+"/reports?"+v.Encode(), nil) 31 } 32 33 // ConfirmReport should be called to mark a report as sent. 34 func (client ReporterClient) ConfirmReport(ctx context.Context, id string) error { 35 _, err := postJSON[any, any](ctx, client.baseURL+"/reports/"+id+"/confirm", nil) 36 return err 37 } 38 39 type UpstreamReportReq struct { 40 User string `json:"user"` 41 } 42 43 func (client ReporterClient) UpstreamReport(ctx context.Context, id string, req *UpstreamReportReq) error { 44 _, err := postJSON[UpstreamReportReq, any](ctx, client.baseURL+"/reports/"+id+"/upstream", req) 45 return err 46 } 47 48 func (client ReporterClient) InvalidateReport(ctx context.Context, id string) error { 49 _, err := postJSON[any, any](ctx, client.baseURL+"/reports/"+id+"/invalidate", nil) 50 return err 51 } 52 53 type RecordReplyReq struct { 54 MessageID string `json:"message_id"` 55 ReportID string `json:"report_id"` 56 // If ReportID is not set, InReplyTo will help identify the original report. 57 InReplyTo string `json:"in_reply_to"` 58 Reporter string `json:"reporter"` 59 Time time.Time `json:"time"` 60 } 61 62 type RecordReplyResp struct { 63 New bool `json:"new"` 64 ReportID string `json:"report_id"` // or empty, if no original message was found 65 } 66 67 func (client ReporterClient) RecordReply(ctx context.Context, req *RecordReplyReq) (*RecordReplyResp, error) { 68 return postJSON[RecordReplyReq, RecordReplyResp](ctx, client.baseURL+"/reports/record_reply", req) 69 } 70 71 type LastReplyResp struct { 72 Time time.Time `json:"time"` 73 } 74 75 // Returns nil if no reply has ever been recorded. 76 func (client ReporterClient) LastReply(ctx context.Context, reporter string) (*LastReplyResp, error) { 77 v := url.Values{} 78 v.Add("reporter", reporter) 79 return postJSON[any, LastReplyResp](ctx, client.baseURL+"/reports/last_reply?"+v.Encode(), nil) 80 }