Skip to content

Commit

Permalink
feat: proxy list [新增代理列表实体]
Browse files Browse the repository at this point in the history
refactor: change client manager structure [重构:更改客户端管理器结构适配影子客户端]

feat: add proxy config table and dao [添加代理配置独立数据表和DAO层]

feat: new proxy config entity [新建的代理配置实体]

feat: update and delete proxy config [更新和删除代理配置接口]

feat: get config api and beautify proxy item [更新获取配置API并美化代理项]

feat: change proxy form style [美化修改代理的表单样式]

fix: client edit [修复:编辑客户端的问题]

fix: shadow copy status error [修复:影子客户端复制状态错误]

fix: http proxy bug [修复:HTTP代理类型的错误]

fix: cannot update client [修复:无法更新客户端]

feat: record trigger refetch [自动重新获取表格内的数据]

fix: filter string length [修复:过滤字符串长度]

fix: add client error [修复:添加客户端错误]

fix: do not notify client when stopped [修复:停止时不通知客户端]

fix: delete when proxy duplicate [修复:代理重复时删除]

feat: add http proxy location [添加HTTP代理路由路径]

chore: edit style [编辑样式美化]

fix: remove expired client [修复:自动移除过期客户端]

feat: proxy status [新增代理状态提示]

fix: build [修复:构建]

fix: refetch trigger [修复:重新获取数据的问题]

fix: remove all expired client [修复:移除所有过期客户端]

feat: i18n for proxy [代理页面的国际化翻译]
  • Loading branch information
VaalaCat committed Dec 20, 2024
1 parent 74908d0 commit 3732766
Show file tree
Hide file tree
Showing 99 changed files with 5,489 additions and 927 deletions.
42 changes: 42 additions & 0 deletions biz/client/get_proxy_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package client

import (
"context"
"fmt"

"github.com/VaalaCat/frp-panel/logger"
"github.com/VaalaCat/frp-panel/pb"
"github.com/VaalaCat/frp-panel/tunnel"
"github.com/samber/lo"
)

func GetProxyConfig(c context.Context, req *pb.GetProxyConfigRequest) (*pb.GetProxyConfigResponse, error) {
var (
clientID = req.GetClientId()
serverID = req.GetServerId()
proxyName = req.GetName()
)

ctrl := tunnel.GetClientController()
cli := ctrl.Get(clientID, serverID)
if cli == nil {
logger.Logger(c).Errorf("cannot get client, clientID: [%s], serverID: [%s]", clientID, serverID)
return nil, fmt.Errorf("cannot get client")
}
workingStatus, ok := cli.GetProxyStatus(proxyName)
if !ok {
logger.Logger(c).Errorf("cannot get proxy status, client: [%s], server: [%s], proxy name: [%s]", clientID, serverID, proxyName)
return nil, fmt.Errorf("cannot get proxy status")
}

return &pb.GetProxyConfigResponse{
Status: &pb.Status{Code: pb.RespCode_RESP_CODE_SUCCESS, Message: "success"},
WorkingStatus: &pb.ProxyWorkingStatus{
Name: lo.ToPtr(workingStatus.Name),
Type: lo.ToPtr(workingStatus.Type),
Status: lo.ToPtr(workingStatus.Phase),
Err: lo.ToPtr(workingStatus.Err),
RemoteAddr: lo.ToPtr(workingStatus.RemoteAddr),
},
}, nil
}
19 changes: 8 additions & 11 deletions biz/client/remove_tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@ package client

import (
"context"
"os"
"time"

"github.com/VaalaCat/frp-panel/logger"
"github.com/VaalaCat/frp-panel/pb"
"github.com/VaalaCat/frp-panel/tunnel"
)

