package main import ( "context" "encoding/json" "fmt" "html/template" "io" "log" "net/http" "strings" "sync" "time" ) type Data struct { mux sync.RWMutex url string token string num int projectId int filterId int minimumVersion string tmpl *template.Template ctx context.Context Issues Issues Timestamp time.Time Lasterror error } func NewData(ctx context.Context, url, token string, num int) *Data { data := &Data{ url: url, token: token, ctx: ctx, num: num, } fm := map[string]any{ "shorten": func(max int, s string) string { if len(s) <= max { return s } return s[:max] + "⋯" }, } data.tmpl = template.Must(template.New("index").Funcs(fm).ParseFS(content, "*.tmpl")) return data } func (d *Data) update() { url := fmt.Sprintf("%s?project_id=%dfilter_id=%d&page_size=%d", d.url, d.projectId, d.filterId, d.num) req, e := http.NewRequestWithContext(d.ctx, "GET", url, nil) if nil != e { d.mux.Lock() defer d.mux.Unlock() d.Lasterror = e return } req.Header.Add("Authorization", d.token) r, e := http.DefaultClient.Do(req) if nil != e { d.mux.Lock() defer d.mux.Unlock() d.Lasterror = e return } else if 200 != r.StatusCode { d.mux.Lock() defer d.mux.Unlock() d.Lasterror = fmt.Errorf("Got unexpected status %s\n", r.Status) return } iss := struct{ Issues Issues }{} e = json.NewDecoder(r.Body).Decode(&iss) d.mux.Lock() defer d.mux.Unlock() d.Lasterror = e if nil != e { return } d.Timestamp = time.Now() // Filter issues with old target versions out var issues = Issues{} for _, issue := range iss.Issues { if strings.Compare(d.minimumVersion, issue.TargetVersion.Name) < 0 { issues = append(issues, issue) } } d.Issues = issues } func (d *Data) printJSON(w io.Writer) { d.mux.RLock() defer d.mux.RUnlock() if nil == d.Issues { fmt.Fprintln(w, "{}") return } enc := json.NewEncoder(w) enc.SetIndent("", " ") enc.Encode(d.Issues) } func (d *Data) printTemplate(w io.Writer, name string) { d.mux.RLock() defer d.mux.RUnlock() e := d.tmpl.ExecuteTemplate(w, name, d) if nil != e { log.Println(e) } }