blob: 0bfd56be5f4bd0e014db7b9285ec765ca16cfff0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ratelimit
import (
"encoding/json"
"net/http"
)
import (
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/dubbogo/dubbo-go-pixiu-filter/pkg/api/config/ratelimit"
fc "github.com/dubbogo/dubbo-go-pixiu-filter/pkg/context"
"github.com/dubbogo/dubbo-go-pixiu-filter/pkg/filter"
)
import (
"github.com/apache/dubbo-go-pixiu/pkg/client"
"github.com/apache/dubbo-go-pixiu/pkg/common/constant"
"github.com/apache/dubbo-go-pixiu/pkg/common/extension"
contexthttp "github.com/apache/dubbo-go-pixiu/pkg/context/http"
"github.com/apache/dubbo-go-pixiu/pkg/filter/ratelimit/matcher"
"github.com/apache/dubbo-go-pixiu/pkg/logger"
)
// Init cache the filter func & init sentinel
func Init(config *ratelimit.Config) {
if err := rateLimitInit(config); err != nil {
logger.Errorf("rate limit init fail: %s", err)
//if sentinel init fail, just return a empty filter func to avoid error.
extension.SetFilterFunc(constant.RateLimitFilter, func(context fc.Context) {})
return
}
extension.SetFilterFunc(constant.RateLimitFilter, New().Do())
}
// rateLimit
type rateLimit struct {
}
// New create the rate limit filter
func New() filter.Filter {
return &rateLimit{}
}
// Do extract the url target & pass or block it.
func (r *rateLimit) Do() fc.FilterFunc {
return func(ctx fc.Context) {
hc := ctx.(*contexthttp.HttpContext)
path := hc.GetAPI().URLPattern
resourceName, ok := matcher.Match(path)
//if not exists, just skip it.
if !ok {
return
}
entry, blockErr := sentinel.Entry(resourceName, sentinel.WithResourceType(base.ResTypeAPIGateway), sentinel.WithTrafficType(base.Inbound))
//if blockErr not nil, indicates the request was blocked by Sentinel
if blockErr != nil {
bt, _ := json.Marshal(filter.ErrResponse{Message: "blocked by rate limit"})
hc.SourceResp = bt
hc.TargetResp = &client.Response{Data: bt}
hc.WriteJSONWithStatus(http.StatusTooManyRequests, bt)
hc.Abort()
return
}
defer entry.Exit()
}
}