package main import ( "bytes" _ "embed" "encoding/json" "fmt" "os" "os/exec" "sort" "text/template" ) const statsPath = "/usr/local/bin/stats" //go:embed blog.tmpl.html var blogTmpl string type newsEntry struct { Title string // Title of entry Pubdate string // Human readable date Content string // HTML of entry } type User struct { Username string Default bool } type tildeData struct { News []newsEntry Users []User ActiveUsers []string `json:"active_users"` } type ByName []User func (n ByName) Len() int { return len(n) } func (n ByName) Swap(i, j int) { n[i], n[j] = n[j], n[i] } func (n ByName) Less(i, j int) bool { return n[i].Username < n[j].Username } func _main() error { data, err := stats() if err != nil { return err } type tmplData struct { News []newsEntry Lights string } td := &tmplData{ News: data.News, Lights: "", } sort.Sort(ByName(data.Users)) isActive := func(username string) bool { for _, u := range data.ActiveUsers { if u == username { return true } } return false } for _, u := range data.Users { if isActive(u.Username) { td.Lights += fmt.Sprintf("*", u.Username) } else if !u.Default { td.Lights += fmt.Sprintf("+", u.Username) } else { td.Lights += "." } } t, err := template.New("blog").Parse(blogTmpl) if err != nil { return fmt.Errorf("failed to parse the blog template: %w", err) } out := bytes.Buffer{} if err = t.Execute(&out, td); err != nil { return fmt.Errorf("failed to render blog template: %w", err) } fmt.Println(out.String()) return nil } func stats() (*tildeData, error) { sout := bytes.Buffer{} cmd := exec.Command(statsPath) cmd.Stdout = &sout err := cmd.Run() if err != nil { return nil, err } var data tildeData err = json.Unmarshal(sout.Bytes(), &data) if err != nil { return nil, err } return &data, nil } func main() { err := _main() if err != nil { fmt.Fprintf(os.Stderr, "error: %s\n", err) os.Exit(1) } }