bump go modules, fix StartTLS email notifications
In #1359, we discovered that StartTLS was not working\ due to the wrong host passed. This bumps the library for the fix. Also, after a switch to go-pkgz/notify MailGun email sending broke due to the difference in the destination email parsing, the fix is also applied after this commit.
This commit is contained in:
committed by
Umputun
parent
9049d7a616
commit
3b5f44da46
+1
@@ -32,6 +32,7 @@ func (l *limiterWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
default:
|
||||
httpError := tollbooth.LimitByRequest(l.lmt, w, r)
|
||||
if httpError != nil {
|
||||
l.lmt.ExecOnLimitReached(w, r)
|
||||
w.Header().Add("Content-Type", l.lmt.GetMessageContentType())
|
||||
w.WriteHeader(httpError.StatusCode)
|
||||
w.Write([]byte(httpError.Message))
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ func parseHeaderList(headerList string) []string {
|
||||
} else {
|
||||
h = append(h, b)
|
||||
}
|
||||
} else if b == '-' || (b >= '0' && b <= '9') {
|
||||
} else if b == '-' || b == '_' || b == '.' || (b >= '0' && b <= '9') {
|
||||
h = append(h, b)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -190,7 +190,7 @@ func (em *Sender) client() (c *smtp.Client, err error) {
|
||||
return nil, fmt.Errorf("timeout connecting to %s: %w", srvAddress, err)
|
||||
}
|
||||
|
||||
c, err = smtp.NewClient(conn, srvAddress)
|
||||
c, err = smtp.NewClient(conn, em.host)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to dial: %w", err)
|
||||
}
|
||||
|
||||
+10
-1
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-pkgz/email"
|
||||
@@ -99,6 +100,9 @@ func (e *Email) String() string {
|
||||
if e.TLS {
|
||||
str += " with TLS"
|
||||
}
|
||||
if e.StartTLS {
|
||||
str += " with StartTLS"
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
@@ -120,7 +124,12 @@ func (e *Email) parseDestination(destination string) (email.Params, error) {
|
||||
}
|
||||
destinations := []string{}
|
||||
for _, addr := range addresses {
|
||||
destinations = append(destinations, addr.String())
|
||||
stringAddr := addr.String()
|
||||
// in case of mailgun, correct RFC5322 address with <> yield 501 error, so we need to remove brackets
|
||||
if strings.HasPrefix(stringAddr, "<") && strings.HasSuffix(stringAddr, ">") {
|
||||
stringAddr = stringAddr[1 : len(stringAddr)-1]
|
||||
}
|
||||
destinations = append(destinations, stringAddr)
|
||||
}
|
||||
|
||||
return email.Params{
|
||||
|
||||
+1
@@ -449,6 +449,7 @@ func (t *Telegram) Request(ctx context.Context, method string, b []byte, data in
|
||||
}
|
||||
|
||||
client := http.Client{Timeout: t.Timeout}
|
||||
defer client.CloseIdleConnections()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send request: %w", err)
|
||||
|
||||
+6
@@ -119,6 +119,12 @@ Maybe middleware will allow you to change the flow of the middleware stack execu
|
||||
value of maybeFn(request). This is useful for example if you'd like to skip a middleware handler if
|
||||
a request does not satisfy the maybeFn logic.
|
||||
|
||||
### Benchmarks middleware
|
||||
|
||||
Benchmarks middleware allows to measure the time of request handling, number of request per second and report aggregated metrics. This middleware keeps track of the request in the memory and keep up to 900 points (15 minutes, data-point per second).
|
||||
|
||||
In order to retrieve the data user should call `Stats(d duration)` method. duration is the time window for which the benchmark data should be returned. It can be any duration from 1s to 15m.
|
||||
|
||||
## Helpers
|
||||
|
||||
- `rest.Wrap` - converts a list of middlewares to nested handlers calls (in reverse order)
|
||||
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var maxTimeRange = time.Duration(15) * time.Minute
|
||||
|
||||
// Benchmarks is a basic benchmarking middleware collecting and reporting performance metrics
|
||||
// It keeps track of the requests speeds and counts in 1s benchData buckets ,limiting the number of buckets
|
||||
// to maxTimeRange. User can request the benchmark for any time duration. This is intended to be used
|
||||
// for retrieving the benchmark data for the last minute, 5 minutes and up to maxTimeRange.
|
||||
type Benchmarks struct {
|
||||
st time.Time
|
||||
data *list.List
|
||||
lock sync.RWMutex
|
||||
|
||||
nowFn func() time.Time // for testing only
|
||||
}
|
||||
|
||||
type benchData struct {
|
||||
// 1s aggregates
|
||||
requests int
|
||||
respTime time.Duration
|
||||
minRespTime time.Duration
|
||||
maxRespTime time.Duration
|
||||
ts time.Time
|
||||
}
|
||||
|
||||
// BenchmarkStats holds the stats for a given interval
|
||||
type BenchmarkStats struct {
|
||||
Requests int `json:"total_requests"`
|
||||
RequestsSec float64 `json:"total_requests_sec"`
|
||||
AverageRespTime float64 `json:"average_resp_time"`
|
||||
MinRespTime float64 `json:"min_resp_time"`
|
||||
MaxRespTime float64 `json:"max_resp_time"`
|
||||
}
|
||||
|
||||
// NewBenchmarks creates a new benchmark middleware
|
||||
func NewBenchmarks() *Benchmarks {
|
||||
res := &Benchmarks{
|
||||
st: time.Now(),
|
||||
data: list.New(),
|
||||
nowFn: time.Now,
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Handler calculates 1/5/10m request per second and allows to access those values
|
||||
func (b *Benchmarks) Handler(next http.Handler) http.Handler {
|
||||
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
st := b.nowFn()
|
||||
defer func() {
|
||||
b.update(time.Since(st))
|
||||
}()
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
func (b *Benchmarks) update(reqDuration time.Duration) {
|
||||
now := b.nowFn().Truncate(time.Second)
|
||||
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
// keep maxTimeRange in the list, drop the rest
|
||||
for e := b.data.Front(); e != nil; e = e.Next() {
|
||||
if b.data.Front().Value.(benchData).ts.After(b.nowFn().Add(-maxTimeRange)) {
|
||||
break
|
||||
}
|
||||
b.data.Remove(b.data.Front())
|
||||
}
|
||||
|
||||
last := b.data.Back()
|
||||
if last == nil || last.Value.(benchData).ts.Before(now) {
|
||||
b.data.PushBack(benchData{requests: 1, respTime: reqDuration, ts: now,
|
||||
minRespTime: reqDuration, maxRespTime: reqDuration})
|
||||
return
|
||||
}
|
||||
|
||||
bd := last.Value.(benchData)
|
||||
bd.requests++
|
||||
bd.respTime += reqDuration
|
||||
|
||||
if bd.minRespTime == 0 || reqDuration < bd.minRespTime {
|
||||
bd.minRespTime = reqDuration
|
||||
}
|
||||
if bd.maxRespTime == 0 || reqDuration > bd.maxRespTime {
|
||||
bd.maxRespTime = reqDuration
|
||||
}
|
||||
|
||||
last.Value = bd
|
||||
}
|
||||
|
||||
// Stats returns the current benchmark stats for the given duration
|
||||
func (b *Benchmarks) Stats(interval time.Duration) BenchmarkStats {
|
||||
if interval < time.Second { // minimum interval is 1s due to the bucket size
|
||||
return BenchmarkStats{}
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
var (
|
||||
requests int
|
||||
respTime time.Duration
|
||||
)
|
||||
|
||||
stInterval, fnInterval := time.Time{}, time.Time{}
|
||||
var minRespTime, maxRespTime time.Duration
|
||||
for e := b.data.Back(); e != nil; e = e.Prev() { // reverse order
|
||||
bd := e.Value.(benchData)
|
||||
if bd.ts.Before(b.nowFn().Add(-interval)) {
|
||||
break
|
||||
}
|
||||
if minRespTime == 0 || bd.minRespTime < minRespTime {
|
||||
minRespTime = bd.minRespTime
|
||||
}
|
||||
if maxRespTime == 0 || bd.maxRespTime > maxRespTime {
|
||||
maxRespTime = bd.maxRespTime
|
||||
}
|
||||
requests += bd.requests
|
||||
respTime += bd.respTime
|
||||
if fnInterval.IsZero() {
|
||||
fnInterval = bd.ts.Add(time.Second)
|
||||
}
|
||||
stInterval = bd.ts
|
||||
}
|
||||
|
||||
if requests == 0 {
|
||||
return BenchmarkStats{}
|
||||
}
|
||||
|
||||
return BenchmarkStats{
|
||||
Requests: requests,
|
||||
RequestsSec: float64(requests) / (fnInterval.Sub(stInterval).Seconds()),
|
||||
AverageRespTime: respTime.Seconds() / float64(requests),
|
||||
MinRespTime: minRespTime.Seconds(),
|
||||
MaxRespTime: maxRespTime.Seconds(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user