Move to fasthttp for improved performance

This commit is contained in:
Morgan Bazalgette
2017-02-02 13:40:28 +01:00
parent ace2fded7e
commit 85e6dc7e5e
26 changed files with 448 additions and 380 deletions

View File

@@ -1,8 +1,10 @@
package v1
import (
"encoding/json"
"github.com/valyala/fasthttp"
"zxq.co/ripple/rippleapi/common"
"github.com/gin-gonic/gin"
)
type response404 struct {
@@ -11,12 +13,17 @@ type response404 struct {
}
// Handle404 handles requests with no implemented handlers.
func Handle404(c *gin.Context) {
c.Header("X-Real-404", "yes")
c.IndentedJSON(404, response404{
func Handle404(c *fasthttp.RequestCtx) {
c.Response.Header.Add("X-Real-404", "yes")
data, err := json.MarshalIndent(response404{
ResponseBase: common.ResponseBase{
Code: 404,
},
Cats: surpriseMe(),
})
}, "", "\t")
if err != nil {
panic(err)
}
c.SetStatusCode(404)
c.Write(data)
}

View File

@@ -2,8 +2,6 @@ package v1
import (
"database/sql"
"fmt"
"net/url"
"zxq.co/ripple/rippleapi/common"
)
@@ -51,10 +49,10 @@ type beatmapSetStatusData struct {
// the beatmap ranked status is frozen. Or freezed. Freezed best meme 2k16
func BeatmapSetStatusPOST(md common.MethodData) common.CodeMessager {
var req beatmapSetStatusData
md.RequestData.Unmarshal(&req)
md.Unmarshal(&req)
var miss []string
if req.BeatmapsetID == 0 && req.BeatmapID == 0 {
if req.BeatmapsetID <= 0 && req.BeatmapID <= 0 {
miss = append(miss, "beatmapset_id or beatmap_id")
}
if len(miss) != 0 {
@@ -84,32 +82,14 @@ func BeatmapSetStatusPOST(md common.MethodData) common.CodeMessager {
SET ranked = ?, ranked_status_freezed = ?
WHERE beatmapset_id = ?`, req.RankedStatus, req.Frozen, param)
var x = make(map[string]interface{}, 1)
if req.BeatmapID != 0 {
x["bb"] = req.BeatmapID
if req.BeatmapID > 0 {
md.Ctx.Request.URI().QueryArgs().SetUint("bb", req.BeatmapID)
} else {
x["s"] = req.BeatmapsetID
md.Ctx.Request.URI().QueryArgs().SetUint("s", req.BeatmapsetID)
}
md.C.Request.URL = genURL(x)
return getMultipleBeatmaps(md)
}
func genURL(d map[string]interface{}) *url.URL {
var s string
for k, v := range d {
if s != "" {
s += "&"
}
s += k + "=" + url.QueryEscape(fmt.Sprintf("%v", v))
}
u := new(url.URL)
if len(d) == 0 {
return u
}
u.RawQuery = s
return u
}
// BeatmapGET retrieves a beatmap.
func BeatmapGET(md common.MethodData) common.CodeMessager {
beatmapID := common.Int(md.Query("b"))

View File

@@ -78,7 +78,7 @@ type submitRequestData struct {
// BeatmapRankRequestsSubmitPOST submits a new beatmap for ranking approval.
func BeatmapRankRequestsSubmitPOST(md common.MethodData) common.CodeMessager {
var d submitRequestData
err := md.RequestData.Unmarshal(&d)
err := md.Unmarshal(&d)
if err != nil {
return ErrBadJSON
}
@@ -91,9 +91,6 @@ func BeatmapRankRequestsSubmitPOST(md common.MethodData) common.CodeMessager {
if !limit.NonBlockingRequest("rankrequest:u:"+strconv.Itoa(md.ID()), 5) {
return common.SimpleResponse(429, "You may only try to request 5 beatmaps per minute.")
}
if !limit.NonBlockingRequest("rankrequest:ip:"+md.C.ClientIP(), 8) {
return common.SimpleResponse(429, "You may only try to request 8 beatmaps per minute from the same IP.")
}
// find out from BeatmapRankRequestsStatusGET if we can submit beatmaps.
statusRaw := BeatmapRankRequestsStatusGET(md)

View File

@@ -134,7 +134,7 @@ func FriendsAddPOST(md common.MethodData) common.CodeMessager {
var u struct {
User int `json:"user"`
}
md.RequestData.Unmarshal(&u)
md.Unmarshal(&u)
return addFriend(md, u.User)
}
@@ -183,7 +183,7 @@ func FriendsDelPOST(md common.MethodData) common.CodeMessager {
var u struct {
User int `json:"user"`
}
md.RequestData.Unmarshal(&u)
md.Unmarshal(&u)
return delFriend(md, u.User)
}

View File

@@ -14,7 +14,7 @@ type setAllowedData struct {
// UserManageSetAllowedPOST allows to set the allowed status of an user.
func UserManageSetAllowedPOST(md common.MethodData) common.CodeMessager {
data := setAllowedData{}
if err := md.RequestData.Unmarshal(&data); err != nil {
if err := md.Unmarshal(&data); err != nil {
return ErrBadJSON
}
if data.Allowed < 0 || data.Allowed > 2 {

View File

@@ -62,7 +62,7 @@ type userSettingsData struct {
// UsersSelfSettingsPOST allows to modify information about the current user.
func UsersSelfSettingsPOST(md common.MethodData) common.CodeMessager {
var d userSettingsData
md.RequestData.Unmarshal(&d)
md.Unmarshal(&d)
// input sanitisation
*d.UsernameAKA = common.SanitiseString(*d.UsernameAKA)

View File

@@ -8,10 +8,10 @@ import (
"github.com/jmoiron/sqlx"
"golang.org/x/crypto/bcrypt"
"zxq.co/ripple/rippleapi/common"
"zxq.co/ripple/rippleapi/limit"
"zxq.co/ripple/schiavolib"
"golang.org/x/crypto/bcrypt"
)
type tokenNewInData struct {
@@ -37,7 +37,7 @@ type tokenNewResponse struct {
func TokenNewPOST(md common.MethodData) common.CodeMessager {
var r tokenNewResponse
data := tokenNewInData{}
err := md.RequestData.Unmarshal(&data)
err := md.Unmarshal(&data)
if err != nil {
return ErrBadJSON
}
@@ -80,7 +80,7 @@ func TokenNewPOST(md common.MethodData) common.CodeMessager {
}
privileges := common.UserPrivileges(privilegesRaw)
if !limit.NonBlockingRequest(fmt.Sprintf("loginattempt:%d:%s", r.ID, md.C.ClientIP()), 5) {
if !limit.NonBlockingRequest(fmt.Sprintf("loginattempt:%d:%s", r.ID, md.ClientIP()), 5) {
return common.SimpleResponse(429, "You've made too many login attempts. Try again later.")
}

View File

@@ -5,9 +5,9 @@ import (
"database/sql"
"strconv"
"strings"
"unicode"
"github.com/jmoiron/sqlx"
"zxq.co/ripple/ocl"
"zxq.co/ripple/rippleapi/common"
)
@@ -71,8 +71,7 @@ type userPutsMultiUserData struct {
}
func userPutsMulti(md common.MethodData) common.CodeMessager {
q := md.C.Request.URL.Query()
pm := md.Ctx.Request.URI().QueryArgs().PeekMulti
// query composition
wh := common.
Where("users.username_safe = ?", common.SafeUsername(md.Query("nname"))).
@@ -83,10 +82,10 @@ func userPutsMulti(md common.MethodData) common.CodeMessager {
Where("users_stats.country = ?", md.Query("country")).
Where("users_stats.username_aka = ?", md.Query("name_aka")).
Where("privileges_groups.name = ?", md.Query("privilege_group")).
In("users.id", q["ids"]...).
In("users.username_safe", safeUsernameBulk(q["names"])...).
In("users_stats.username_aka", q["names_aka"]...).
In("users_stats.country", q["countries"]...)
In("users.id", pm("ids")...).
In("users.username_safe", safeUsernameBulk(pm("names"))...).
In("users_stats.username_aka", pm("names_aka")...).
In("users_stats.country", pm("countries")...)
var extraJoin string
if md.Query("privilege_group") != "" {
@@ -130,13 +129,19 @@ func userPutsMulti(md common.MethodData) common.CodeMessager {
// UserSelfGET is a shortcut for /users/id/self. (/users/self)
func UserSelfGET(md common.MethodData) common.CodeMessager {
md.C.Request.URL.RawQuery = "id=self&" + md.C.Request.URL.RawQuery
md.Ctx.Request.URI().SetQueryString("id=self")
return UsersGET(md)
}
func safeUsernameBulk(us []string) []string {
for i, u := range us {
us[i] = common.SafeUsername(u)
func safeUsernameBulk(us [][]byte) [][]byte {
for _, u := range us {
for idx, v := range u {
if v == ' ' {
u[idx] = '_'
continue
}
u[idx] = byte(unicode.ToLower(rune(v)))
}
}
return us
}
@@ -341,7 +346,7 @@ func UserSelfUserpagePOST(md common.MethodData) common.CodeMessager {
var d struct {
Data *string `json:"data"`
}
md.RequestData.Unmarshal(&d)
md.Unmarshal(&d)
if d.Data == nil {
return ErrMissingField("data")
}
@@ -350,7 +355,7 @@ func UserSelfUserpagePOST(md common.MethodData) common.CodeMessager {
if err != nil {
md.Err(err)
}
md.C.Request.URL.RawQuery += "&id=" + strconv.Itoa(md.ID())
md.Ctx.URI().SetQueryString("id=self")
return UserUserpageGET(md)
}