1
0
Fork 0

ntfy client

main v0.8.0
Jordan Hotmann 2023-11-08 16:12:04 -07:00
parent 2282efa3e9
commit 9142be3688
No known key found for this signature in database
GPG Key ID: 01B504170C2A2EA3
6 changed files with 92 additions and 0 deletions

View File

@ -8,8 +8,10 @@ import (
"log/slog"
"code.jhot.me/jhot/hats/internal/nats"
"code.jhot.me/jhot/hats/internal/ntfy"
"code.jhot.me/jhot/hats/pkg/config"
"code.jhot.me/jhot/hats/pkg/homeassistant"
ntfyPkg "code.jhot.me/jhot/hats/pkg/ntfy"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
@ -48,6 +50,8 @@ func Listen(parentLogger *slog.Logger) {
router.Post("/api/schedule/{scheduleName}", createScheduleHandler)
router.Delete("/api/schedule/{scheduleName}", deleteScheduleHandler)
router.Post("/api/ntfy", postNtfyHandler)
server = http.Server{
Addr: ":8888",
Handler: router,
@ -244,3 +248,20 @@ func deleteScheduleHandler(w http.ResponseWriter, r *http.Request) {
schedule.Cancel()
render.PlainText(w, r, "OK")
}
// NTFY
func postNtfyHandler(w http.ResponseWriter, r *http.Request) {
data := &ntfyPkg.Message{}
if err := render.DecodeJSON(r.Body, data); err != nil {
http.Error(w, "Unable to parse message data", http.StatusNotAcceptable)
return
}
if err := ntfy.Send(*data); err != nil {
http.Error(w, "Unable to send message", http.StatusBadRequest)
return
}
render.PlainText(w, r, "OK")
}

28
internal/ntfy/client.go Normal file
View File

@ -0,0 +1,28 @@
package ntfy
import (
"fmt"
"code.jhot.me/jhot/hats/pkg/config"
ntfyPkg "code.jhot.me/jhot/hats/pkg/ntfy"
"github.com/go-resty/resty/v2"
)
var (
ntfyClient *resty.Client
)
func InitClient(cfg *config.HatsConfig) {
ntfyClient = resty.New().SetBaseURL(cfg.NtfyHost)
if cfg.NtfyToken != "" {
ntfyClient.SetHeader("Authorization", fmt.Sprintf("Bearer %s", cfg.NtfyToken))
}
}
func Send(data ntfyPkg.Message) error {
resp, err := ntfyClient.R().SetBody(data).Post("")
if err == nil && !resp.IsSuccess() {
err = fmt.Errorf("%d status code received: %s", resp.StatusCode(), resp.String())
}
return err
}

View File

@ -9,6 +9,7 @@ import (
"code.jhot.me/jhot/hats/internal/api"
"code.jhot.me/jhot/hats/internal/homeassistant"
"code.jhot.me/jhot/hats/internal/nats"
"code.jhot.me/jhot/hats/internal/ntfy"
"code.jhot.me/jhot/hats/pkg/config"
)
@ -53,6 +54,8 @@ func main() {
}
defer homeassistant.CloseSubscription()
ntfy.InitClient(cfg)
api.Listen(logger)
defer api.Close()

View File

@ -5,6 +5,7 @@ import (
"code.jhot.me/jhot/hats/internal/api"
ha "code.jhot.me/jhot/hats/pkg/homeassistant"
"code.jhot.me/jhot/hats/pkg/ntfy"
"github.com/go-resty/resty/v2"
)
@ -178,3 +179,11 @@ func (c *HatsClient) DeleteSchedule(name string) error {
}
return err
}
func (c *HatsClient) SendNtfyMessage(data ntfy.Message) error {
resp, err := c.client.R().SetBody(data).Post("api/ntfy")
if err == nil && !resp.IsSuccess() {
err = fmt.Errorf("%d status code received: %s", resp.StatusCode(), resp.String())
}
return err
}

View File

@ -25,6 +25,9 @@ type HatsConfig struct {
HatsHost string
HatsPort string
HatsSecure bool
NtfyHost string
NtfyToken string
}
func FromEnvironment() *HatsConfig {
@ -39,6 +42,8 @@ func FromEnvironment() *HatsConfig {
NatsClientName: util.GetEnvWithDefault("NATS_CLIENT_NAME", "hats"),
HatsHost: util.GetEnvWithDefault("HATS_HOST", "hats"),
HatsPort: util.GetEnvWithDefault("HATS_PORT", "8888"),
NtfyHost: util.GetEnvWithDefault("NTFY_HOST", "https://ntfy.sh"),
NtfyToken: util.GetEnvWithDefault("NTFY_TOKEN", ""),
}
config.HomeAssistantSecure, _ = strconv.ParseBool(util.GetEnvWithDefault("HASS_SECURE", "false"))

26
pkg/ntfy/structs.go Normal file
View File

@ -0,0 +1,26 @@
package ntfy
type Message struct {
Topic string `json:"topic"` // Required
Message string `json:"message,omitempty"`
Markdown bool `json:"markdown"`
Title string `json:"title"` // Required
Tags []string `json:"tags,omitempty"` // https://docs.ntfy.sh/publish/#tags-emojis
Priority int `json:"priority,omitempty"` // 1-5
Delay string `json:"delay,omitempty"` // Duration i.e. "5s"
Icon string `json:"icon,omitempty"` // URL
Attach string `json:"attach,omitempty"` // URL
Filename string `json:"filename,omitempty"`
Click string `json:"click,omitempty"` // URL
Actions []struct {
Action string `json:"action"` // "view", "broadcast", or "http"
Label string `json:"label"`
URL string `json:"url,omitempty"`
Method string `json:"method,omitempty"`
Headers string `json:"headers,omitempty"`
Body string `json:"body,omitempty"`
Intent string `json:"intent,omitempty"`
Clear bool `json:"clear,omitempty"`
Extras map[string]string `json:"extras,omitempty"`
} `json:"actions,omitempty"`
}