github.com/Venafi/vcert/v5@v5.10.2/pkg/webclient/notificationservice/notificationservice.go (about)

     1  package notificationservice
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"net/http"
     9  	"net/url"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/go-http-utils/headers"
    14  	"github.com/gorilla/websocket"
    15  
    16  	"github.com/Venafi/vcert/v5/pkg/domain"
    17  	"github.com/Venafi/vcert/v5/pkg/util"
    18  )
    19  
    20  type NotificationServiceClient struct {
    21  	baseURL     string
    22  	accessToken string
    23  	apiKey      string
    24  }
    25  
    26  func NewNotificationServiceClient(baseURL string, accessToken string, apiKey string) *NotificationServiceClient {
    27  	return &NotificationServiceClient{
    28  		baseURL:     baseURL,
    29  		accessToken: accessToken,
    30  		apiKey:      apiKey,
    31  	}
    32  }
    33  
    34  func (ns *NotificationServiceClient) Subscribe(wsClientId string) (*websocket.Conn, error) {
    35  
    36  	_, host, found := strings.Cut(ns.baseURL, "https://")
    37  	if !found {
    38  		return nil, fmt.Errorf("failed to parse baseURL")
    39  	}
    40  
    41  	if strings.HasSuffix(host, "/") && len(host) > 0 {
    42  		host = host[:len(host)-1]
    43  	}
    44  
    45  	notificationsUrl := url.URL{Scheme: "wss", Host: host, Path: fmt.Sprintf("ws/notificationclients/%s", wsClientId)}
    46  	httpHeader := http.Header{}
    47  	if ns.accessToken != "" {
    48  		httpHeader = http.Header{headers.Authorization: {fmt.Sprintf("%s %s", util.OauthTokenType, ns.accessToken)}}
    49  	} else if ns.apiKey != "" {
    50  		httpHeader = http.Header{util.HeaderTpplApikey: {ns.apiKey}}
    51  	}
    52  
    53  	// nolint:bodyclose // TODO: figure out better way to close the body response so it is detected by the linter
    54  	wsConn, resp, err := websocket.DefaultDialer.Dial(notificationsUrl.String(), httpHeader)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	defer func(Body io.ReadCloser) {
    59  		tempErr := Body.Close()
    60  		if tempErr != nil {
    61  			err = tempErr
    62  		}
    63  	}(resp.Body)
    64  
    65  	if resp.StatusCode != http.StatusSwitchingProtocols {
    66  		return nil, fmt.Errorf("failed switch protocols")
    67  	}
    68  	log.Print("successfully switched to websocket connection")
    69  
    70  	time.Sleep(5 * time.Second)
    71  	return wsConn, nil
    72  }
    73  
    74  func (ns *NotificationServiceClient) ReadResponse(wsConn *websocket.Conn) (*domain.WorkflowResponse, error) {
    75  	_, msg, err := wsConn.ReadMessage()
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	defer func() {
    81  		_ = wsConn.Close()
    82  	}()
    83  	log.Printf("<---- Workflow Response:\n%s", msg)
    84  
    85  	workflowResponse := domain.WorkflowResponse{}
    86  	err = json.Unmarshal(msg, &workflowResponse)
    87  	if err != nil {
    88  		log.Printf("failed to unmarshal response %s", err.Error())
    89  		return nil, err
    90  	}
    91  
    92  	return &workflowResponse, nil
    93  }