移除不必要的 user_host 字段及相关索引;优化通道缓存方式,直接缓存通道授权信息

This commit is contained in:
2025-05-12 17:04:20 +08:00
parent 2c37dcc2be
commit 2be1a18e91
5 changed files with 43 additions and 68 deletions

View File

@@ -4,9 +4,6 @@
- 页面 提取记录
- 页面 使用记录
- 保存 session 到数据库
- 移除 PayloadType使用 Grant_Type
### 长效业务
- 支付回调处理

View File

@@ -628,7 +628,6 @@ create table channel (
node_host varchar(255),
protocol int,
auth_ip bool not null default false,
user_host varchar(255),
auth_pass bool not null default false,
username varchar(255),
password varchar(255),
@@ -644,7 +643,6 @@ create index channel_proxy_host_index on channel (proxy_host);
create index channel_proxy_port_index on channel (proxy_port);
create index channel_node_host_index on channel (node_host);
create index channel_auth_ip_index on channel (auth_ip);
create index channel_user_host_index on channel (user_host);
create index channel_auth_pass_index on channel (auth_pass);
create index channel_username_index on channel (username);
create index channel_expiration_index on channel (expiration);
@@ -661,7 +659,6 @@ comment on column channel.proxy_port is '转发端口';
comment on column channel.node_host is '节点地址';
comment on column channel.protocol is '协议类型1-http2-https3-socks5';
comment on column channel.auth_ip is 'IP认证';
comment on column channel.user_host is '用户地址';
comment on column channel.auth_pass is '密码认证';
comment on column channel.username is '用户名';
comment on column channel.password is '密码';

View File

@@ -23,7 +23,6 @@ type Channel struct {
NodeHost string `gorm:"column:node_host;comment:节点地址" json:"node_host"` // 节点地址
Protocol int32 `gorm:"column:protocol;comment:协议类型1-http2-https3-socks5" json:"protocol"` // 协议类型1-http2-https3-socks5
AuthIP bool `gorm:"column:auth_ip;not null;comment:IP认证" json:"auth_ip"` // IP认证
UserHost string `gorm:"column:user_host;comment:用户地址" json:"user_host"` // 用户地址
AuthPass bool `gorm:"column:auth_pass;not null;comment:密码认证" json:"auth_pass"` // 密码认证
Username string `gorm:"column:username;comment:用户名" json:"username"` // 用户名
Password string `gorm:"column:password;comment:密码" json:"password"` // 密码

View File

@@ -36,7 +36,6 @@ func newChannel(db *gorm.DB, opts ...gen.DOOption) channel {
_channel.NodeHost = field.NewString(tableName, "node_host")
_channel.Protocol = field.NewInt32(tableName, "protocol")
_channel.AuthIP = field.NewBool(tableName, "auth_ip")
_channel.UserHost = field.NewString(tableName, "user_host")
_channel.AuthPass = field.NewBool(tableName, "auth_pass")
_channel.Username = field.NewString(tableName, "username")
_channel.Password = field.NewString(tableName, "password")
@@ -63,7 +62,6 @@ type channel struct {
NodeHost field.String // 节点地址
Protocol field.Int32 // 协议类型1-http2-https3-socks5
AuthIP field.Bool // IP认证
UserHost field.String // 用户地址
AuthPass field.Bool // 密码认证
Username field.String // 用户名
Password field.String // 密码
@@ -96,7 +94,6 @@ func (c *channel) updateTableName(table string) *channel {
c.NodeHost = field.NewString(table, "node_host")
c.Protocol = field.NewInt32(table, "protocol")
c.AuthIP = field.NewBool(table, "auth_ip")
c.UserHost = field.NewString(table, "user_host")
c.AuthPass = field.NewBool(table, "auth_pass")
c.Username = field.NewString(table, "username")
c.Password = field.NewString(table, "password")
@@ -120,7 +117,7 @@ func (c *channel) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
}
func (c *channel) fillFieldMap() {
c.fieldMap = make(map[string]field.Expr, 17)
c.fieldMap = make(map[string]field.Expr, 16)
c.fieldMap["id"] = c.ID
c.fieldMap["user_id"] = c.UserID
c.fieldMap["proxy_id"] = c.ProxyID
@@ -130,7 +127,6 @@ func (c *channel) fillFieldMap() {
c.fieldMap["node_host"] = c.NodeHost
c.fieldMap["protocol"] = c.Protocol
c.fieldMap["auth_ip"] = c.AuthIP
c.fieldMap["user_host"] = c.UserHost
c.fieldMap["auth_pass"] = c.AuthPass
c.fieldMap["username"] = c.Username
c.fieldMap["password"] = c.Password

View File

@@ -3,7 +3,6 @@ package services
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"log/slog"
@@ -97,12 +96,6 @@ func (s *channelService) RemoveChannels(ctx context.Context, authCtx *auth.Conte
return ChannelServiceErr("删除通道失败")
}
// 删除缓存
err = deleteCache(ctx, channels)
if err != nil {
return err
}
// 禁用代理端口并下线用过的节点
if env.DebugExternalChange {
var step = time.Now()
@@ -276,7 +269,7 @@ func (s *channelService) CreateChannel(
}
// 缓存通道数据
err = cacheChannels(ctx, rid, newChannels)
err = cacheChannels(ctx, rid, newChannels, whitelist)
if err != nil {
return err
}
@@ -612,8 +605,28 @@ func saveChannels(channels []*m.Channel) (err error) {
return nil
}
func cacheChannels(ctx context.Context, rid string, channels []*m.Channel) (err error) {
err = cache(ctx, channels)
func cacheChannels(ctx context.Context, rid string, channels []*m.Channel, whitelists *[]string) (err error) {
if len(channels) == 0 {
return nil
}
pipe := g.Redis.TxPipeline()
zList := make([]redis.Z, 0, len(channels))
for _, channel := range channels {
expiration := time.Time(channel.Expiration)
keys := chAuthItems(channel, whitelists)
for _, key := range keys {
pipe.Set(ctx, key, true, time.Since(expiration))
}
zList = append(zList, redis.Z{
Score: float64(expiration.Unix()),
Member: channel.ID,
})
}
pipe.ZAdd(ctx, "tasks:channel", zList...)
_, err = pipe.Exec(ctx)
if err != nil {
return err
}
@@ -642,62 +655,35 @@ func genPassPair() (string, string) {
return string(username), string(password)
}
func chKey(channel *m.Channel) string {
return fmt.Sprintf("channel:%d", channel.ID)
}
func cache(ctx context.Context, channels []*m.Channel) error {
if len(channels) == 0 {
return nil
func chAuthItems(channel *m.Channel, whitelists *[]string) []string {
var count = 1
var ips = make([]string, 0)
if channel.AuthIP && whitelists != nil {
count = len(*whitelists)
ips = *whitelists
}
pipe := g.Redis.TxPipeline()
zList := make([]redis.Z, 0, len(channels))
for _, channel := range channels {
marshal, err := json.Marshal(channel)
if err != nil {
return err
var proxy = channel.ProxyHost + ":" + strconv.Itoa(int(channel.ProxyPort))
var sb = strings.Builder{}
var items = make([]string, count)
for i := range items {
// 权限 key 格式:<proxy_host>:<proxy_port>:<user_ip>?:<username>?:<password>?
sb.WriteString(proxy)
if channel.AuthIP {
sb.WriteString(":" + ips[i])
}
if channel.AuthPass {
sb.WriteString(":" + channel.Username + ":" + channel.Password)
}
expiration := time.Time(channel.Expiration)
pipe.Set(ctx, chKey(channel), string(marshal), time.Until(expiration))
zList = append(zList, redis.Z{
Score: float64(expiration.Unix()),
Member: channel.ID,
})
}
pipe.ZAdd(ctx, "tasks:channel", zList...)
_, err := pipe.Exec(ctx)
if err != nil {
return err
}
return nil
}
func deleteCache(ctx context.Context, channels []*m.Channel) error {
if len(channels) == 0 {
return nil
}
keys := make([]string, len(channels))
for i := range channels {
keys[i] = chKey(channels[i])
}
_, err := g.Redis.Del(ctx, keys...).Result()
if err != nil {
return err
}
return nil
return items
}
type ChannelAuthType int
const (
ChannelAuthTypeAll ChannelAuthType = iota
ChannelAuthTypeIp
ChannelAuthTypeIp ChannelAuthType = iota + 1
ChannelAuthTypePass
)