Skip to content

Commit fd4b1d1

Browse files
Modernize code
1 parent 0107342 commit fd4b1d1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+880
-300
lines changed

.circleci/config.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ workflows:
99
jobs:
1010
build-and-test:
1111
docker:
12-
- image: cimg/go:1.21.5
12+
- image: cimg/go:1.24.2
1313
steps:
1414
- checkout
1515
- run: go vet ./...
1616
- run: go test ./...
1717
govulncheck:
1818
docker:
19-
- image: cimg/go:1.21.5
19+
- image: cimg/go:1.24.2
2020
steps:
2121
- checkout
2222
- run: go install golang.org/x/vuln/cmd/govulncheck@latest
23-
- run: govulncheck ./...
23+
- run: $(go env GOPATH)/bin/govulncheck ./...

client/client.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Recommended Usage:
44
//
55
// type MyClient struct {
6-
// Client *client.Client
6+
// Client *client.Client
77
// }
88
//
99
// type ThingInput struct {
@@ -13,10 +13,10 @@
1313
// }
1414
//
1515
// func(c MyClient) Thing(input *ThingInput) (*ThingOutput, err) {
16-
// var output ThingOutput
17-
// req := c.Client.NewRequest("GET", "/thing", input, output)
18-
// err := req.Send()
19-
// return output, err
16+
// var output ThingOutput
17+
// req := c.Client.NewRequest("GET", "/thing", input, output)
18+
// err := req.Send()
19+
// return output, err
2020
// }
2121
package client
2222

@@ -109,8 +109,7 @@ func New(info metadata.ClientInfo, options ...ClientOpt) *Client {
109109
// A request.Request will be initialized with the http.Request, Handlers,
110110
// params and data.
111111
func (c *Client) NewRequest(ctx context.Context, method, path string, params interface{}, data interface{}) *request.Request {
112-
httpReq, _ := http.NewRequest(method, path, nil)
113-
httpReq = httpReq.WithContext(ctx)
112+
httpReq, _ := http.NewRequestWithContext(ctx, method, path, nil)
114113
httpReq.URL, _ = url.Parse(c.Info.Endpoint + path)
115114

116115
r := request.New(httpReq, c.Info, c.Handlers.Copy(), params, data)

client/request/handlers.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/json"
66
"fmt"
77
"io"
8-
"io/ioutil"
98
"net/http"
109
"net/http/httputil"
1110
"net/url"
@@ -138,7 +137,7 @@ func handleSendError(r *Request, err error) {
138137
r.HTTPResponse = &http.Response{
139138
StatusCode: int(code),
140139
Status: http.StatusText(int(code)),
141-
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
140+
Body: io.NopCloser(bytes.NewReader([]byte{})),
142141
}
143142
return
144143
}
@@ -150,7 +149,7 @@ func handleSendError(r *Request, err error) {
150149
r.HTTPResponse = &http.Response{
151150
StatusCode: int(0),
152151
Status: http.StatusText(int(0)),
153-
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
152+
Body: io.NopCloser(bytes.NewReader([]byte{})),
154153
}
155154
}
156155

@@ -173,7 +172,7 @@ var JSONBuilder = Handler{
173172
return
174173
}
175174
r.HTTPRequest.ContentLength = int64(len(raw))
176-
r.HTTPRequest.Body = ioutil.NopCloser(bytes.NewReader(raw))
175+
r.HTTPRequest.Body = io.NopCloser(bytes.NewReader(raw))
177176
}
178177
},
179178
}
@@ -189,7 +188,7 @@ var JSONDecoder = Handler{
189188
defer func() {
190189
// Read the entire body, including any trailing garbage, so
191190
// this connection is in a good state for reuse.
192-
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
191+
io.Copy(io.Discard, r.HTTPResponse.Body)
193192
r.HTTPResponse.Body.Close()
194193
}()
195194
}

counting/probabilistic_counter.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import (
44
"hash/fnv"
55
"math"
66

7-
"github.com/pkg/errors"
87
"github.com/bits-and-blooms/bitset"
8+
"github.com/pkg/errors"
99
)
1010

