157 lines
3.3 KiB
Go
157 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type LogEntry struct {
|
|
Timestamp string `json:"timestamp"`
|
|
Version int `json:"version"`
|
|
Type string `json:"type"`
|
|
Tailnet string `json:"tailnet"`
|
|
Message string `json:"message"`
|
|
Data Data `json:"data"`
|
|
}
|
|
type Data struct {
|
|
NodeID string `json:"nodeID,omitempty"`
|
|
DeviceName string `json:"deviceName,omitempty"`
|
|
ManagedBy string `json:"managedBy,omitempty"`
|
|
Actor string `json:"actor,omitempty"`
|
|
URL string `json:"url,omitempty"`
|
|
}
|
|
|
|
type TSLogs []LogEntry
|
|
|
|
// Push represents a message sent to the Pushover api
|
|
type Push struct {
|
|
Token string `json:"token"`
|
|
User string `json:"user"`
|
|
Message string `json:"message"`
|
|
Device string `json:"device,omitempty"`
|
|
Title string `json:"title"`
|
|
URL string `json:"url"`
|
|
URLTitle string `json:"url_title,omitempty"`
|
|
Priority int `json:"priority,omitempty"`
|
|
Sound string `json:"sound,omitempty"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
}
|
|
|
|
// PushResponse is a response from the Pushover api
|
|
type PushResponse struct {
|
|
Status int `json:"status,omitempty"`
|
|
Request string `json:"request,omitempty"`
|
|
User string `json:"user,omitempty"`
|
|
Errors []string `json:"errors,omitempty"`
|
|
}
|
|
|
|
type apiHandler struct{}
|
|
|
|
var (
|
|
appToken = os.Getenv("PUSHOVER_TOKEN")
|
|
userToken = os.Getenv("PUSHOVER_USER")
|
|
potsToken = os.Getenv("POTS_TOKEN")
|
|
client = *http.DefaultClient
|
|
)
|
|
|
|
func sendPush(p *Push) error {
|
|
buf := new(bytes.Buffer)
|
|
|
|
if err := json.NewEncoder(buf).Encode(p); err != nil {
|
|
return err
|
|
}
|
|
|
|
req, err := http.NewRequest("POST", "https://api.pushover.net/1/messages.json", buf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
var resBody PushResponse
|
|
if err = json.NewDecoder(res.Body).Decode(&resBody); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(resBody.Errors) > 0 {
|
|
return fmt.Errorf("%s", strings.Join(resBody.Errors, ", "))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (apiHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
if req.Method != "POST" {
|
|
http.NotFound(w, req)
|
|
return
|
|
}
|
|
|
|
token := path.Base(req.URL.Path)
|
|
if token != potsToken {
|
|
http.NotFound(w, req)
|
|
return
|
|
}
|
|
|
|
decoder := json.NewDecoder(req.Body)
|
|
var tsLogs TSLogs
|
|
err := decoder.Decode(&tsLogs)
|
|
if err != nil {
|
|
http.Error(w, "invalid data", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
for _, t := range tsLogs {
|
|
var push = &Push{
|
|
Token: appToken,
|
|
User: userToken,
|
|
Timestamp: time.Now(),
|
|
Title: t.Message,
|
|
Message: t.Type,
|
|
URL: t.Data.URL,
|
|
}
|
|
err := sendPush(push)
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
port := flag.Int("port", 8888, "port to listen on")
|
|
ip := flag.String("ip", "127.0.0.1", "ip to listen on")
|
|
flag.Parse()
|
|
|
|
mux := http.NewServeMux()
|
|
mux.Handle("/api/", apiHandler{})
|
|
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
|
log.Println(req.URL.Path)
|
|
if req.URL.Path != "/" {
|
|
http.NotFound(w, req)
|
|
return
|
|
}
|
|
fmt.Fprintf(w, `<a href="https://suah.dev/pots">suah.dev/pots</a>`)
|
|
})
|
|
|
|
s := &http.Server{
|
|
Addr: fmt.Sprintf("%s:%d", *ip, *port),
|
|
Handler: mux,
|
|
}
|
|
|
|
log.Fatal(s.ListenAndServe())
|
|
}
|