diff --git a/app/start.go b/app/start.go index 17f70c3..9ec5c8c 100644 --- a/app/start.go +++ b/app/start.go @@ -84,6 +84,7 @@ func Start(conf common.Conf, dbO *sqlx.DB) *gin.Engine { gv1.GET("/users/scores/recent", Method(v1.UserScoresRecentGET)) gv1.GET("/badges", Method(v1.BadgesGET)) gv1.GET("/beatmaps", Method(v1.BeatmapGET)) + gv1.GET("/beatmaps/rank_requests/status", Method(v1.BeatmapRankRequestsStatusGET)) gv1.GET("/leaderboard", Method(v1.LeaderboardGET)) gv1.GET("/tokens", Method(v1.TokenGET)) gv1.GET("/users/self", Method(v1.UserSelfGET)) @@ -122,12 +123,12 @@ func Start(conf common.Conf, dbO *sqlx.DB) *gin.Engine { common.PrivilegeManageUser, common.PrivilegeAPIMeta)) // in the new osu-web, the old endpoints are also in /v1 it seems. So /shrug - p.GET("/get_user", PeppyMethod(peppy.GetUser)) - p.GET("/get_match", PeppyMethod(peppy.GetMatch)) - p.GET("/get_user_recent", PeppyMethod(peppy.GetUserRecent)) - p.GET("/get_user_best", PeppyMethod(peppy.GetUserBest)) - p.GET("/get_scores", PeppyMethod(peppy.GetScores)) - p.GET("/get_beatmaps", PeppyMethod(peppy.GetBeatmap)) + gv1.GET("/get_user", PeppyMethod(peppy.GetUser)) + gv1.GET("/get_match", PeppyMethod(peppy.GetMatch)) + gv1.GET("/get_user_recent", PeppyMethod(peppy.GetUserRecent)) + gv1.GET("/get_user_best", PeppyMethod(peppy.GetUserBest)) + gv1.GET("/get_scores", PeppyMethod(peppy.GetScores)) + gv1.GET("/get_beatmaps", PeppyMethod(peppy.GetBeatmap)) } api.GET("/status", internals.Status) diff --git a/app/v1/beatmap_requests.go b/app/v1/beatmap_requests.go new file mode 100644 index 0000000..09c16a5 --- /dev/null +++ b/app/v1/beatmap_requests.go @@ -0,0 +1,55 @@ +package v1 + +import ( + "strconv" + "time" + + "git.zxq.co/ripple/rippleapi/common" +) + +type rankRequestsStatusResponse struct { + common.ResponseBase + QueueSize int `json:"queue_size"` + MaxPeruser int `json:"max_per_user"` + Submitted int `json:"submitted"` + SubmittedByUser int `json:"submitted_by_user"` + CanSubmit bool `json:"can_submit"` + NextExpiration *time.Time `json:"next_expiration"` +} + +// BeatmapRankRequestsStatusGET gets the current status for beatmap ranking requests. +func BeatmapRankRequestsStatusGET(md common.MethodData) common.CodeMessager { + c := common.GetConf() + rows, err := md.DB.Query("SELECT userid, time FROM rank_requests WHERE time > ? ORDER BY id ASC LIMIT "+strconv.Itoa(c.RankQueueSize), time.Now().Add(-time.Hour*24).Unix()) + if err != nil { + md.Err(err) + return Err500 + } + var r rankRequestsStatusResponse + isFirst := true + for rows.Next() { + var ( + user int + timestamp common.UnixTimestamp + ) + err := rows.Scan(&user, ×tamp) + if err != nil { + md.Err(err) + continue + } + if user == md.ID() { + r.SubmittedByUser++ + } + if isFirst { + x := time.Time(timestamp) + r.NextExpiration = &x + isFirst = false + } + r.Submitted++ + } + r.QueueSize = c.RankQueueSize + r.MaxPeruser = c.BeatmapRequestsPerUser + r.CanSubmit = r.Submitted < r.QueueSize && r.SubmittedByUser < r.MaxPeruser + r.Code = 200 + return r +} diff --git a/app/v1/init.go b/app/v1/init.go deleted file mode 100644 index 993a1af..0000000 --- a/app/v1/init.go +++ /dev/null @@ -1,5 +0,0 @@ -package v1 - -func init() { - go removeUseless() -} diff --git a/common/conf.go b/common/conf.go index 2a129f5..73971a4 100644 --- a/common/conf.go +++ b/common/conf.go @@ -13,12 +13,14 @@ var Version string // Conf is the configuration file data for the ripple API. // Conf uses https://github.com/thehowl/conf type Conf struct { - DatabaseType string `description:"At the moment, 'mysql' is the only supported database type."` - DSN string `description:"The Data Source Name for the database. More: https://github.com/go-sql-driver/mysql#dsn-data-source-name"` - ListenTo string `description:"The IP/Port combination from which to take connections, e.g. :8080"` - Unix bool `description:"Bool indicating whether ListenTo is a UNIX socket or an address."` - SentryDSN string `description:"thing for sentry whatever"` - HanayoKey string + DatabaseType string `description:"At the moment, 'mysql' is the only supported database type."` + DSN string `description:"The Data Source Name for the database. More: https://github.com/go-sql-driver/mysql#dsn-data-source-name"` + ListenTo string `description:"The IP/Port combination from which to take connections, e.g. :8080"` + Unix bool `description:"Bool indicating whether ListenTo is a UNIX socket or an address."` + SentryDSN string `description:"thing for sentry whatever"` + HanayoKey string + BeatmapRequestsPerUser int + RankQueueSize int } var cachedConf *Conf @@ -33,14 +35,26 @@ func Load() (c Conf, halt bool) { halt = err == conf.ErrNoFile if halt { conf.MustExport(Conf{ - DatabaseType: "mysql", - DSN: "root@/ripple", - ListenTo: ":40001", - Unix: false, - HanayoKey: "Potato", + DatabaseType: "mysql", + DSN: "root@/ripple", + ListenTo: ":40001", + Unix: false, + HanayoKey: "Potato", + BeatmapRequestsPerUser: 2, + RankQueueSize: 25, }, "api.conf") fmt.Println("Please compile the configuration file (api.conf).") } cachedConf = &c return } + +// GetConf returns the cachedConf. +func GetConf() *Conf { + if cachedConf == nil { + return nil + } + // so that the cachedConf cannot actually get modified + c := *cachedConf + return &c +}