diff --git a/garmin.go b/garmin.go new file mode 100644 index 0000000..0ad4534 --- /dev/null +++ b/garmin.go @@ -0,0 +1,87 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "time" +) + +type garminClient struct { + c *http.Client + apiKey string +} + +type garminMessageRequest struct { + Messages []garminMessage `json:"messages"` +} + +type garminMessage struct { + Recipients []string `json:"recipients"` + Sender string `json:"sender"` + Timestamp string `json:"timestamp"` + Message string `json:"message"` +} + +type garminMessageResponse struct { + Count int `json:"count"` +} + +func newGarminClient(apiKey string) *garminClient { + return &garminClient{ + c: &http.Client{}, + apiKey: apiKey, + } +} + +func (gc *garminClient) sendMessage(imei, sender, msg string) error { + buf := &bytes.Buffer{} + err := json.NewEncoder(buf).Encode(garminMessageRequest{ + Messages: []garminMessage{ + { + Recipients: []string{imei}, + Sender: sender, + Timestamp: time.Now().Format(time.RFC3339), + Message: msg, + }, + }, + }) + + if err != nil { + return err + } + + req, err := http.NewRequest("POST", "https://ipcinbound.inreachapp.com/IPC/IPCInboundApi/api/Messaging/Message", buf) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("x-api-key", gc.apiKey) + + resp, err := gc.c.Do(req) + if err != nil { + return err + } + + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + + if resp.StatusCode != 200 { + return fmt.Errorf("%s", string(body)) + } + + grResp := garminMessageResponse{} + err = json.NewDecoder(resp.Body).Decode(&grResp) + if err != nil { + return err + } + + if grResp.Count != 1 { + return fmt.Errorf("expected 1 message, got %d", grResp.Count) + } + + return nil +} diff --git a/main.go b/main.go index 91963f2..9258e32 100644 --- a/main.go +++ b/main.go @@ -10,12 +10,15 @@ import ( ) type PHandler struct { - tmpl *template.Template - pd *pdClient - mux *http.ServeMux + tmpl *template.Template + pd *pdClient + gc *garminClient + garminIMEI string + garminSender string + mux *http.ServeMux } -func NewPHandler(routingKey string) (*PHandler, error) { +func NewPHandler(pdRoutingKey, garminApiKey, garminIMEI, garminSender string) (*PHandler, error) { tmpl := template.New("index.html") tmpl.Funcs(template.FuncMap{ @@ -28,9 +31,12 @@ func NewPHandler(routingKey string) (*PHandler, error) { } ph := &PHandler{ - tmpl: tmpl, - pd: newPDClient(routingKey), - mux: http.NewServeMux(), + tmpl: tmpl, + pd: newPDClient(pdRoutingKey), + gc: newGarminClient(garminApiKey), + garminIMEI: garminIMEI, + garminSender: garminSender, + mux: http.NewServeMux(), } ph.mux.HandleFunc("/{$}", ph.serveRoot) @@ -62,7 +68,7 @@ func (ph *PHandler) serveRoot(w http.ResponseWriter, r *http.Request) { return } - err = ph.pd.sendAlert(m) + err = ph.sendAlert(m) if err != nil { sendError(w, http.StatusInternalServerError, "Error sending to PagerDuty: %s", err) return @@ -70,6 +76,20 @@ func (ph *PHandler) serveRoot(w http.ResponseWriter, r *http.Request) { sendResponse(w, "Page sent") } +func (ph *PHandler) sendAlert(m string) error { + err := ph.pd.sendAlert(m) + if err != nil { + return fmt.Errorf("Error sending to PagerDuty: %s", err) + } + + err = ph.gc.sendMessage(ph.garminIMEI, ph.garminSender, m) + if err != nil { + return fmt.Errorf("Error sending to Garmin: %s", err) + } + + return nil +} + var allowedEnvs = []string{ "SHORT_NAME", "CONTACT_NAME", @@ -94,12 +114,27 @@ func (ph *PHandler) envs() map[string]string { } func main() { - routingKey := os.Getenv("PD_ROUTING_KEY") - if routingKey == "" { + pdRoutingKey := os.Getenv("PD_ROUTING_KEY") + if pdRoutingKey == "" { log.Fatalf("please set PD_ROUTING_KEY") } - ph, err := NewPHandler(routingKey) + garminApiKey := os.Getenv("GARMIN_API_KEY") + if garminApiKey == "" { + log.Fatalf("please set GARMIN_API_KEY") + } + + garminIMEI := os.Getenv("GARMIN_IMEI") + if garminIMEI == "" { + log.Fatalf("please set GARMIN_IMEI") + } + + garminSender := os.Getenv("GARMIN_SENDER") + if garminSender == "" { + log.Fatalf("please set GARMIN_SENDER") + } + + ph, err := NewPHandler(pdRoutingKey, garminApiKey, garminIMEI, garminSender) if err != nil { log.Fatalf("NewPHandler: %s", err) }