nightingale/http/http_funcs.go

426 lines
8.0 KiB
Go

package http
import (
"fmt"
"net/http"
"strconv"
"strings"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/didi/nightingale/v5/models"
"github.com/didi/nightingale/v5/pkg/i18n"
"github.com/didi/nightingale/v5/pkg/ierr"
)
const defaultLimit = 20
func _e(format string, a ...interface{}) error {
return fmt.Errorf(_s(format, a...))
}
func _s(format string, a ...interface{}) string {
return i18n.Sprintf(format, a...)
}
func dangerous(v interface{}, code ...int) {
ierr.Dangerous(v, code...)
}
func bomb(code int, format string, a ...interface{}) {
ierr.Bomb(code, _s(format, a...))
}
func bind(c *gin.Context, ptr interface{}) {
dangerous(c.ShouldBindJSON(ptr), http.StatusBadRequest)
}
func urlParamStr(c *gin.Context, field string) string {
val := c.Param(field)
if val == "" {
bomb(http.StatusBadRequest, "url param[%s] is blank", field)
}
return val
}
func urlParamInt64(c *gin.Context, field string) int64 {
strval := urlParamStr(c, field)
intval, err := strconv.ParseInt(strval, 10, 64)
if err != nil {
bomb(http.StatusBadRequest, "cannot convert %s to int64", strval)
}
return intval
}
func urlParamInt(c *gin.Context, field string) int {
return int(urlParamInt64(c, field))
}
func queryStr(c *gin.Context, key string, defaultVal ...string) string {
val := c.Query(key)
if val != "" {
return val
}
if len(defaultVal) == 0 {
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
}
return defaultVal[0]
}
func queryInt(c *gin.Context, key string, defaultVal ...int) int {
strv := c.Query(key)
if strv != "" {
intv, err := strconv.Atoi(strv)
if err != nil {
bomb(http.StatusBadRequest, "cannot convert [%s] to int", strv)
}
return intv
}
if len(defaultVal) == 0 {
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
}
return defaultVal[0]
}
func queryInt64(c *gin.Context, key string, defaultVal ...int64) int64 {
strv := c.Query(key)
if strv != "" {
intv, err := strconv.ParseInt(strv, 10, 64)
if err != nil {
bomb(http.StatusBadRequest, "cannot convert [%s] to int64", strv)
}
return intv
}
if len(defaultVal) == 0 {
bomb(http.StatusBadRequest, "query param[%s] is necessary", key)
}
return defaultVal[0]
}
func queryBool(c *gin.Context, key string, defaultVal ...bool) bool {
strv := c.Query(key)
if strv != "" {
if strv == "true" || strv == "1" || strv == "on" || strv == "checked" || strv == "yes" || strv == "Y" {
return true
} else if strv == "false" || strv == "0" || strv == "off" || strv == "no" || strv == "N" {
return false
} else {
bomb(http.StatusBadRequest, "unknown arg[%s] value: %s", key, strv)
}
}
if len(defaultVal) == 0 {
bomb(http.StatusBadRequest, "arg[%s] is necessary", key)
}
return defaultVal[0]
}
func offset(c *gin.Context, limit int) int {
if limit <= 0 {
limit = 10
}
page := queryInt(c, "p", 1)
return (page - 1) * limit
}
func renderMessage(c *gin.Context, v interface{}, statusCode ...int) {
code := 200
if len(statusCode) > 0 {
code = statusCode[0]
}
if v == nil {
c.JSON(code, gin.H{"err": ""})
return
}
switch t := v.(type) {
case string:
c.JSON(code, gin.H{"err": _s(t)})
case error:
c.JSON(code, gin.H{"err": t.Error()})
}
}
func renderData(c *gin.Context, data interface{}, err error, statusCode ...int) {
code := 200
if len(statusCode) > 0 {
code = statusCode[0]
}
if err == nil {
c.JSON(code, gin.H{"dat": data, "err": ""})
return
}
renderMessage(c, err.Error(), code)
}
func renderZeroPage(c *gin.Context) {
renderData(c, gin.H{
"list": []int{},
"total": 0,
}, nil)
}
type idsForm struct {
Ids []int64 `json:"ids"`
}
func (f idsForm) Validate() {
if len(f.Ids) == 0 {
bomb(http.StatusBadRequest, "ids empty")
}
}
func cookieUsername(c *gin.Context) string {
session := sessions.Default(c)
value := session.Get("username")
if value == nil {
return ""
}
return value.(string)
}
func headerUsername(c *gin.Context) string {
token := c.GetHeader("Authorization")
if token == "" {
return ""
}
ut, err := models.UserTokenGet("token=?", strings.TrimPrefix(token, "Bearer "))
if err != nil {
return ""
}
if ut == nil {
return ""
}
return ut.Username
}
// must get username
func loginUsername(c *gin.Context) string {
usernameInterface, has := c.Get("username")
if has {
return usernameInterface.(string)
}
username := cookieUsername(c)
if username == "" {
username = headerUsername(c)
}
if username == "" {
remoteAddr := c.Request.RemoteAddr
idx := strings.LastIndex(remoteAddr, ":")
ip := ""
if idx > 0 {
ip = remoteAddr[0:idx]
}
if ip == "127.0.0.1" {
//本地调用都当成是root用户在调用
username = "root"
}
}
if username == "" {
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
}
c.Set("username", username)
return username
}
func loginUser(c *gin.Context) *models.User {
username := loginUsername(c)
user, err := models.UserGetByUsername(username)
dangerous(err)
if user == nil {
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
}
if user.Status == 1 {
ierr.Bomb(http.StatusUnauthorized, "unauthorized")
}
return user
}
func User(id int64) *models.User {
obj, err := models.UserGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such user")
}
return obj
}
func UserGroup(id int64) *models.UserGroup {
obj, err := models.UserGroupGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such user group")
}
return obj
}
func Classpath(id int64) *models.Classpath {
obj, err := models.ClasspathGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such classpath")
}
return obj
}
func Mute(id int64) *models.Mute {
obj, err := models.MuteGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such mute config")
}
return obj
}
func Dashboard(id int64) *models.Dashboard {
obj, err := models.DashboardGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such dashboard")
}
return obj
}
func ChartGroup(id int64) *models.ChartGroup {
obj, err := models.ChartGroupGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such chart group")
}
return obj
}
func Chart(id int64) *models.Chart {
obj, err := models.ChartGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such chart")
}
return obj
}
func AlertRule(id int64) *models.AlertRule {
obj, err := models.AlertRuleGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such alert rule")
}
return obj
}
func AlertRuleGroup(id int64) *models.AlertRuleGroup {
obj, err := models.AlertRuleGroupGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such alert rule group")
}
return obj
}
func AlertEvent(id int64) *models.AlertEvent {
obj, err := models.AlertEventGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such alert event")
}
return obj
}
func HistoryAlertEvent(id int64) *models.HistoryAlertEvent {
obj, err := models.HistoryAlertEventGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such alert all event")
}
return obj
}
func CollectRule(id int64) *models.CollectRule {
obj, err := models.CollectRuleGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such collect rule")
}
return obj
}
func MetricDescription(id int64) *models.MetricDescription {
obj, err := models.MetricDescriptionGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such metric description")
}
return obj
}
func Resource(id int64) *models.Resource {
obj, err := models.ResourceGet("id=?", id)
dangerous(err)
if obj == nil {
bomb(http.StatusNotFound, "No such resource")
}
classpathResources, err := models.ClasspathResourceGets("res_ident=?", obj.Ident)
dangerous(err)
for _, cr := range classpathResources {
obj.ClasspathIds = append(obj.ClasspathIds, cr.ClasspathId)
}
return obj
}