remote/siri_lite_client.go

Summary

Maintainability
A
1 hr
Test Coverage
package remote

import (
    "bytes"
    "context"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "strings"

    "bitbucket.org/enroute-mobi/ara/siri/slite"
    "bitbucket.org/enroute-mobi/ara/version"
    "github.com/pkg/errors"
)

type SIRILiteClient struct {
    HTTPClientUrls
    credential SiriCredentialHeader

    httpClient *HTTPClient
}

type siriLiteClientArguments struct {
    params           url.Values
    requestType      requestType
    expectedResponse string
    destination      interface{}
}

func NewSIRILiteClient(c *HTTPClient, credential SiriCredentialHeader) *SIRILiteClient {
    return &SIRILiteClient{
        httpClient: c,
        credential: credential,
    }
}

func (client *SIRILiteClient) remoteClient() *http.Client {
    return client.httpClient.HTTPClient()
}

func (c *SIRILiteClient) prepareAndSendRequest(args siriLiteClientArguments) error {
    dest := args.destination

    ctx, cncl := context.WithTimeout(context.Background(), getTimeOut(args.requestType))
    defer cncl()

    buildUrl, err := URI(c.getURL(args.requestType), "", args.params)
    if err != nil {
        return errors.Wrap(err, "unable to build URI")
    }

    // Create http request
    httpRequest, err := http.NewRequestWithContext(ctx, http.MethodGet, buildUrl.String(), nil)
    if err != nil {
        return errors.Wrap(err, "cannot create request")
    }

    httpRequest.Header.Add("Accept", "application/json")
    httpRequest.Header.Add("Content-Type", "application/json")
    httpRequest.Header.Set("User-Agent", version.ApplicationName())
    httpRequest.Header.Set(c.credential.CredentialHeader, c.credential.Value)

    // Send http request
    resp, err := c.remoteClient().Do(httpRequest)
    if err != nil {
        return errors.Wrap(err, "cannot proceed request")
    }

    // Attempt to read the body
    defer resp.Body.Close()
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return errors.Wrap(err, "cannot read the response")
    }

    // Check empty body
    if len(body) == 0 {
        return errors.Wrap(err, "empty body")
    }

    // Check response status
    if resp.StatusCode < 200 || resp.StatusCode >= 300 {
        return fmt.Errorf("request failed with status %d: %s", resp.StatusCode, strings.Replace(string(body), "\n", "", -1))
    }

    // rewrite the payload
    rewriteBody, err := slite.RewriteValues(body)
    if err != nil {
        return errors.Wrap(err, "cannot rewrite the payload")
    }

    // Parse the body
    err = json.NewDecoder(bytes.NewReader(rewriteBody)).Decode(&dest)
    if err != nil {
        return errors.Wrap(err, "cannot parse server response")
    }

    return nil
}

func (client *SIRILiteClient) StopMonitoring(stopArea string) (*slite.SIRILiteStopMonitoring, error) {
    params := url.Values{}
    params.Add("MonitoringRef", stopArea)

    dest := &slite.SIRILiteStopMonitoring{}

    err := client.prepareAndSendRequest(siriLiteClientArguments{
        params:           params,
        requestType:      NOTIFICATION,
        expectedResponse: "StopMonitoringDelivery",
        destination:      dest,
    })
    if err != nil {
        return nil, err
    }

    return dest, nil
}

func URI(baseurl string, path string, params url.Values) (*url.URL, error) {
    base, err := url.Parse(baseurl)
    if err != nil {
        return nil, errors.Wrapf(err, "unable to parse base url %v", baseurl)
    }

    if params == nil {
        params = url.Values{}
    }
    u := base.ResolveReference(&url.URL{Path: path, RawQuery: params.Encode()})
    return u, nil
}

func (client *SIRILiteClient) getURL(requestType requestType) string {
    switch requestType {
    case SUBSCRIPTION:
        if client.httpClient.SubscriptionsUrl != "" {
            return client.httpClient.SubscriptionsUrl
        }
    case NOTIFICATION:
        if client.httpClient.NotificationsUrl != "" {
            return client.httpClient.NotificationsUrl
        }
    }
    return client.httpClient.Url
}