Cybersecurity-Projects/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/digest.go

102 lines
2.3 KiB
Go

// ©AngelaMos | 2026
// digest.go
package main
import (
"fmt"
"os"
"time"
"github.com/spf13/cobra"
"github.com/CarterPerez-dev/nadezhda/internal/export"
"github.com/CarterPerez-dev/nadezhda/internal/rank"
"github.com/CarterPerez-dev/nadezhda/internal/store"
)
const (
defaultDigestTop = 20
formatMarkdown = "md"
formatJSON = "json"
outFilePerm = 0o644
)
var (
digestTop int
digestSince string
digestFormat string
digestOut string
)
var digestCmd = &cobra.Command{
Use: "digest",
Short: "Render a ranked digest of story clusters to Markdown or JSON",
RunE: runDigest,
}
func init() {
digestCmd.Flags().IntVar(&digestTop, "top", defaultDigestTop, "show the top N ranked clusters")
digestCmd.Flags().StringVar(&digestSince, "since", "", "only clusters active within this window (e.g. 24h, 168h)")
digestCmd.Flags().StringVar(&digestFormat, "format", formatMarkdown, "output format: md or json")
digestCmd.Flags().StringVar(&digestOut, "out", "", "write to this file instead of stdout")
rootCmd.AddCommand(digestCmd)
}
func runDigest(cmd *cobra.Command, args []string) error {
cfg, err := loadConfig()
if err != nil {
return err
}
if digestFormat != formatMarkdown && digestFormat != formatJSON {
return fmt.Errorf("invalid --format %q: want md or json", digestFormat)
}
var since int64
now := time.Now()
if digestSince != "" {
d, err := time.ParseDuration(digestSince)
if err != nil {
return fmt.Errorf("invalid --since %q: %w", digestSince, err)
}
since = now.Add(-d).Unix()
}
st, err := store.Open(cfg.DBPath)
if err != nil {
return err
}
defer st.Close()
clusters, err := st.DigestClusters(since)
if err != nil {
return err
}
scored := rank.Rank(clusters, cfg.Rank, cfg.Watchlist, now)
shown := len(scored)
if digestTop > 0 && digestTop < shown {
shown = digestTop
}
var rendered string
if digestFormat == formatJSON {
rendered, err = export.JSON(scored, digestTop)
if err != nil {
return err
}
} else {
rendered = export.Markdown(scored, digestTop)
}
if digestOut != "" {
if err := os.WriteFile(digestOut, []byte(rendered), outFilePerm); err != nil {
return fmt.Errorf("write digest to %s: %w", digestOut, err)
}
fmt.Fprintf(cmd.OutOrStdout(), "wrote %d clusters to %s\n", shown, digestOut)
return nil
}
fmt.Fprint(cmd.OutOrStdout(), rendered)
return nil
}