Skip to content

Commit 0e41c61

Browse files
committed
feat(cli): dump request/responses in debug mode
1 parent 4a37585 commit 0e41c61

File tree

7 files changed

+97
-24
lines changed

7 files changed

+97
-24
lines changed

client.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package rfms
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
67
"io"
8+
"net/http"
9+
"net/http/httputil"
10+
"os"
711
"runtime/debug"
812

913
"github.com/hashicorp/go-retryablehttp"
@@ -50,6 +54,40 @@ func (c *Client) newRequest(ctx context.Context, method, path string, body io.Re
5054
return request, nil
5155
}
5256

57+
func (c *Client) do(request *retryablehttp.Request) (*http.Response, error) {
58+
if c.config.debug {
59+
requestData, err := httputil.DumpRequestOut(request.Request, true)
60+
if err != nil {
61+
return nil, err
62+
}
63+
var output bytes.Buffer
64+
output.Grow(2 * len(requestData))
65+
for line := range bytes.Lines(requestData) {
66+
_, _ = output.WriteString("> ")
67+
_, _ = output.Write(line)
68+
}
69+
_, _ = os.Stderr.Write(output.Bytes())
70+
}
71+
response, err := c.httpClient.Do(request)
72+
if err != nil {
73+
return nil, err
74+
}
75+
if c.config.debug {
76+
responseData, err := httputil.DumpResponse(response, true)
77+
if err != nil {
78+
return nil, err
79+
}
80+
var output bytes.Buffer
81+
output.Grow(2 * len(responseData))
82+
for line := range bytes.Lines(responseData) {
83+
_, _ = output.WriteString("< ")
84+
_, _ = output.Write(line)
85+
}
86+
_, _ = os.Stderr.Write(output.Bytes())
87+
}
88+
return response, nil
89+
}
90+
5391
func getUserAgent() string {
5492
userAgent := "rfms-go"
5593
if info, ok := debug.ReadBuildInfo(); ok && info.Main.Version != "" {

client_config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type ClientConfig struct {
1313
transport http.RoundTripper
1414
retryCount int
1515
logger Logger
16+
debug bool
1617
}
1718

1819
// newClientConfig creates a new default [ClientConfig].
@@ -27,6 +28,13 @@ func newClientConfig() ClientConfig {
2728
// ClientOption is an option that configures a [Client].
2829
type ClientOption func(*ClientConfig)
2930

31+
// WithDebug sets the debug flag for the [Client].
32+
func WithDebug(debug bool) ClientOption {
33+
return func(cc *ClientConfig) {
34+
cc.debug = debug
35+
}
36+
}
37+
3038
// WithBaseURL sets the API base URL for the [Client].
3139
func WithBaseURL(baseURL string) ClientOption {
3240
return func(cc *ClientConfig) {

client_vehiclepositions.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func (c *Client) vehiclePositionsV2(ctx context.Context, request VehiclePosition
8989
q.Set("triggerFilter", request.TriggerFilter)
9090
}
9191
httpRequest.URL.RawQuery = q.Encode()
92-
httpResponse, err := c.httpClient.Do(httpRequest)
92+
httpResponse, err := c.do(httpRequest)
9393
if err != nil {
9494
return VehiclePositionsResponse{}, fmt.Errorf("send request: %w", err)
9595
}
@@ -145,7 +145,7 @@ func (c *Client) vehiclePositionsV4(ctx context.Context, request VehiclePosition
145145
q.Set("triggerFilter", request.TriggerFilter)
146146
}
147147
httpRequest.URL.RawQuery = q.Encode()
148-
httpResponse, err := c.httpClient.Do(httpRequest)
148+
httpResponse, err := c.do(httpRequest)
149149
if err != nil {
150150
return VehiclePositionsResponse{}, fmt.Errorf("send request: %w", err)
151151
}

client_vehicles.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (c *Client) vehiclesV2(ctx context.Context, request VehiclesRequest) (Vehic
5757
q.Set("lastVin", request.LastVIN)
5858
}
5959
httpRequest.URL.RawQuery = q.Encode()
60-
httpResponse, err := c.httpClient.Do(httpRequest)
60+
httpResponse, err := c.do(httpRequest)
6161
if err != nil {
6262
return VehiclesResponse{}, fmt.Errorf("send request: %w", err)
6363
}
@@ -94,7 +94,7 @@ func (c *Client) vehiclesV4(ctx context.Context, request VehiclesRequest) (Vehic
9494
q.Set("lastVin", request.LastVIN)
9595
}
9696
httpRequest.URL.RawQuery = q.Encode()
97-
httpResponse, err := c.httpClient.Do(httpRequest)
97+
httpResponse, err := c.do(httpRequest)
9898
if err != nil {
9999
return VehiclesResponse{}, fmt.Errorf("send request: %w", err)
100100
}

client_vehiclestatuses.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func (c *Client) vehicleStatusesV2(ctx context.Context, request VehicleStatusesR
9494
q.Set("latestOnly", "true")
9595
}
9696
httpRequest.URL.RawQuery = q.Encode()
97-
httpResponse, err := c.httpClient.Do(httpRequest)
97+
httpResponse, err := c.do(httpRequest)
9898
if err != nil {
9999
return VehicleStatusesResponse{}, fmt.Errorf("send request: %w", err)
100100
}
@@ -153,7 +153,7 @@ func (c *Client) vehicleStatusesV4(ctx context.Context, request VehicleStatusesR
153153
q.Set("latestOnly", "true")
154154
}
155155
httpRequest.URL.RawQuery = q.Encode()
156-
httpResponse, err := c.httpClient.Do(httpRequest)
156+
httpResponse, err := c.do(httpRequest)
157157
if err != nil {
158158
return VehicleStatusesResponse{}, fmt.Errorf("send request: %w", err)
159159
}

cmd/rfms/internal/auth/cmd.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func ReadCredentials() (*Credentials, error) {
4545
}
4646

4747
// NewClient creates a new rFMS client using the CLI credentials.
48-
func NewClient() (*rfms.Client, error) {
48+
func NewClient(opts ...rfms.ClientOption) (*rfms.Client, error) {
4949
auth, err := ReadCredentials()
5050
if err != nil {
5151
return nil, err
@@ -60,13 +60,17 @@ func NewClient() (*rfms.Client, error) {
6060
return nil, fmt.Errorf("session expired - please login again")
6161
}
6262
return rfms.NewClient(
63-
rfms.WithBaseURL(rfms.ScaniaBaseURL),
64-
rfms.WithVersion(rfms.V4),
65-
rfms.WithReuseTokenAuth(*auth.TokenCredentials),
63+
append(opts,
64+
rfms.WithBaseURL(rfms.ScaniaBaseURL),
65+
rfms.WithVersion(rfms.V4),
66+
rfms.WithReuseTokenAuth(*auth.TokenCredentials),
67+
)...,
6668
), nil
6769
case rfms.BrandVolvoTrucks:
6870
return rfms.NewClient(
69-
rfms.WithVolvoTrucks(auth.Username, auth.Password),
71+
append(opts,
72+
rfms.WithVolvoTrucks(auth.Username, auth.Password),
73+
)...,
7074
), nil
7175
default:
7276
return nil, fmt.Errorf("unknown provider: %s", auth.Provider)

cmd/rfms/main.go

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func newRootCommand() *cobra.Command {
4949
Use: "rfms",
5050
Short: "rFMS CLI",
5151
}
52+
cmd.PersistentFlags().Bool("debug", false, "Enable debug logging")
5253
cmd.AddGroup(&cobra.Group{
5354
ID: "rfms",
5455
Title: "rFMS Commands",
@@ -67,10 +68,9 @@ func newRootCommand() *cobra.Command {
6768
})
6869
cmd.SetHelpCommandGroupID("utils")
6970
cmd.SetCompletionCommandGroupID("utils")
70-
cmd.PersistentFlags().BoolP("debug", "d", false, "enable debug logging")
7171
cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
7272
level := slog.LevelInfo
73-
if cmd.Flags().Changed("debug") {
73+
if cmd.Root().PersistentFlags().Changed("debug") {
7474
level = slog.LevelDebug
7575
}
7676
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
@@ -81,6 +81,17 @@ func newRootCommand() *cobra.Command {
8181
return cmd
8282
}
8383

84+
func newClient(cmd *cobra.Command) (*rfms.Client, error) {
85+
debug, _ := cmd.Root().PersistentFlags().GetBool("debug")
86+
client, err := auth.NewClient(
87+
rfms.WithDebug(debug),
88+
)
89+
if err != nil {
90+
return nil, err
91+
}
92+
return client, nil
93+
}
94+
8495
func newVehiclesCommand() *cobra.Command {
8596
cmd := &cobra.Command{
8697
Use: "vehicles",
@@ -89,7 +100,7 @@ func newVehiclesCommand() *cobra.Command {
89100
}
90101
limit := cmd.Flags().Int("limit", 100, "max vehicles queried")
91102
cmd.RunE = func(cmd *cobra.Command, args []string) error {
92-
client, err := auth.NewClient()
103+
client, err := newClient(cmd)
93104
if err != nil {
94105
return err
95106
}
@@ -115,30 +126,42 @@ func newVehiclesCommand() *cobra.Command {
115126

116127
func newVehiclePositionsCommand() *cobra.Command {
117128
cmd := &cobra.Command{
118-
Use: "vehicle-positions",
129+
Use: "vehicle-positions [VIN]",
119130
Short: "List vehicle positions",
120131
GroupID: "rfms",
132+
Args: cobra.MaximumNArgs(1),
121133
}
122-
limit := cmd.Flags().Int("limit", 100, "max vehicle positions queried")
134+
startTime := cmd.Flags().Time("start", time.Time{}, []string{time.DateOnly, time.RFC3339}, "start time")
135+
stopTime := cmd.Flags().Time("stop", time.Time{}, []string{time.DateOnly, time.RFC3339}, "stop time")
123136
cmd.RunE = func(cmd *cobra.Command, args []string) error {
124-
client, err := auth.NewClient()
137+
client, err := newClient(cmd)
125138
if err != nil {
126139
return err
127140
}
128-
moreDataAvailable, lastVIN, count := true, "", 0
129-
for moreDataAvailable && count < *limit {
130-
response, err := client.VehiclePositions(cmd.Context(), rfms.VehiclePositionsRequest{
141+
var vin string
142+
if len(args) > 0 {
143+
vin = args[0]
144+
}
145+
moreDataAvailable, lastVIN := true, ""
146+
for moreDataAvailable {
147+
request := rfms.VehiclePositionsRequest{
131148
LastVIN: lastVIN,
132-
LatestOnly: true,
133-
})
149+
VIN: vin,
150+
LatestOnly: startTime.IsZero() && stopTime.IsZero(),
151+
StartTime: *startTime,
152+
StopTime: *stopTime,
153+
}
154+
response, err := client.VehiclePositions(cmd.Context(), request)
134155
if err != nil {
135156
return err
136157
}
137158
for _, vehiclePosition := range response.VehiclePositions {
138159
fmt.Println(protojson.Format(vehiclePosition))
139160
}
140-
count += len(response.VehiclePositions)
141161
moreDataAvailable = response.MoreDataAvailable
162+
if !moreDataAvailable {
163+
break
164+
}
142165
lastVIN = response.VehiclePositions[len(response.VehiclePositions)-1].GetVin()
143166
}
144167
return nil
@@ -156,7 +179,7 @@ func newVehicleStatusesCommand() *cobra.Command {
156179
startTime := cmd.Flags().Time("start", time.Time{}, []string{time.DateOnly, time.RFC3339}, "start time")
157180
stopTime := cmd.Flags().Time("stop", time.Time{}, []string{time.DateOnly, time.RFC3339}, "stop time")
158181
cmd.RunE = func(cmd *cobra.Command, args []string) error {
159-
client, err := auth.NewClient()
182+
client, err := newClient(cmd)
160183
if err != nil {
161184
return err
162185
}

0 commit comments

Comments
 (0)