Add back old middlewares
This commit is contained in:
parent
736c904f65
commit
490d13e333
|
@ -3,6 +3,7 @@ package app
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"unsafe"
|
||||
|
||||
|
@ -114,3 +115,17 @@ func mkjson(c *fasthttp.RequestCtx, data interface{}) {
|
|||
func b2s(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// s2b converts string to a byte slice without memory allocation.
|
||||
//
|
||||
// Note it may break if string and/or slice header will change
|
||||
// in the future go versions.
|
||||
func s2b(s string) []byte {
|
||||
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
bh := reflect.SliceHeader{
|
||||
Data: sh.Data,
|
||||
Len: sh.Len,
|
||||
Cap: sh.Len,
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&bh))
|
||||
}
|
||||
|
|
104
app/recovery.go
104
app/recovery.go
|
@ -1,104 +0,0 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
raven "github.com/getsentry/raven-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Recovery is a better sentry logger.
|
||||
func Recovery(client *raven.Client, onlyCrashes bool) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var requestBody []byte
|
||||
|
||||
defer func() {
|
||||
st := raven.NewStacktrace(0, 3, []string{"zxq.co/ripple"})
|
||||
|
||||
tokenRaw, ex := c.Get("token")
|
||||
var token string
|
||||
if ex {
|
||||
token = tokenRaw.(string)
|
||||
}
|
||||
|
||||
ravenHTTP := raven.NewHttp(c.Request)
|
||||
if len(requestBody) != 0 {
|
||||
ravenHTTP.Data = string(requestBody)
|
||||
}
|
||||
|
||||
ravenUser := &raven.User{
|
||||
Username: token,
|
||||
IP: c.Request.RemoteAddr,
|
||||
}
|
||||
|
||||
flags := map[string]string{
|
||||
"endpoint": c.Request.RequestURI,
|
||||
"token": token,
|
||||
}
|
||||
|
||||
if rval := recover(); rval != nil {
|
||||
var err error
|
||||
switch rval := rval.(type) {
|
||||
case string:
|
||||
err = errors.New(rval)
|
||||
case error:
|
||||
err = rval
|
||||
default:
|
||||
err = fmt.Errorf("%v - %#v", rval, rval)
|
||||
}
|
||||
fmt.Println(err)
|
||||
client.CaptureError(
|
||||
err,
|
||||
flags,
|
||||
st,
|
||||
ravenHTTP,
|
||||
ravenUser,
|
||||
)
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
}
|
||||
if !onlyCrashes {
|
||||
for _, item := range c.Errors {
|
||||
var err = error(item)
|
||||
if item.Type == gin.ErrorTypePrivate {
|
||||
err = item.Err
|
||||
}
|
||||
fmt.Println(err)
|
||||
client.CaptureError(
|
||||
err,
|
||||
flags,
|
||||
ravenHTTP,
|
||||
ravenUser,
|
||||
)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if c.Request.Method == "POST" && c.Request.URL.Path != "/tokens" &&
|
||||
c.Request.URL.Path != "/tokens/new" {
|
||||
var err error
|
||||
requestBody, err = ioutil.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
c.Error(err)
|
||||
}
|
||||
c.Request.Body = fakeBody{
|
||||
r: bytes.NewReader(requestBody),
|
||||
orig: c.Request.Body,
|
||||
}
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
type fakeBody struct {
|
||||
r io.Reader
|
||||
orig io.ReadCloser
|
||||
}
|
||||
|
||||
func (f fakeBody) Read(p []byte) (int, error) { return f.r.Read(p) }
|
||||
func (f fakeBody) Close() error { return f.orig.Close() }
|
|
@ -1,6 +1,11 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/buaazp/fasthttprouter"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/valyala/fasthttp"
|
||||
|
@ -12,14 +17,85 @@ type router struct {
|
|||
}
|
||||
|
||||
func (r router) Method(path string, f func(md common.MethodData) common.CodeMessager, privilegesNeeded ...int) {
|
||||
r.r.GET(path, Method(f, privilegesNeeded...))
|
||||
r.r.GET(path, wrap(Method(f, privilegesNeeded...)))
|
||||
}
|
||||
func (r router) POSTMethod(path string, f func(md common.MethodData) common.CodeMessager, privilegesNeeded ...int) {
|
||||
r.r.POST(path, Method(f, privilegesNeeded...))
|
||||
r.r.POST(path, wrap(Method(f, privilegesNeeded...)))
|
||||
}
|
||||
func (r router) Peppy(path string, a func(c *fasthttp.RequestCtx, db *sqlx.DB)) {
|
||||
r.r.GET(path, PeppyMethod(a))
|
||||
r.r.GET(path, wrap(PeppyMethod(a)))
|
||||
}
|
||||
func (r router) GET(path string, handle fasthttp.RequestHandler) {
|
||||
r.r.GET(path, handle)
|
||||
r.r.GET(path, wrap(handle))
|
||||
}
|
||||
|
||||
const (
|
||||
// \x1b is escape code for ESC
|
||||
// <ESC>[<n>m is escape sequence for a certain colour
|
||||
// no IP is written out because of the hundreds of possible ways to pass IPs
|
||||
// to a request when using a reverse proxy
|
||||
// this is partly inspired from gin, though made even more simplistic.
|
||||
fmtString = "%s | %15s |\x1b[%sm %3d \x1b[0m %-7s %s\n"
|
||||
// a kind of human readable RFC3339
|
||||
timeFormat = "2006-01-02 15:04:05"
|
||||
// color reference
|
||||
// http://misc.flogisoft.com/bash/tip_colors_and_formatting
|
||||
colorOk = "42" // green
|
||||
colorError = "41" // red
|
||||
)
|
||||
|
||||
// wrap returns a function that wraps around handle, providing middleware
|
||||
// functionality to apply to all API calls, which is to say:
|
||||
// - logging
|
||||
// - panic recovery (reporting to sentry)
|
||||
// - gzipping
|
||||
func wrap(handle fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||
return func(c *fasthttp.RequestCtx) {
|
||||
start := time.Now()
|
||||
|
||||
defer func() {
|
||||
if rval := recover(); rval != nil {
|
||||
var err error
|
||||
switch rval := rval.(type) {
|
||||
case string:
|
||||
err = errors.New(rval)
|
||||
case error:
|
||||
err = rval
|
||||
default:
|
||||
err = fmt.Errorf("%v - %#v", rval, rval)
|
||||
}
|
||||
common.Err(c, err)
|
||||
c.SetStatusCode(500)
|
||||
c.SetBodyString(`{ "code": 500, "message": "something really bad happened" }`)
|
||||
}
|
||||
|
||||
// switch color to colorError if statusCode is in [500;600)
|
||||
color := colorOk
|
||||
statusCode := c.Response.StatusCode()
|
||||
if statusCode >= 500 && statusCode < 600 {
|
||||
color = colorError
|
||||
}
|
||||
|
||||
if bytes.Contains(c.Request.Header.Peek("Accept-Encoding"), s2b("gzip")) {
|
||||
c.Response.Header.Add("Content-Encoding", "gzip")
|
||||
c.Response.Header.Add("Vary", "Accept-Encoding")
|
||||
b := c.Response.Body()
|
||||
c.Response.ResetBody()
|
||||
fasthttp.WriteGzip(c.Response.BodyWriter(), b)
|
||||
}
|
||||
|
||||
// print stuff
|
||||
fmt.Printf(
|
||||
fmtString,
|
||||
time.Now().Format(timeFormat),
|
||||
time.Since(start).String(),
|
||||
color,
|
||||
statusCode,
|
||||
c.Method(),
|
||||
c.Path(),
|
||||
)
|
||||
}()
|
||||
|
||||
handle(c)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,8 @@ var randomSentences = [...]string{
|
|||
}
|
||||
|
||||
func surpriseMe() string {
|
||||
return randomSentences[rn.Intn(len(randomSentences))] + " " + kaomojis[rn.Intn(len(kaomojis))]
|
||||
n := int(time.Now().UnixNano())
|
||||
return randomSentences[n%len(randomSentences)] + " " + kaomojis[n%len(kaomojis)]
|
||||
}
|
||||
|
||||
type pingResponse struct {
|
||||
|
|
|
@ -47,36 +47,30 @@ func (md MethodData) ClientIP() string {
|
|||
// Err logs an error. If RavenClient is set, it will use the client to report
|
||||
// the error to sentry, otherwise it will just write the error to stdout.
|
||||
func (md MethodData) Err(err error) {
|
||||
if RavenClient == nil {
|
||||
fmt.Println("ERROR!!!!")
|
||||
fmt.Println(err)
|
||||
return
|
||||
user := &raven.User{
|
||||
ID: strconv.Itoa(md.User.UserID),
|
||||
Username: md.User.Value,
|
||||
IP: md.Ctx.RemoteAddr().String(),
|
||||
}
|
||||
|
||||
// Create stacktrace
|
||||
st := raven.NewStacktrace(0, 3, []string{"zxq.co/ripple", "git.zxq.co/ripple"})
|
||||
|
||||
// Generate tags for error
|
||||
tags := map[string]string{
|
||||
"endpoint": b2s(md.Ctx.RequestURI()),
|
||||
"endpoint": string(md.Ctx.RequestURI()),
|
||||
"token": md.User.Value,
|
||||
}
|
||||
|
||||
RavenClient.CaptureError(
|
||||
err,
|
||||
tags,
|
||||
st,
|
||||
generateRavenHTTP(md.Ctx),
|
||||
&raven.User{
|
||||
ID: strconv.Itoa(md.User.UserID),
|
||||
Username: md.User.Value,
|
||||
IP: md.Ctx.RemoteAddr().String(),
|
||||
},
|
||||
)
|
||||
_err(err, tags, user, md.Ctx)
|
||||
}
|
||||
|
||||
// Err for peppy API calls
|
||||
func Err(c *fasthttp.RequestCtx, err error) {
|
||||
// Generate tags for error
|
||||
tags := map[string]string{
|
||||
"endpoint": string(c.RequestURI()),
|
||||
}
|
||||
|
||||
_err(err, tags, nil, c)
|
||||
}
|
||||
|
||||
func _err(err error, tags map[string]string, user *raven.User, c *fasthttp.RequestCtx) {
|
||||
if RavenClient == nil {
|
||||
fmt.Println("ERROR!!!!")
|
||||
fmt.Println(err)
|
||||
|
@ -86,16 +80,15 @@ func Err(c *fasthttp.RequestCtx, err error) {
|
|||
// Create stacktrace
|
||||
st := raven.NewStacktrace(0, 3, []string{"zxq.co/ripple", "git.zxq.co/ripple"})
|
||||
|
||||
// Generate tags for error
|
||||
tags := map[string]string{
|
||||
"endpoint": b2s(c.RequestURI()),
|
||||
ifaces := []raven.Interface{st, generateRavenHTTP(c)}
|
||||
if user != nil {
|
||||
ifaces = append(ifaces, user)
|
||||
}
|
||||
|
||||
RavenClient.CaptureError(
|
||||
err,
|
||||
tags,
|
||||
st,
|
||||
generateRavenHTTP(c),
|
||||
ifaces...,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user