1111
// ProbabilisticCounter implements an a linear-time counting algorithm, also known as "linear counting".
@@ -20,7 +20,7 @@ import (
2020
// the number of "0" entries). It then estimates the column cardinality by dividing this count by the bit map size m
2121
// (thus obtaining the fraction of empty bit map entries V_n) and plugging the result into the following equation:
2222
//
23-
// n^ = -m * ln V_n (The symbol ^ denotes an estimator)"
23+
// n^ = -m * ln V_n (The symbol ^ denotes an estimator)"
2424
//
2525
// Therefore, ProbabilisticCounter is able to compute an approximate distinct count for a sufficiently large number of
2626
// string values, with an error rate of less than 1.25% on average. It does so while using a very low amount of memory,

example/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package main
22

33
import (
44
"fmt"
5-
"io/ioutil"
5+
"io"
66
"net/http"
77
"time"
88

@@ -101,7 +101,7 @@ func (e *Error) Error() string {
101101

102102
// ip returns your ip.
103103
func ip(ctx context.Context) (string, error) {
104-
req, err := http.NewRequest("GET", "http://api.ipify.org?format=text", nil)
104+
req, err := http.NewRequestWithContext(ctx, "GET", "http://api.ipify.org?format=text", nil)
105105
if err != nil {
106106
return "", err
107107
}
@@ -115,7 +115,7 @@ func ip(ctx context.Context) (string, error) {
115115
resp := val.(*http.Response)
116116
defer resp.Body.Close()
117117

118-
raw, err := ioutil.ReadAll(resp.Body)
118+
raw, err := io.ReadAll(resp.Body)
119119
if err != nil {
120120
return "", err
121121
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/remind101/pkg
22

3-
go 1.24.0
3+
go 1.24.2
44

55
require (
66
cloud.google.com/go/profiler v0.4.2

go1.24.2.linux-arm64.tar.gz

71.3 MB
Binary file not shown.

httpx/error.go

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@ package httpx
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
7+
"fmt"
68
"net/http"
79

8-
"github.com/pkg/errors"
910
"github.com/remind101/pkg/reporter"
1011
)
1112

13+
// Error reports an error and encodes it to the http.ResponseWriter
1214
func Error(ctx context.Context, err error, rw http.ResponseWriter, r *http.Request) {
1315
reporter.Report(ctx, err)
1416
EncodeError(err, rw)
1517
}
1618

19+
// ErrorWithStatus reports an error with a specific status code
20+
func ErrorWithStatus(ctx context.Context, err error, status int, rw http.ResponseWriter, r *http.Request) {
21+
reporter.Report(ctx, err)
22+
EncodeErrorWithStatus(err, status, rw)
23+
}
24+
1725
type temporaryError interface {
1826
Temporary() bool // Is the error temporary?
1927
}
@@ -26,9 +34,15 @@ type statusCoder interface {
2634
StatusCode() int
2735
}
2836

37+
// EncodeError encodes an error to the http.ResponseWriter
2938
func EncodeError(err error, rw http.ResponseWriter) {
39+
EncodeErrorWithStatus(err, ErrorStatusCode(err), rw)
40+
}
41+
42+
// EncodeErrorWithStatus encodes an error with a specific status code
43+
func EncodeErrorWithStatus(err error, status int, rw http.ResponseWriter) {
3044
rw.Header().Set("Content-Type", "application/json")
31-
rw.WriteHeader(ErrorStatusCode(err))
45+
rw.WriteHeader(status)
3246

3347
errorResp := map[string]string{
3448
"error": err.Error(),
@@ -37,18 +51,71 @@ func EncodeError(err error, rw http.ResponseWriter) {
3751
json.NewEncoder(rw).Encode(errorResp)
3852
}
3953

54+
// ErrorStatusCode returns an appropriate HTTP status code based on the error type
4055
func ErrorStatusCode(err error) int {
41-
rootErr := errors.Cause(err)
42-
if e, ok := rootErr.(statusCoder); ok {
43-
return e.StatusCode()
56+
var sc statusCoder
57+
if errors.As(err, &sc) {
58+
return sc.StatusCode()
4459
}
45-
if e, ok := rootErr.(temporaryError); ok && e.Temporary() {
60+
61+
var te temporaryError
62+
if errors.As(err, &te) && te.Temporary() {
4663
return http.StatusServiceUnavailable
4764
}
4865

49-
if e, ok := rootErr.(timeoutError); ok && e.Timeout() {
66+
var to timeoutError
67+
if errors.As(err, &to) && to.Timeout() {
5068
return http.StatusServiceUnavailable
5169
}
5270

5371
return http.StatusInternalServerError
5472
}
73+
74+
// NewError creates a new error with a message and optional key-value pairs
75+
func NewError(msg string, keyvals ...interface{}) error {
76+
return &httpError{
77+
msg: msg,
78+
keyvals: keyvals,
79+
}
80+
}
81+
82+
// httpError is a structured error type that can include key-value pairs
83+
type httpError struct {
84+
msg string
85+
keyvals []interface{}
86+
status int
87+
err error
88+
}
89+
90+
// Error implements the error interface
91+
func (e *httpError) Error() string {
92+
if e.err != nil {
93+
return fmt.Sprintf("%s: %s", e.msg, e.err.Error())
94+
}
95+
return e.msg
96+
}
97+
98+
// WithStatus sets the HTTP status code for the error
99+
func (e *httpError) WithStatus(status int) *httpError {
100+
e.status = status
101+
return e
102+
}
103+
104+
// WithError wraps another error
105+
func (e *httpError) WithError(err error) *httpError {
106+
e.err = err
107+
return e
108+
}
109+
110+
// StatusCode implements the statusCoder interface
111+
func (e *httpError) StatusCode() int {
112+
if e.status != 0 {
113+
return e.status
114+
}
115+
return http.StatusInternalServerError
116+
}
117+
118+
// Unwrap implements the errors.Wrapper interface for Go 1.13+ error unwrapping
119+
func (e *httpError) Unwrap() error {
120+
return e.err
121+
}

0 commit comments

Comments
 (0)