package main import ( "encoding/json" "fmt" "io" "log" "net/http" "net/url" "strings" ) type garminClient struct { c *http.Client mapshareID string } type garminResponse struct { Success bool `json:"success"` Error *struct { Code int `json:"code"` Msg string `json:"msg"` } `json:"error"` } func newGarminClient(mapshareID string) *garminClient { return &garminClient{ c: &http.Client{}, mapshareID: mapshareID, } } func (gc *garminClient) sendMessage(deviceIDs []string, sender, msg string) error { for _, deviceID := range deviceIDs { err := gc.sendToDevice(deviceID, sender, msg) if err != nil { return fmt.Errorf("device %s: %w", deviceID, err) } } return nil } 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 { return err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, err := gc.c.Do(req) if err != nil { return err } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) log.Printf("[<-garmin] %d %s", resp.StatusCode, string(body)) if resp.StatusCode != 200 { return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body)) } var grResp garminResponse err = json.Unmarshal(body, &grResp) if err != nil { return fmt.Errorf("parse response: %w", err) } if !grResp.Success { if grResp.Error != nil { return fmt.Errorf("garmin error %d: %s", grResp.Error.Code, grResp.Error.Msg) } return fmt.Errorf("garmin returned success=false") } return nil }