add ntfy integration

This commit is contained in:
Elizabeth Hunt 2025-01-05 16:36:51 -08:00
parent 687caaa787
commit 040994898b
Signed by: simponic
GPG Key ID: 2909B9A7FF6213EE
6 changed files with 142 additions and 5 deletions

View File

@ -12,9 +12,9 @@ prompt_with_default() {
DNS_ENDPOINT=$(prompt_with_default "Enter DNS endpoint" "https://hatecomputers.club/dns")
BIND_FILE=$(prompt_with_default "Enter bind file path" "roles/nameservers/templates/db.simponic.xyz.j2")
SERVICE_TITLE=$(prompt_with_default "Enter service title" "phoneof simponic.")
SERVICE=$(prompt_with_default "Enter service name" "phoneof")
SERVICE_PORT=$(prompt_with_default "Enter service port" "6363")
SERVICE_TITLE=$(prompt_with_default "Enter service title" "whois simponic.")
SERVICE=$(prompt_with_default "Enter service name" "whois")
SERVICE_PORT=$(prompt_with_default "Enter service port" "8466")
SERVICE_REPO=$(prompt_with_default "Enter service repository URL" "git.simponic.xyz/simponic/$SERVICE")
SERVICE_ORIGIN=$(prompt_with_default "Enter service origin URL" "git@git.simponic.xyz:simponic/$SERVICE")
INTERNAL=$(prompt_with_default "Is the service internal? (yes/no)" "no")

View File

@ -10,4 +10,4 @@ RUN go build -o /app/{{ service }}
EXPOSE 8080
CMD ["/app/{{ service }}", "--server", "--migrate", "--port", "8080", "--template-path", "/app/templates", "--database-path", "/app/db/{{ service }}.db", "--static-path", "/app/static", "--scheduler"]
CMD ["/app/{{ service }}", "--server", "--migrate", "--port", "8080", "--template-path", "/app/templates", "--database-path", "/app/db/{{ service }}.db", "--static-path", "/app/static", "--scheduler", "--ntfy-topics", "whois", "--ntfy-endpoint", "https://ntfy.simponic.hatecomputers.club"]

View File

@ -4,6 +4,7 @@ import (
"flag"
"fmt"
"os"
"strings"
"sync"
)
@ -15,6 +16,10 @@ type Arguments struct {
Migrate bool
Scheduler bool
NtfyEndpoint string
NtfyTopics []string
NtfyListener bool
Port int
Server bool
}
@ -56,6 +61,10 @@ func GetArgs() (*Arguments, error) {
templatePath := flag.String("template-path", "./templates", "Path to the template directory")
staticPath := flag.String("static-path", "./static", "Path to the static directory")
ntfyEndpoint := flag.String("ntfy-endpoint", "https://ntfy.simponic.hatecomputers.club", "NTFY Endpoint")
ntfyTopics := flag.String("ntfy-topics", "testtopic", "Comma-separated NTFY Topics")
ntfyListener := flag.Bool("ntfy-listener", false, "Listen to NTFY Topic and propagate messages")
scheduler := flag.Bool("scheduler", false, "Run scheduled jobs via cron")
migrate := flag.Bool("migrate", false, "Run the migrations")
@ -72,6 +81,9 @@ func GetArgs() (*Arguments, error) {
Server: *server,
Migrate: *migrate,
Scheduler: *scheduler,
NtfyEndpoint: *ntfyEndpoint,
NtfyTopics: strings.Split(*ntfyTopics, ","),
NtfyListener: *ntfyListener,
}
err := validateArgs(args)
if err != nil {

View File

@ -9,6 +9,7 @@ import (
"{{ service_repo }}/args"
"{{ service_repo }}/database"
"{{ service_repo }}/scheduler"
"{{ service_repo }}/ntfy"
"github.com/joho/godotenv"
)
@ -36,6 +37,18 @@ func main() {
log.Println("database migrated successfully")
}
if argv.NtfyListener {
ntfy := ntfy.MakeNtfyWatcher(argv.NtfyEndpoint, argv.NtfyTopics)
notifications := ntfy.Watch()
go func() {
for notification := range notifications {
message := notification.Message
log.Println("got message", message)
}
}()
}
if argv.Scheduler {
go func() {
scheduler.StartScheduler(dbConn, argv)
@ -57,7 +70,7 @@ func main() {
}()
}
if argv.Server || argv.Scheduler {
if argv.Server || argv.Scheduler || argv.NtfyListener {
select {} // block forever
}
}

View File

@ -0,0 +1,16 @@
package ntfy
import (
"net/http"
"strings"
)
func SendMessage(message string, endpoint string, topics []string) error {
for _, topic := range topics {
_, err := http.Post(endpoint+"/"+topic, "text/plain", strings.NewReader(message))
if err != nil {
return err
}
}
return nil
}

96
template/ntfy/watcher.go Normal file
View File

@ -0,0 +1,96 @@
package ntfy
import (
"bufio"
"encoding/json"
"log"
"net/http"
"net/url"
"path"
"time"
)
type Message struct {
Id string `json:"id"`
Time int `json:"time"`
Message string `json:"message"`
Event string `json:"event"`
}
type NtfyWatcher struct {
Endpoint string
Topics []string
}
func (w *NtfyWatcher) Watch() chan Message {
notifications := make(chan Message)
for _, topic := range w.Topics {
log.Println("subscribing to topic:", topic)
go func() {
retryCount := 5
retryTime := 5 * time.Second
retries := retryCount
sleepAndDecrementRetry := func() {
log.Println("waiting 5 seconds before reconnecting. retries left:", retries, "topic:", topic, "endpoint:", w.Endpoint)
time.Sleep(retryTime)
retries--
}
for true {
if retries == 0 {
log.Fatal("too many retries, exiting")
}
endpoint, _ := url.JoinPath(w.Endpoint, path.Join(topic, "json"))
resp, err := http.Get(endpoint)
if err != nil {
log.Println("error connecting to endpoint:", err)
sleepAndDecrementRetry()
continue
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
bytes := scanner.Bytes()
var msg Message
err := json.Unmarshal(bytes, &msg)
if err != nil {
log.Println("could not unmarshal message:", err)
continue
}
if msg.Event == "keepalive" {
log.Println("received keepalive message")
continue
}
if msg.Event != "message" {
log.Println("received unknown event:", msg.Event)
continue
}
log.Println("received notification:", msg)
notifications <- msg
retries = retryCount // reset retries
}
if err := scanner.Err(); err != nil {
log.Println("error reading response body:", err)
sleepAndDecrementRetry()
}
}
}()
}
return notifications
}
func MakeNtfyWatcher(endpoint string, topics []string) *NtfyWatcher {
return &NtfyWatcher{
Endpoint: endpoint,
Topics: topics,
}
}