Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions framework/components/chiprouter/.changeset/v1.0.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add ChIP Router client
134 changes: 134 additions & 0 deletions framework/components/chiprouter/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package client

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

pkgerrors "github.com/pkg/errors"
)

const (
adminRequestTimeout = 5 * time.Second
)

type RegisterSubscriberRequest struct {
Name string `json:"name"`
Endpoint string `json:"endpoint"`
}

type RegisterSubscriberResponse struct {
ID string `json:"id"`
}

type Client struct {
httpClient *http.Client
adminURL string
grpcURL string
}

func New(ctx context.Context, adminURL, grpcURL string) (*Client, error) {
c := &Client{
httpClient: &http.Client{Timeout: adminRequestTimeout},
adminURL: adminURL,
grpcURL: grpcURL,
}

if !c.isHTTPReady(ctx) {
return nil, fmt.Errorf("chip router admin endpoint is not reachable: %s", c.adminURL)
}
if !c.isTCPReady() {
return nil, fmt.Errorf("chip router grpc endpoint is not reachable: %s", c.grpcURL)
}
return c, nil
}

func (c *Client) RegisterSubscriber(ctx context.Context, name, endpoint string) (string, error) {
body, err := json.Marshal(RegisterSubscriberRequest{Name: name, Endpoint: endpoint})
if err != nil {
return "", pkgerrors.Wrap(err, "marshal chip router register request")
}

req, err := http.NewRequestWithContext(ctx, http.MethodPost, strings.TrimRight(c.adminURL, "/")+"/subscribers", bytes.NewReader(body))
if err != nil {
return "", pkgerrors.Wrap(err, "create chip router register request")
}
req.Header.Set("Content-Type", "application/json")

resp, err := c.httpClient.Do(req)
if err != nil {
return "", pkgerrors.Wrap(err, "perform chip router register request")
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("chip router register request failed with status %s", resp.Status)
}

var out RegisterSubscriberResponse
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
return "", pkgerrors.Wrap(err, "decode chip router register response")
}
if out.ID == "" {
return "", pkgerrors.New("chip router register response missing subscriber id")
}

return out.ID, nil
}

func (c *Client) UnregisterSubscriber(ctx context.Context, id string) error {
if strings.TrimSpace(id) == "" {
return nil
}

req, err := http.NewRequestWithContext(ctx, http.MethodDelete, strings.TrimRight(c.adminURL, "/")+"/subscribers/"+id, nil)
if err != nil {
return pkgerrors.Wrap(err, "create chip router unregister request")
}

resp, err := c.httpClient.Do(req)
if err != nil {
return pkgerrors.Wrap(err, "perform chip router unregister request")
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("chip router unregister request failed with status %s", resp.Status)
}
return nil
}

func (c *Client) isHTTPReady(ctx context.Context) bool {
if strings.TrimSpace(c.adminURL) == "" {
return false
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, strings.TrimRight(c.adminURL, "/")+"/health", nil)
if err != nil {
return false
}
resp, err := c.httpClient.Do(req)
if err != nil {
return false
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return false
}

return true
}

func (c *Client) isTCPReady() bool {
dialer := &net.Dialer{Timeout: adminRequestTimeout}
conn, err := dialer.Dial("tcp", c.grpcURL)
if err != nil {
return false
}
_ = conn.Close()
return true
}
2 changes: 1 addition & 1 deletion framework/components/chiprouter/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/docker/docker v28.5.2+incompatible
github.com/docker/go-connections v0.6.0
github.com/google/uuid v1.6.0
github.com/pkg/errors v0.9.1
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4
github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.8
github.com/testcontainers/testcontainers-go v0.41.0
Expand Down Expand Up @@ -58,7 +59,6 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/rs/zerolog v1.33.0 // indirect
Expand Down
Loading