Switch Garmin messaging from IPC Inbound API to MapShare API
This commit is contained in:
92
garmin.go
92
garmin.go
@@ -1,68 +1,61 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"net/url"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type garminClient struct {
|
type garminClient struct {
|
||||||
c *http.Client
|
c *http.Client
|
||||||
apiKey string
|
mapshareID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type garminMessageRequest struct {
|
type garminResponse struct {
|
||||||
Messages []garminMessage `json:"messages"`
|
Success bool `json:"success"`
|
||||||
|
Error *struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
} `json:"error"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type garminMessage struct {
|
func newGarminClient(mapshareID string) *garminClient {
|
||||||
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{
|
return &garminClient{
|
||||||
c: &http.Client{},
|
c: &http.Client{},
|
||||||
apiKey: apiKey,
|
mapshareID: mapshareID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *garminClient) sendMessage(imeis []string, sender, msg string) error {
|
func (gc *garminClient) sendMessage(deviceIDs []string, sender, msg string) error {
|
||||||
buf := &bytes.Buffer{}
|
for _, deviceID := range deviceIDs {
|
||||||
err := json.NewEncoder(buf).Encode(garminMessageRequest{
|
err := gc.sendToDevice(deviceID, sender, msg)
|
||||||
Messages: []garminMessage{
|
if err != nil {
|
||||||
{
|
return fmt.Errorf("device %s: %w", deviceID, err)
|
||||||
Recipients: imeis,
|
}
|
||||||
Sender: sender,
|
}
|
||||||
Timestamp: time.Now().UTC().Format("2006-01-02T15:04:05Z"),
|
return nil
|
||||||
Message: msg,
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
func (gc *garminClient) sendToDevice(deviceID, sender, msg string) error {
|
||||||
|
data := url.Values{}
|
||||||
|
data.Set("deviceIds", deviceID)
|
||||||
|
data.Set("messageText", msg)
|
||||||
|
data.Set("fromAddr", sender)
|
||||||
|
|
||||||
|
endpoint := fmt.Sprintf("https://share.garmin.com/%s/Map/SendMessageToDevices", gc.mapshareID)
|
||||||
|
|
||||||
|
log.Printf("[->garmin] %s %s", endpoint, data.Encode())
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", endpoint, strings.NewReader(data.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[->garmin] %s", buf.String())
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
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)
|
resp, err := gc.c.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -72,20 +65,23 @@ func (gc *garminClient) sendMessage(imeis []string, sender, msg string) error {
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
log.Printf("[<-garmin] %d %s", resp.StatusCode, string(body))
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
return fmt.Errorf("%s", string(body))
|
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
grResp := garminMessageResponse{}
|
var grResp garminResponse
|
||||||
err = json.Unmarshal(body, &grResp)
|
err = json.Unmarshal(body, &grResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("parse response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[<-garmin] %s", string(body))
|
if !grResp.Success {
|
||||||
|
if grResp.Error != nil {
|
||||||
if grResp.Count != len(imeis) {
|
return fmt.Errorf("garmin error %d: %s", grResp.Error.Code, grResp.Error.Msg)
|
||||||
return fmt.Errorf("expected %d messages, got %d", len(imeis), grResp.Count)
|
}
|
||||||
|
return fmt.Errorf("garmin returned success=false")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
38
main.go
38
main.go
@@ -13,12 +13,12 @@ type PHandler struct {
|
|||||||
tmpl *template.Template
|
tmpl *template.Template
|
||||||
pd *pdClient
|
pd *pdClient
|
||||||
gc *garminClient
|
gc *garminClient
|
||||||
garminIMEIs []string
|
garminDeviceIDs []string
|
||||||
garminSender string
|
garminSender string
|
||||||
mux *http.ServeMux
|
mux *http.ServeMux
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPHandler(pdRoutingKey, garminAPIKey string, garminIMEIs []string, garminSender string) (*PHandler, error) {
|
func NewPHandler(pdRoutingKey, garminMapshareID string, garminDeviceIDs []string, garminSender string) (*PHandler, error) {
|
||||||
tmpl := template.New("index.html")
|
tmpl := template.New("index.html")
|
||||||
|
|
||||||
tmpl.Funcs(template.FuncMap{
|
tmpl.Funcs(template.FuncMap{
|
||||||
@@ -33,13 +33,13 @@ func NewPHandler(pdRoutingKey, garminAPIKey string, garminIMEIs []string, garmin
|
|||||||
ph := &PHandler{
|
ph := &PHandler{
|
||||||
tmpl: tmpl,
|
tmpl: tmpl,
|
||||||
pd: newPDClient(pdRoutingKey),
|
pd: newPDClient(pdRoutingKey),
|
||||||
garminIMEIs: garminIMEIs,
|
garminDeviceIDs: garminDeviceIDs,
|
||||||
garminSender: garminSender,
|
garminSender: garminSender,
|
||||||
mux: http.NewServeMux(),
|
mux: http.NewServeMux(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if garminAPIKey != "" {
|
if garminMapshareID != "" {
|
||||||
ph.gc = newGarminClient(garminAPIKey)
|
ph.gc = newGarminClient(garminMapshareID)
|
||||||
}
|
}
|
||||||
|
|
||||||
ph.mux.HandleFunc("/{$}", ph.serveRoot)
|
ph.mux.HandleFunc("/{$}", ph.serveRoot)
|
||||||
@@ -86,7 +86,7 @@ func (ph *PHandler) sendAlert(m string) error {
|
|||||||
|
|
||||||
if ph.gc != nil {
|
if ph.gc != nil {
|
||||||
go func() {
|
go func() {
|
||||||
err := ph.gc.sendMessage(ph.garminIMEIs, ph.garminSender, m)
|
err := ph.gc.sendMessage(ph.garminDeviceIDs, ph.garminSender, m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res <- fmt.Errorf("Error sending to Garmin: %w", err)
|
res <- fmt.Errorf("Error sending to Garmin: %w", err)
|
||||||
} else {
|
} else {
|
||||||
@@ -150,28 +150,28 @@ func main() {
|
|||||||
log.Fatalf("please set PD_ROUTING_KEY")
|
log.Fatalf("please set PD_ROUTING_KEY")
|
||||||
}
|
}
|
||||||
|
|
||||||
garminAPIKey := os.Getenv("GARMIN_API_KEY")
|
garminMapshareID := os.Getenv("GARMIN_MAPSHARE_ID")
|
||||||
|
|
||||||
garminIMEIStr := os.Getenv("GARMIN_IMEI")
|
garminDeviceIDStr := os.Getenv("GARMIN_DEVICE_IDS")
|
||||||
if garminAPIKey != "" && garminIMEIStr == "" {
|
if garminMapshareID != "" && garminDeviceIDStr == "" {
|
||||||
log.Fatalf("please set GARMIN_IMEI")
|
log.Fatalf("please set GARMIN_DEVICE_IDS")
|
||||||
}
|
}
|
||||||
var garminIMEIs []string
|
var garminDeviceIDs []string
|
||||||
if garminIMEIStr != "" {
|
if garminDeviceIDStr != "" {
|
||||||
for _, imei := range strings.Split(garminIMEIStr, ",") {
|
for _, id := range strings.Split(garminDeviceIDStr, ",") {
|
||||||
imei = strings.TrimSpace(imei)
|
id = strings.TrimSpace(id)
|
||||||
if imei != "" {
|
if id != "" {
|
||||||
garminIMEIs = append(garminIMEIs, imei)
|
garminDeviceIDs = append(garminDeviceIDs, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
garminSender := os.Getenv("GARMIN_SENDER")
|
garminSender := os.Getenv("GARMIN_SENDER")
|
||||||
if garminAPIKey != "" && garminSender == "" {
|
if garminMapshareID != "" && garminSender == "" {
|
||||||
log.Fatalf("please set GARMIN_SENDER")
|
log.Fatalf("please set GARMIN_SENDER")
|
||||||
}
|
}
|
||||||
|
|
||||||
ph, err := NewPHandler(pdRoutingKey, garminAPIKey, garminIMEIs, garminSender)
|
ph, err := NewPHandler(pdRoutingKey, garminMapshareID, garminDeviceIDs, garminSender)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("NewPHandler: %s", err)
|
log.Fatalf("NewPHandler: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user