parent
2282efa3e9
commit
9142be3688
|
@ -8,8 +8,10 @@ import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
"code.jhot.me/jhot/hats/internal/nats"
|
"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/config"
|
||||||
"code.jhot.me/jhot/hats/pkg/homeassistant"
|
"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/middleware"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/render"
|
"github.com/go-chi/render"
|
||||||
|
@ -48,6 +50,8 @@ func Listen(parentLogger *slog.Logger) {
|
||||||
router.Post("/api/schedule/{scheduleName}", createScheduleHandler)
|
router.Post("/api/schedule/{scheduleName}", createScheduleHandler)
|
||||||
router.Delete("/api/schedule/{scheduleName}", deleteScheduleHandler)
|
router.Delete("/api/schedule/{scheduleName}", deleteScheduleHandler)
|
||||||
|
|
||||||
|
router.Post("/api/ntfy", postNtfyHandler)
|
||||||
|
|
||||||
server = http.Server{
|
server = http.Server{
|
||||||
Addr: ":8888",
|
Addr: ":8888",
|
||||||
Handler: router,
|
Handler: router,
|
||||||
|
@ -244,3 +248,20 @@ func deleteScheduleHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
schedule.Cancel()
|
schedule.Cancel()
|
||||||
render.PlainText(w, r, "OK")
|
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")
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
3
main.go
3
main.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"code.jhot.me/jhot/hats/internal/api"
|
"code.jhot.me/jhot/hats/internal/api"
|
||||||
"code.jhot.me/jhot/hats/internal/homeassistant"
|
"code.jhot.me/jhot/hats/internal/homeassistant"
|
||||||
"code.jhot.me/jhot/hats/internal/nats"
|
"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/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,6 +54,8 @@ func main() {
|
||||||
}
|
}
|
||||||
defer homeassistant.CloseSubscription()
|
defer homeassistant.CloseSubscription()
|
||||||
|
|
||||||
|
ntfy.InitClient(cfg)
|
||||||
|
|
||||||
api.Listen(logger)
|
api.Listen(logger)
|
||||||
defer api.Close()
|
defer api.Close()
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"code.jhot.me/jhot/hats/internal/api"
|
"code.jhot.me/jhot/hats/internal/api"
|
||||||
ha "code.jhot.me/jhot/hats/pkg/homeassistant"
|
ha "code.jhot.me/jhot/hats/pkg/homeassistant"
|
||||||
|
"code.jhot.me/jhot/hats/pkg/ntfy"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -178,3 +179,11 @@ func (c *HatsClient) DeleteSchedule(name string) error {
|
||||||
}
|
}
|
||||||
return err
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,9 @@ type HatsConfig struct {
|
||||||
HatsHost string
|
HatsHost string
|
||||||
HatsPort string
|
HatsPort string
|
||||||
HatsSecure bool
|
HatsSecure bool
|
||||||
|
|
||||||
|
NtfyHost string
|
||||||
|
NtfyToken string
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromEnvironment() *HatsConfig {
|
func FromEnvironment() *HatsConfig {
|
||||||
|
@ -39,6 +42,8 @@ func FromEnvironment() *HatsConfig {
|
||||||
NatsClientName: util.GetEnvWithDefault("NATS_CLIENT_NAME", "hats"),
|
NatsClientName: util.GetEnvWithDefault("NATS_CLIENT_NAME", "hats"),
|
||||||
HatsHost: util.GetEnvWithDefault("HATS_HOST", "hats"),
|
HatsHost: util.GetEnvWithDefault("HATS_HOST", "hats"),
|
||||||
HatsPort: util.GetEnvWithDefault("HATS_PORT", "8888"),
|
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"))
|
config.HomeAssistantSecure, _ = strconv.ParseBool(util.GetEnvWithDefault("HASS_SECURE", "false"))
|
||||||
|
|
|
@ -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"`
|
||||||
|
}
|
Loading…
Reference in New Issue