func DraftRateLimit()

in lib/limit.go [277:364]


func DraftRateLimit(h http.Header, window time.Duration) map[string]interface{} {
	limit := h.Get("Rate-Limit-Limit")
	remaining := h.Get("Rate-Limit-Remaining")
	reset := h.Get("Rate-Limit-Reset")
	if limit == "" || remaining == "" || reset == "" {
		return map[string]interface{}{
			"headers": fmt.Sprintf("Rate-Limit-Limit=%q Rate-Limit-Remaining=%q Rate-Limit-Reset=%q",
				limit, remaining, reset),
		}
	}
	rem, err := strconv.ParseFloat(remaining, 64)
	if err != nil {
		return map[string]interface{}{
			"headers": fmt.Sprintf("Rate-Limit-Limit=%q Rate-Limit-Remaining=%q Rate-Limit-Reset=%q",
				limit, remaining, reset),
			"error": err.Error(),
		}
	}
	var (
		per       float64
		resetTime time.Time
	)
	if d, err := strconv.ParseFloat(reset, 64); err == nil {
		per = d
		resetTime = time.Now().Add(time.Duration(d) * time.Second)
	} else if t, err := time.Parse(http.TimeFormat, reset); err == nil {
		per = time.Until(t).Seconds()
		resetTime = t
	} else if t, err := time.Parse(time.RFC1123, reset); err == nil {
		per = time.Until(t).Seconds()
		resetTime = t
	} else {
		return map[string]interface{}{
			"headers": fmt.Sprintf("Rate-Limit-Limit=%q Rate-Limit-Remaining=%q Rate-Limit-Reset=%q",
				limit, remaining, reset),
			"error": fmt.Sprintf("could not parse %q as number or timestamp", reset),
		}
	}
	burst := 1

	// Examine quota policies.
	limFields := strings.Split(limit, ",")
	quota, err := strconv.Atoi(limFields[0])
	if err != nil {
		return map[string]interface{}{
			"headers": fmt.Sprintf("Rate-Limit-Limit=%q Rate-Limit-Remaining=%q Rate-Limit-Reset=%q",
				limit, remaining, reset),
			"error": err.Error(),
		}
	}
	win := window.Seconds()
	for _, f := range limFields[1:] {
		p := policy(strings.TrimSpace(f))
		q, err := p.quota()
		if err != nil {
			return map[string]interface{}{
				"headers": fmt.Sprintf("Rate-Limit-Limit=%q Rate-Limit-Remaining=%q Rate-Limit-Reset=%q",
					limit, remaining, reset),
				"error": err.Error(),
			}
		}
		if q > quota {
			break
		}
		w, b, err := p.details(q)
		if err != nil {
			return map[string]interface{}{
				"headers": fmt.Sprintf("Rate-Limit-Limit=%q Rate-Limit-Remaining=%q Rate-Limit-Reset=%q",
					limit, remaining, reset),
				"error": err.Error(),
			}
		}
		if w >= 0 {
			win = float64(w)
		}
		if b > 0 {
			burst = b
		}
	}
	return map[string]interface{}{
		"headers": fmt.Sprintf("Rate-Limit-Limit=%q Rate-Limit-Remaining=%q Rate-Limit-Reset=%q",
			limit, remaining, reset),
		"rate":  rate.Limit(rem / per),
		"next":  rate.Limit(float64(quota) / win),
		"burst": burst,
		"reset": resetTime.UTC(),
	}
}