Skip to content

Commit

Permalink
client.Do option 1: Do with RequestOptions and RequestResponse per Fred
Browse files Browse the repository at this point in the history
  • Loading branch information
benhoyt committed Oct 4, 2023
1 parent 9decf59 commit 48939e9
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 4 deletions.
65 changes: 64 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ type Client struct {
warningTimestamp time.Time

getWebsocket getWebsocketFunc
transport *http.Transport
decodeHook DecodeHookFunc
}

type getWebsocketFunc func(url string) (clientWebsocket, error)
Expand Down Expand Up @@ -159,10 +161,15 @@ func New(config *Config) (*Client, error) {
client.getWebsocket = func(url string) (clientWebsocket, error) {
return getWebsocket(transport, url)
}
client.transport = transport

return client, nil
}

func (client *Client) Transport() *http.Transport {
return client.transport
}

func (client *Client) getTaskWebsocket(taskID, websocketID string) (clientWebsocket, error) {
url := fmt.Sprintf("ws://localhost/v1/tasks/%s/websocket/%s", taskID, websocketID)
return client.getWebsocket(url)
Expand Down Expand Up @@ -304,8 +311,21 @@ func (client *Client) do(method, path string, query url.Values, headers map[stri
}
defer rsp.Body.Close()

var responseBody io.Reader = rsp.Body
if client.decodeHook != nil {
bodyBytes, err := io.ReadAll(responseBody)
if err != nil {
return err
}
err = client.decodeHook(bodyBytes, &RequestOptions{Method: method, Path: path /* TODO */})
if err != nil {
return err
}
responseBody = bytes.NewReader(bodyBytes)
}

if v != nil {
if err := decodeInto(rsp.Body, v); err != nil {
if err := decodeInto(responseBody, v); err != nil {
return err
}
}
Expand Down Expand Up @@ -515,3 +535,46 @@ func (client *Client) DebugGet(action string, result interface{}, params map[str
_, err := client.doSync("GET", "/v1/debug", urlParams, nil, nil, &result)
return err
}

// RequestOptions allows setting up a specific request.
type RequestOptions struct {
Method string
Path string
Query url.Values
Headers map[string]string
Body io.Reader
Async bool
ReturnBody bool
}

// RequestResponse defines a common response associated with requests.
type RequestResponse struct {
StatusCode int
ChangeID string
Body io.ReadCloser
}

// NOTE: not the real implementation, just to get things to work at a basic level
func (client *Client) Do(ctx context.Context, opts *RequestOptions, result interface{}) (*RequestResponse, error) {
if opts.ReturnBody {
panic("not yet implemented")
}
if opts.Async {
changeID, err := client.doAsync(opts.Method, opts.Path, opts.Query, opts.Headers, opts.Body)
if err != nil {
return nil, err
}
return &RequestResponse{ChangeID: changeID}, nil
}
_, err := client.doSync(opts.Method, opts.Path, opts.Query, opts.Headers, opts.Body, result)
if err != nil {
return nil, err
}
return &RequestResponse{}, nil
}

type DecodeHookFunc func(data []byte, opts *RequestOptions) error

func (client *Client) SetDecodeHook(hook DecodeHookFunc) {
client.decodeHook = hook
}
99 changes: 99 additions & 0 deletions cmd/clienttest/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package main

import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"strings"
"time"

"github.com/gorilla/websocket"

"github.com/canonical/pebble/client"
)

func main() {
config := &client.Config{
Socket: os.Getenv("PEBBLE_SOCKET"),
}
pebble, err := client.New(config)
if err != nil {
log.Fatal(err)
}
myClient := NewMyClient(pebble)
services, err := myClient.UpperServices()
if err != nil {
log.Fatal(err)
}
for _, info := range services {
fmt.Printf("%s: startup %q, current %q\n", info.Name, info.Startup, info.Current)
}
fmt.Println("---")
fmt.Printf("Server version: %s\n", myClient.ServerVersion)
}

type MyClient struct {
ServerVersion string

pebble *client.Client
}

func NewMyClient(pebble *client.Client) *MyClient {
c := &MyClient{pebble: pebble}
c.pebble.SetDecodeHook(c.decodeHook)
return c
}

func (c *MyClient) decodeHook(data []byte, opts *client.RequestOptions) error {
// Demonstrate use of opts: only do custom decode on v1 requests.
if !strings.HasPrefix(opts.Path, "/v1/") {
return nil
}
var frame struct {
ServerVersion string `json:"server-version"`
}
err := json.Unmarshal(data, &frame)
if err != nil {
return err
}
if frame.ServerVersion != "" {
c.ServerVersion = frame.ServerVersion
}
return nil
}

func (c *MyClient) UpperServices() ([]UpperServiceInfo, error) {
var infos []UpperServiceInfo
_, err := c.pebble.Do(context.Background(), &client.RequestOptions{
Method: "GET",
Path: "/v1/services",
}, &infos)
if err != nil {
return nil, err
}
for _, info := range infos {
info.Name = strings.ToUpper(info.Name)
info.Startup = strings.ToUpper(info.Startup)
info.Current = strings.ToUpper(info.Current)
}
return infos, nil
}

func (c *MyClient) GetWebsocket(url string) (*websocket.Conn, error) {
dialer := websocket.Dialer{
NetDial: c.pebble.Transport().Dial,
Proxy: c.pebble.Transport().Proxy,
TLSClientConfig: c.pebble.Transport().TLSClientConfig,
HandshakeTimeout: 5 * time.Second,
}
conn, _, err := dialer.Dial(url, nil)
return conn, err
}

type UpperServiceInfo struct {
Name string `json:"name"`
Startup string `json:"startup"`
Current string `json:"current"`
}
10 changes: 7 additions & 3 deletions internals/daemon/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type resp struct {
WarningTimestamp *time.Time `json:"warning-timestamp,omitempty"`
WarningCount int `json:"warning-count,omitempty"`
Maintenance *errorResult `json:"maintenance,omitempty"`
ServerVersion string `json:"server-version"`
}

type respJSON struct {
Expand All @@ -56,6 +57,7 @@ type respJSON struct {
WarningTimestamp *time.Time `json:"warning-timestamp,omitempty"`
WarningCount int `json:"warning-count,omitempty"`
Maintenance *errorResult `json:"maintenance,omitempty"`
ServerVersion string `json:"server-version"`
}

func (r *resp) transmitMaintenance(kind errorKind, message string) {
Expand Down Expand Up @@ -86,6 +88,7 @@ func (r *resp) MarshalJSON() ([]byte, error) {
WarningTimestamp: r.WarningTimestamp,
WarningCount: r.WarningCount,
Maintenance: r.Maintenance,
ServerVersion: r.ServerVersion,
})
}

Expand Down Expand Up @@ -143,9 +146,10 @@ func SyncResponse(result interface{}) Response {
}

return &resp{
Type: ResponseTypeSync,
Status: http.StatusOK,
Result: result,
Type: ResponseTypeSync,
Status: http.StatusOK,
Result: result,
ServerVersion: "v1.2.3",
}
}

Expand Down

0 comments on commit 48939e9

Please sign in to comment.