-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
381 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Limiter | ||
|
||
### Structure | ||
|
||
```json | ||
{ | ||
"limiters": [ | ||
{ | ||
"tag": "limiter-a", | ||
"download": "1M", | ||
"upload": "10M", | ||
"auth_user": [ | ||
"user-a", | ||
"user-b" | ||
], | ||
"inbound": [ | ||
"in-a", | ||
"in-b" | ||
] | ||
} | ||
] | ||
} | ||
|
||
``` | ||
|
||
### Fields | ||
|
||
#### download upload | ||
|
||
==Required== | ||
|
||
Format: `[Integer][Unit]` e.g. `100M, 100m, 1G, 1g`. | ||
|
||
Supported units (case insensitive): `B, K, M, G, T, P, E`. | ||
|
||
#### tag | ||
|
||
The tag of the limiter, used in route rule. | ||
|
||
#### auth_user | ||
|
||
Global limiter for a group of usernames, see each inbound for details. | ||
|
||
#### inbound | ||
|
||
Global limiter for a group of inbounds. | ||
|
||
!!! info "" | ||
|
||
All the auth_users, inbounds and route rule with limiter tag share the same limiter. To take effect independently, configure limiters seperately. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# 限速 | ||
|
||
### 结构 | ||
|
||
```json | ||
{ | ||
"limiters": [ | ||
{ | ||
"tag": "limiter-a", | ||
"download": "1M", | ||
"upload": "10M", | ||
"auth_user": [ | ||
"user-a", | ||
"user-b" | ||
], | ||
"inbound": [ | ||
"in-a", | ||
"in-b" | ||
] | ||
} | ||
] | ||
} | ||
|
||
``` | ||
|
||
### 字段 | ||
|
||
#### download upload | ||
|
||
==必填== | ||
|
||
格式: `[Integer][Unit]` 例如: `100M, 100m, 1G, 1g`. | ||
|
||
支持的单位 (大小写不敏感): `B, K, M, G, T, P, E`. | ||
|
||
#### tag | ||
|
||
限速标签,在路由规则中使用。 | ||
|
||
#### auth_user | ||
|
||
用户组全局限速,参阅入站设置。 | ||
|
||
#### inbound | ||
|
||
入站组全局限速。 | ||
|
||
!!! info "" | ||
|
||
所有用户、入站和有限速标签的路由规则共享同一个限速。为了独立生效,请分别配置限速器。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package limiter | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net" | ||
"sync" | ||
|
||
"github.com/dustin/go-humanize" | ||
"github.com/sagernet/sing-box/log" | ||
"github.com/sagernet/sing-box/option" | ||
E "github.com/sagernet/sing/common/exceptions" | ||
"github.com/sagernet/sing/service" | ||
) | ||
|
||
const ( | ||
limiterTag = "tag" | ||
limiterUser = "user" | ||
limiterInbound = "inbound" | ||
) | ||
|
||
var _ Manager = (*defaultManager)(nil) | ||
|
||
type defaultManager struct { | ||
mp *sync.Map | ||
} | ||
|
||
func WithDefault(ctx context.Context, logger log.ContextLogger, options []option.Limiter) context.Context { | ||
m := &defaultManager{mp: &sync.Map{}} | ||
for i, option := range options { | ||
if err := m.createLimiter(ctx, option); err != nil { | ||
logger.ErrorContext(ctx, fmt.Sprintf("id=%d, %s", i, err)) | ||
} else { | ||
logger.InfoContext(ctx, fmt.Sprintf("id=%d, tag=%s, users=%v, inbounds=%v, download=%s, upload=%s", | ||
i, option.Tag, option.AuthUser, option.Inbound, option.Download, option.Upload)) | ||
} | ||
} | ||
return service.ContextWith[Manager](ctx, m) | ||
} | ||
|
||
func buildKey(prefix string, tag string) string { | ||
return fmt.Sprintf("%s|%s", prefix, tag) | ||
} | ||
|
||
func (m *defaultManager) createLimiter(ctx context.Context, option option.Limiter) (err error) { | ||
var download, upload uint64 | ||
if len(option.Download) > 0 { | ||
download, err = humanize.ParseBytes(option.Download) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
if len(option.Upload) > 0 { | ||
upload, err = humanize.ParseBytes(option.Upload) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
if download == 0 && upload == 0 { | ||
return E.New("download/upload, at least one must be set") | ||
} | ||
l := newLimiter(download, upload) | ||
valid := false | ||
if len(option.Tag) > 0 { | ||
valid = true | ||
m.mp.Store(buildKey(limiterTag, option.Tag), l) | ||
} | ||
if len(option.AuthUser) > 0 { | ||
valid = true | ||
for _, user := range option.AuthUser { | ||
m.mp.Store(buildKey(limiterUser, user), l) | ||
} | ||
} | ||
if len(option.Inbound) > 0 { | ||
valid = true | ||
for _, inbound := range option.Inbound { | ||
m.mp.Store(buildKey(limiterInbound, inbound), l) | ||
} | ||
} | ||
if !valid { | ||
return E.New("tag/user/inbound, at least one must be set") | ||
} | ||
return | ||
} | ||
|
||
func (m *defaultManager) LoadLimiters(tags []string, user, inbound string) (limiters []*limiter) { | ||
for _, t := range tags { | ||
if v, ok := m.mp.Load(buildKey(limiterTag, t)); ok { | ||
limiters = append(limiters, v.(*limiter)) | ||
} | ||
} | ||
if v, ok := m.mp.Load(buildKey(limiterUser, user)); ok { | ||
limiters = append(limiters, v.(*limiter)) | ||
} | ||
if v, ok := m.mp.Load(buildKey(limiterInbound, inbound)); ok { | ||
limiters = append(limiters, v.(*limiter)) | ||
} | ||
return | ||
} | ||
|
||
func (m *defaultManager) NewConnWithLimiters(ctx context.Context, conn net.Conn, limiters []*limiter) net.Conn { | ||
for _, limiter := range limiters { | ||
conn = &connWithLimiter{Conn: conn, limiter: limiter, ctx: ctx} | ||
} | ||
return conn | ||
} |
Oops, something went wrong.