package main import ( "fmt" "log" "net/http" "strings" "time" ) type Ntfy struct { cfg *NtfyConfig } // Publish posts a message to the configured ntfy server. Errors are // logged, never fatal — notifications must not take the server down. func (n *Ntfy) Publish(topic, title, message, priority string) error { if !n.cfg.Enabled || n.cfg.Server == "" { return nil } if topic == "" { topic = n.cfg.Topic } url := strings.TrimRight(n.cfg.Server, "/") + "/" + topic req, err := http.NewRequest("POST", url, strings.NewReader(message)) if err != nil { return err } if title != "" { req.Header.Set("X-Title", title) } if priority != "" { req.Header.Set("X-Priority", priority) } client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { log.Printf("ntfy: %v", err) return err } defer resp.Body.Close() if resp.StatusCode >= 300 { err := fmt.Errorf("ntfy: %s -> %s", topic, resp.Status) log.Print(err) return err } return nil } func (n *Ntfy) Question(session string, q *Question) { if !n.cfg.NotifyOnQuestion { return } var b strings.Builder b.WriteString(q.Text) for i, o := range q.Options { b.WriteString("\n") if o.Num > 0 { fmt.Fprintf(&b, "%d. %s", o.Num, o.Label) } else { fmt.Fprintf(&b, "- %s", o.Label) } if i == q.Selected { b.WriteString(" ←") } } n.Publish("", "helm: "+session+" väntar på svar", b.String(), "high") }