191 lines
5.2 KiB
Go
191 lines
5.2 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"log/slog"
|
|
"sync"
|
|
"time"
|
|
|
|
"git.savin.nyc/alex/go-iar-notificator/config"
|
|
resty "resty.dev/v3"
|
|
)
|
|
|
|
const (
|
|
GET = "GET"
|
|
POST = "POST"
|
|
)
|
|
|
|
// Config holds the API configuration
|
|
// type Config struct {
|
|
// URL string
|
|
// SecretKey string
|
|
// AuthToken string
|
|
// SubscriberID int
|
|
// PagerGroupID string
|
|
// }
|
|
|
|
// Client represents a MySubaru API client that interacts with the MySubaru API.
|
|
type Client struct {
|
|
credentials *config.Credentials
|
|
IAR IaR
|
|
HTTPClient *resty.Client
|
|
isAlive bool
|
|
logger *slog.Logger
|
|
sync.RWMutex
|
|
}
|
|
|
|
type IaR struct {
|
|
PagerGroupID string
|
|
PagerGroupName string
|
|
Type string
|
|
}
|
|
|
|
// New function creates a New MySubaru API client
|
|
func New(credentials *config.Credentials, logger *slog.Logger) (*Client, error) {
|
|
|
|
client := &Client{
|
|
credentials: credentials,
|
|
IAR: IaR{
|
|
PagerGroupID: "",
|
|
PagerGroupName: "",
|
|
Type: "",
|
|
},
|
|
isAlive: false,
|
|
logger: logger,
|
|
}
|
|
|
|
httpClient := resty.New()
|
|
httpClient.
|
|
SetBaseURL("https://ttd.iamresponding.com/ttd").
|
|
SetHeaders(map[string]string{
|
|
"User-Agent": "python-requests/2.22.0",
|
|
"Accept-Encoding": "gzip, deflate",
|
|
"Accept": "*/*",
|
|
"Connection": "keep-alive",
|
|
"Content-Type": "application/json",
|
|
"SecretKey": client.credentials.SecretKey,
|
|
"Authorization": "TTDApiKey " + client.credentials.TTDApiKey,
|
|
},
|
|
)
|
|
|
|
client.HTTPClient = httpClient
|
|
return client, nil
|
|
}
|
|
|
|
func (c *Client) KeepAlive() error {
|
|
query := `query {getMutualPagerGroupsList {_id subscriberId name type tone_tolerance gaplength ignore_after record_delay record_seconds release_time playback_during_record post_email_command alert_command atone btone atonelength btonelength longtone longtonelength createDate},getTTDSetting(keySetting: "pollingSeconds"){keySetting keyValue}}`
|
|
resp, err := c.execute(POST, "", map[string]string{"query": query})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp != nil && len(resp.Data.GetMutualPagerGroupsList) > 0 {
|
|
pg := resp.Data.GetMutualPagerGroupsList[0]
|
|
c.IAR.PagerGroupID = pg.ID
|
|
c.IAR.PagerGroupName = pg.Name
|
|
c.IAR.Type = pg.Type
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) PreAlert() (string, error) {
|
|
ttdReceivedDate := time.Now().UTC().Format(time.RFC3339)
|
|
query := `mutation {addAlert(ttdReceivedDate: "` + ttdReceivedDate + `", pagerGroup: ["` + c.IAR.PagerGroupID + `"]){_id textAlert pagerGroup subscriberId}}`
|
|
resp, err := c.execute(POST, "", map[string]string{"query": query})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return resp.Data.AddAlert.ID, nil
|
|
}
|
|
|
|
func (c *Client) Alert(audioBase64 string) error {
|
|
var err error
|
|
var alertID string
|
|
ttdReceivedDate := time.Now().UTC().Format(time.RFC3339)
|
|
if alertID, err = c.PreAlert(); err != nil {
|
|
return errors.New("failed to create pre-alert")
|
|
}
|
|
query := `mutation {addAlert(_id: "` + alertID + `", ttdReceivedDate: "` + ttdReceivedDate + `", pagerGroup: ["` + c.IAR.PagerGroupID + `"], audio: "` + audioBase64 + `"){_id textAlert pagerGroup audioUrl subscriberId}}`
|
|
resp, err := c.execute(POST, "", map[string]string{"query": query})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.logger.Info("Alert sent successfully", "alertID", resp.Data.AddAlert.ID, "audioURL", resp.Data.AddAlert.AudioUrl)
|
|
|
|
return nil
|
|
}
|
|
|
|
// ServeKeepAlive starts a goroutine that sends keep-alive requests at the specified interval.
|
|
func (c *Client) ServeKeepAlive(ctx context.Context, interval time.Duration) {
|
|
ticker := time.NewTicker(interval)
|
|
defer ticker.Stop()
|
|
|
|
slog.Info("Starting keep-alive sender", "interval", interval)
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
slog.Info("Stopping keep-alive sender")
|
|
return
|
|
case <-ticker.C:
|
|
if err := c.KeepAlive(); err != nil {
|
|
slog.Error("Failed to send keep-alive", "error", err)
|
|
} else {
|
|
slog.Info("Sent keep-alive successfully")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// IsAlive checks if the Client instance is alive
|
|
func (c *Client) IsAlive() bool {
|
|
return c.isAlive
|
|
}
|
|
|
|
// execute executes an HTTP request based on the method, URL, and parameters provided.
|
|
func (c *Client) execute(method string, url string, params map[string]string) (*Response, error) {
|
|
c.Lock()
|
|
var resp *resty.Response
|
|
var err error
|
|
c.logger.Debug("executing http request", "method", method, "url", url, "params", params)
|
|
|
|
// POST Requests
|
|
if method == POST {
|
|
resp, err = c.HTTPClient.
|
|
R().
|
|
SetBody(params).
|
|
Post(url)
|
|
if err != nil {
|
|
c.logger.Error("error while executing POST request", "request", "execute", "method", method, "url", url, "error", err.Error())
|
|
return nil, err
|
|
}
|
|
c.logger.Debug("executed POST request", "method", method, "url", url, "params", params)
|
|
}
|
|
|
|
if resp.IsSuccess() {
|
|
resBytes, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
c.logger.Error("error while getting body", "error", err.Error())
|
|
}
|
|
c.logger.Debug("parsed http request output", "data", string(resBytes))
|
|
|
|
c.HTTPClient.SetCookies(resp.Cookies())
|
|
|
|
var r Response
|
|
if err := json.Unmarshal(resBytes, &r); err != nil {
|
|
c.logger.Error("error while unmarshalling response", "error", err.Error())
|
|
c.isAlive = false
|
|
c.Unlock()
|
|
return nil, err
|
|
}
|
|
c.isAlive = true
|
|
c.Unlock()
|
|
return &r, nil
|
|
}
|
|
c.isAlive = false
|
|
c.Unlock()
|
|
return nil, errors.New("request is not successfull, HTTP code: " + resp.Status())
|
|
}
|