func RemoveFrpcHandler(ctx context.Context, req *pb.RemoveFRPCRequest) (*pb.RemoveFRPCResponse, error) {
logger.Logger(ctx).Infof("remove frpc, req: [%+v]", req)
cli := tunnel.GetClientController().Get(req.GetClientId())
if cli == nil {
logger.Logger(ctx).Infof("client not found, no need to remove")
return &pb.RemoveFRPCResponse{
Status: &pb.Status{Code: pb.RespCode_RESP_CODE_INVALID, Message: "client not found"},
}, nil
}
cli.Stop()
tunnel.GetClientController().Delete(req.GetClientId())
logger.Logger(ctx).Infof("remove frpc, req: [%+v], will exit in 10s", req)

go func() {
time.Sleep(10 * time.Second)
os.Exit(0)
}()

return &pb.RemoveFRPCResponse{
Status: &pb.Status{Code: pb.RespCode_RESP_CODE_SUCCESS, Message: "ok"},
Expand Down
2 changes: 2 additions & 0 deletions biz/client/rpc_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ func HandleServerMessage(req *pb.ServerMessage) *pb.ClientMessage {
return common.WrapperServerMsg(req, StopSteamLogHandler)
case pb.Event_EVENT_START_PTY_CONNECT:
return common.WrapperServerMsg(req, StartPTYConnect)
case pb.Event_EVENT_GET_PROXY_INFO:
return common.WrapperServerMsg(req, GetProxyConfig)
case pb.Event_EVENT_PING:
rawData, _ := proto.Marshal(conf.GetVersion().ToProto())
return &pb.ClientMessage{
Expand Down
65 changes: 50 additions & 15 deletions biz/client/rpc_pull_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (
"github.com/VaalaCat/frp-panel/services/client"
"github.com/VaalaCat/frp-panel/tunnel"
"github.com/VaalaCat/frp-panel/utils"
"github.com/samber/lo"
)

func PullConfig(clientID, clientSecret string) error {
ctx := context.Background()
ctrl := tunnel.GetClientController()

logger.Logger(ctx).Infof("start to pull client config, clientID: [%s]", clientID)
cli, err := rpc.MasterCli(ctx)
Expand All @@ -32,6 +34,38 @@ func PullConfig(clientID, clientSecret string) error {
return err
}

if resp.GetClient().GetStopped() {
logger.Logger(ctx).Infof("client [%s] is stopped, stop client", clientID)
ctrl.StopByClient(clientID)
return nil
}

if len(resp.GetClient().GetOriginClientId()) == 0 {
currentClientIDs := ctrl.List()
if idsToRemove, _ := lo.Difference(resp.GetClient().GetClientIds(), currentClientIDs); len(idsToRemove) > 0 {
logger.Logger(ctx).Infof("client [%s] has %d expired child clients, remove clientIDs: [%+v]", clientID, len(idsToRemove), idsToRemove)
for _, id := range idsToRemove {
ctrl.StopByClient(id)
ctrl.DeleteByClient(id)
}
}
}

// this client is shadow client, has no config
// pull child client config
if len(resp.GetClient().GetClientIds()) > 0 {
for _, id := range resp.GetClient().GetClientIds() {
if id == clientID {
logger.Logger(ctx).Infof("client [%s] is shadow client, skip", clientID)
continue
}
if err := PullConfig(id, clientSecret); err != nil {
logger.Logger(context.Background()).WithError(err).Errorf("cannot pull child client config, id: [%s]", id)
}
}
return nil
}

if len(resp.GetClient().GetConfig()) == 0 {
logger.Logger(ctx).Infof("client [%s] config is empty, wait for server init", clientID)
return nil
Expand All @@ -43,37 +77,38 @@ func PullConfig(clientID, clientSecret string) error {
return err
}

ctrl := tunnel.GetClientController()
serverID := resp.GetClient().GetServerId()

if t := ctrl.Get(clientID); t == nil {
ctrl.Add(clientID, client.NewClientHandler(c, p, v))
ctrl.Run(clientID)
if t := ctrl.Get(clientID, serverID); t == nil {
logger.Logger(ctx).Infof("client [%s] for server [%s] not exists, create it", clientID, serverID)
ctrl.Add(clientID, serverID, client.NewClientHandler(c, p, v))
ctrl.Run(clientID, serverID)
} else {
if !reflect.DeepEqual(t.GetCommonCfg(), c) {
logger.Logger(ctx).Infof("client %s config changed, will recreate it", clientID)
tcli := ctrl.Get(clientID)
logger.Logger(ctx).Infof("client [%s] for server [%s] config changed, will recreate it", clientID, serverID)
tcli := ctrl.Get(clientID, serverID)
if tcli != nil {
tcli.Stop()
ctrl.Delete(clientID)
ctrl.Delete(clientID, serverID)
}
ctrl.Add(clientID, client.NewClientHandler(c, p, v))
ctrl.Run(clientID)
ctrl.Add(clientID, serverID, client.NewClientHandler(c, p, v))
ctrl.Run(clientID, serverID)
} else {
logger.Logger(ctx).Infof("client %s already exists, update if need", clientID)
tcli := ctrl.Get(clientID)
logger.Logger(ctx).Infof("client [%s] for server [%s] already exists, update if need", clientID, serverID)
tcli := ctrl.Get(clientID, serverID)
if tcli == nil || !tcli.Running() {
if tcli != nil {
tcli.Stop()
ctrl.Delete(clientID)
ctrl.Delete(clientID, serverID)
}
ctrl.Add(clientID, client.NewClientHandler(c, p, v))
ctrl.Run(clientID)
ctrl.Add(clientID, serverID, client.NewClientHandler(c, p, v))
ctrl.Run(clientID, serverID)
} else {
tcli.Update(p, v)
}
}
}

logger.Logger(ctx).Infof("pull client config success, clientID: [%s]", clientID)
logger.Logger(ctx).Infof("pull client config success, clientID: [%s], serverID: [%s]", clientID, serverID)
return nil
}
7 changes: 5 additions & 2 deletions biz/client/start_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ package client
import (
"context"

"github.com/VaalaCat/frp-panel/conf"
"github.com/VaalaCat/frp-panel/logger"
"github.com/VaalaCat/frp-panel/pb"
"github.com/VaalaCat/frp-panel/tunnel"
)

func StartFRPCHandler(ctx context.Context, req *pb.StartFRPCRequest) (*pb.StartFRPCResponse, error) {
logger.Logger(ctx).Infof("client get a start client request, origin is: [%+v]", req)

tunnel.GetClientController().Run(req.GetClientId())
if err := PullConfig(req.GetClientId(), conf.Get().Client.Secret); err != nil {
logger.Logger(ctx).WithError(err).Error("cannot pull client config")
return nil, err
}

return &pb.StartFRPCResponse{
Status: &pb.Status{Code: pb.RespCode_RESP_CODE_SUCCESS, Message: "ok"},
Expand Down
3 changes: 2 additions & 1 deletion biz/client/stop_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (
func StopFRPCHandler(ctx context.Context, req *pb.StopFRPCRequest) (*pb.StopFRPCResponse, error) {
logger.Logger(ctx).Infof("client get a stop client request, origin is: [%+v]", req)

tunnel.GetClientController().Stop(req.GetClientId())
tunnel.GetClientController().StopAll()
tunnel.GetClientController().DeleteAll()

return &pb.StopFRPCResponse{
Status: &pb.Status{Code: pb.RespCode_RESP_CODE_SUCCESS, Message: "ok"},
Expand Down
14 changes: 7 additions & 7 deletions biz/client/update_tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,27 @@ func UpdateFrpcHander(ctx context.Context, req *pb.UpdateFRPCRequest) (*pb.Updat
content := req.GetConfig()
c, p, v, err := utils.LoadClientConfig(content, false)
if err != nil {
logger.Logger(context.Background()).WithError(err).Errorf("cannot load config")
logger.Logger(ctx).WithError(err).Errorf("cannot load config")
return &pb.UpdateFRPCResponse{
Status: &pb.Status{Code: pb.RespCode_RESP_CODE_INVALID, Message: err.Error()},
}, err
}

cli := tunnel.GetClientController().Get(req.GetClientId())
cli := tunnel.GetClientController().Get(req.GetClientId(), req.GetServerId())
if cli != nil {
if reflect.DeepEqual(c, cli.GetCommonCfg()) {
logger.Logger(ctx).Warnf("client common config not changed")
cli.Update(p, v)
} else {
cli.Stop()
tunnel.GetClientController().Delete(req.GetClientId())
tunnel.GetClientController().Add(req.GetClientId(), client.NewClientHandler(c, p, v))
tunnel.GetClientController().Run(req.GetClientId())
tunnel.GetClientController().Delete(req.GetClientId(), req.GetServerId())
tunnel.GetClientController().Add(req.GetClientId(), req.GetServerId(), client.NewClientHandler(c, p, v))
tunnel.GetClientController().Run(req.GetClientId(), req.GetServerId())
}
logger.Logger(ctx).Infof("update client, id: [%s] success, running", req.GetClientId())
} else {
tunnel.GetClientController().Add(req.GetClientId(), client.NewClientHandler(c, p, v))
tunnel.GetClientController().Run(req.GetClientId())
tunnel.GetClientController().Add(req.GetClientId(), req.GetServerId(), client.NewClientHandler(c, p, v))
tunnel.GetClientController().Run(req.GetClientId(), req.GetServerId())
logger.Logger(ctx).Infof("add new client, id: [%s], running", req.GetClientId())
}

Expand Down
4 changes: 3 additions & 1 deletion biz/master/client/create_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/VaalaCat/frp-panel/dao"
"github.com/VaalaCat/frp-panel/models"
"github.com/VaalaCat/frp-panel/pb"
"github.com/VaalaCat/frp-panel/utils"
"github.com/google/uuid"
)

Expand All @@ -20,7 +21,7 @@ func InitClientHandler(c context.Context, req *pb.InitClientRequest) (*pb.InitCl
}, nil
}

if len(userClientID) == 0 {
if len(userClientID) == 0 || !utils.IsClientIDPermited(userClientID) {
return &pb.InitClientResponse{
Status: &pb.Status{Code: pb.RespCode_RESP_CODE_INVALID, Message: "invalid client id"},
}, nil
Expand All @@ -34,6 +35,7 @@ func InitClientHandler(c context.Context, req *pb.InitClientRequest) (*pb.InitCl
TenantID: userInfo.GetTenantID(),
UserID: userInfo.GetUserID(),
ConnectSecret: uuid.New().String(),
IsShadow: true,
}); err != nil {
return nil, err
}
Expand Down
4 changes: 4 additions & 0 deletions biz/master/client/delete_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func DeleteClientHandler(ctx context.Context, req *pb.DeleteClientRequest) (*pb.
return nil, err
}

if err := dao.DeleteProxyConfigsByClientIDOrOriginClientID(userInfo, clientID); err != nil {
return nil, err
}

go func() {
resp, err := rpc.CallClient(context.Background(), req.GetClientId(), pb.Event_EVENT_REMOVE_FRPC, req)
if err != nil {
Expand Down
58 changes: 47 additions & 11 deletions biz/master/client/get_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/VaalaCat/frp-panel/common"
"github.com/VaalaCat/frp-panel/dao"
"github.com/VaalaCat/frp-panel/logger"
"github.com/VaalaCat/frp-panel/models"
"github.com/VaalaCat/frp-panel/pb"
"github.com/samber/lo"
)
Expand All @@ -16,6 +17,7 @@ func GetClientHandler(ctx context.Context, req *pb.GetClientRequest) (*pb.GetCli
var (
userInfo = common.GetUserInfo(ctx)
clientID = req.GetClientId()
serverID = req.GetServerId()
)

if !userInfo.Valid() {
Expand All @@ -30,20 +32,54 @@ func GetClientHandler(ctx context.Context, req *pb.GetClientRequest) (*pb.GetCli
}, nil
}

client, err := dao.GetClientByClientID(userInfo, clientID)
if err != nil {
return nil, err
respCli := &pb.Client{}
if len(serverID) == 0 {
client, err := dao.GetClientByClientID(userInfo, clientID)
if err != nil {
return nil, err
}
clientIDs, err := dao.GetClientIDsInShadowByClientID(userInfo, clientID)
if err != nil {
logger.Logger(ctx).WithError(err).Errorf("cannot get client ids in shadow, id: [%s]", clientID)
}

respCli = &pb.Client{
Id: lo.ToPtr(client.ClientID),
Secret: lo.ToPtr(client.ConnectSecret),
Config: lo.ToPtr(string(client.ConfigContent)),
ServerId: lo.ToPtr(client.ServerID),
Stopped: lo.ToPtr(client.Stopped),
Comment: lo.ToPtr(client.Comment),
ClientIds: clientIDs,
}
} else {
client, err := dao.GetClientByFilter(userInfo, &models.ClientEntity{
OriginClientID: clientID,
ServerID: serverID,
}, lo.ToPtr(false))
if err != nil {
client, err = dao.GetClientByFilter(userInfo, &models.ClientEntity{
ClientID: clientID,
ServerID: serverID,
}, nil)
if err != nil {
return nil, err
}
}

respCli = &pb.Client{
Id: lo.ToPtr(client.ClientID),
Secret: lo.ToPtr(client.ConnectSecret),
Config: lo.ToPtr(string(client.ConfigContent)),
ServerId: lo.ToPtr(client.ServerID),
Stopped: lo.ToPtr(client.Stopped),
Comment: lo.ToPtr(client.Comment),
ClientIds: nil,
}
}

return &pb.GetClientResponse{
Status: &pb.Status{Code: pb.RespCode_RESP_CODE_SUCCESS, Message: "ok"},
Client: &pb.Client{
Id: lo.ToPtr(client.ClientID),
Secret: lo.ToPtr(client.ConnectSecret),
Config: lo.ToPtr(string(client.ConfigContent)),
ServerId: lo.ToPtr(client.ServerID),
Stopped: lo.ToPtr(client.Stopped),
Comment: lo.ToPtr(client.Comment),
},
Client: respCli,
}, nil
}
Loading

0 comments on commit 3732766

Please sign in to comment.