fix: start timeout

This commit is contained in:
VaalaCat
2025-08-10 15:45:41 +00:00
parent 6e9d2d6c25
commit c0eb0c07f2
6 changed files with 70 additions and 15 deletions

View File

@@ -41,6 +41,7 @@ func BuildCommand(fs embed.FS) *cobra.Command {
logger.UpdateLoggerOpt( logger.UpdateLoggerOpt(
cfg.Logger.FRPLoggerLevel, cfg.Logger.FRPLoggerLevel,
cfg.Logger.DefaultLoggerLevel, cfg.Logger.DefaultLoggerLevel,
cfg.IsDebug,
) )
return NewRootCmd( return NewRootCmd(
@@ -152,6 +153,7 @@ func NewMasterCmd(cfg conf.Config, fs embed.FS) *cobra.Command {
warnDepParam(cmd) warnDepParam(cmd)
opts := []fx.Option{ opts := []fx.Option{
fx.StartTimeout(defs.AppStartTimeout),
commonMod, commonMod,
masterMod, masterMod,
serverMod, serverMod,
@@ -198,6 +200,7 @@ func NewClientCmd(cfg conf.Config) *cobra.Command {
warnDepParam(cmd) warnDepParam(cmd)
opts := []fx.Option{ opts := []fx.Option{
fx.StartTimeout(defs.AppStartTimeout),
clientMod, clientMod,
commonMod, commonMod,
fx.Supply( fx.Supply(
@@ -243,6 +246,7 @@ func NewServerCmd(cfg conf.Config) *cobra.Command {
warnDepParam(cmd) warnDepParam(cmd)
opts := []fx.Option{ opts := []fx.Option{
fx.StartTimeout(defs.AppStartTimeout),
serverMod, serverMod,
commonMod, commonMod,
fx.Supply( fx.Supply(

View File

@@ -71,6 +71,7 @@ const (
PullConfigDuration = 30 * time.Second PullConfigDuration = 30 * time.Second
PushProxyInfoDuration = 30 * time.Second PushProxyInfoDuration = 30 * time.Second
PullClientWorkersDuration = 30 * time.Second PullClientWorkersDuration = 30 * time.Second
AppStartTimeout = 5 * time.Minute
) )
const ( const (

View File

@@ -1,8 +1,11 @@
package clientrpc package clientrpc
import ( import (
"context"
"github.com/VaalaCat/frp-panel/pb" "github.com/VaalaCat/frp-panel/pb"
"github.com/VaalaCat/frp-panel/services/app" "github.com/VaalaCat/frp-panel/services/app"
"github.com/VaalaCat/frp-panel/utils/logger"
) )
type ClientRPCHandler interface { type ClientRPCHandler interface {
@@ -42,6 +45,12 @@ func NewClientRPCHandler(
} }
func (s *clientRPCHandler) Run() { func (s *clientRPCHandler) Run() {
defer func() {
if err := recover(); err != nil {
logger.Logger(context.Background()).Fatalf("client rpc handler panic: %v", err)
}
}()
startClientRpcHandler(s.appInstance, s.rpcClient, s.done, s.clientID, s.clientSecret, s.event, s.handerFunc) startClientRpcHandler(s.appInstance, s.rpcClient, s.done, s.clientID, s.clientSecret, s.event, s.handerFunc)
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/VaalaCat/frp-panel/defs" "github.com/VaalaCat/frp-panel/defs"
"github.com/VaalaCat/frp-panel/pb" "github.com/VaalaCat/frp-panel/pb"
"github.com/VaalaCat/frp-panel/services/app" "github.com/VaalaCat/frp-panel/services/app"
"github.com/VaalaCat/frp-panel/utils"
"github.com/VaalaCat/frp-panel/utils/logger" "github.com/VaalaCat/frp-panel/utils/logger"
"github.com/VaalaCat/frp-panel/utils/wsgrpc" "github.com/VaalaCat/frp-panel/utils/wsgrpc"
"github.com/imroc/req/v3" "github.com/imroc/req/v3"
@@ -34,6 +35,7 @@ func (m *masterClient) Call() pb.MasterClient {
} }
func NewMasterCli(appInstance app.Application) *masterClient { func NewMasterCli(appInstance app.Application) *masterClient {
logger.Logger(context.Background()).Debugf("creating new master client")
return &masterClient{ return &masterClient{
inited: false, inited: false,
appInstance: appInstance, appInstance: appInstance,
@@ -60,16 +62,23 @@ func newMasterCli(appInstance app.Application) pb.MasterClient {
wsURL := fmt.Sprintf("%s://%s/wsgrpc", connInfo.Scheme, connInfo.Host) wsURL := fmt.Sprintf("%s://%s/wsgrpc", connInfo.Scheme, connInfo.Host)
header := http.Header{} header := http.Header{}
wsDialer := wsgrpc.WebsocketDialer(wsURL, header, appInstance.GetConfig().Client.TLSInsecureSkipVerify) wsDialer := wsgrpc.WebsocketDialer(wsURL,
header,
appInstance.GetConfig().Client.TLSInsecureSkipVerify,
logger.Logger(ctx),
)
opt = append(opt, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(wsDialer)) opt = append(opt, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(wsDialer))
} }
logger.Logger(ctx).Debugf("creating new grpc client to [%s]", utils.MarshalForJson(connInfo))
conn, err := grpc.NewClient(connInfo.Host, opt...) conn, err := grpc.NewClient(connInfo.Host, opt...)
if err != nil { if err != nil {
logger.Logger(ctx).Fatalf("did not connect: %v", err) logger.Logger(ctx).Fatalf("did not connect: %v", err)
} }
logger.Logger(ctx).Debugf("grpc client created")
return pb.NewMasterClient(conn) return pb.NewMasterClient(conn)
} }

View File

@@ -34,17 +34,25 @@ func InitLogger() {
logrus.SetFormatter(NewCustomFormatter(false, true)) logrus.SetFormatter(NewCustomFormatter(false, true))
} }
func UpdateLoggerOpt(frpLogLevel string, logrusLevel string) { func UpdateLoggerOpt(frpLogLevel string, logrusLevel string, isDebug bool) {
ctx := context.Background() ctx := context.Background()
frpLogLevel = strings.ToLower(frpLogLevel) frpLogLevel = strings.ToLower(frpLogLevel)
logrusLevel = strings.ToLower(logrusLevel) logrusLevel = strings.ToLower(logrusLevel)
if frpLogLevel == "" { if frpLogLevel == "" {
frpLogLevel = "info" if isDebug {
frpLogLevel = "trace"
} else {
frpLogLevel = "info"
}
} }
if logrusLevel == "" { if logrusLevel == "" {
logrusLevel = "info" if isDebug {
logrusLevel = "trace"
} else {
logrusLevel = "info"
}
} }
frpLv, err := log.ParseLevel(frpLogLevel) frpLv, err := log.ParseLevel(frpLogLevel)

View File

@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"crypto/tls" "crypto/tls"
"errors"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
@@ -14,6 +15,10 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
var (
WSGrpcError = errors.New("wsgrpc error")
)
// --------------------------------------- // ---------------------------------------
// 通用 websocketConn 实现 net.Conn 接口 // 通用 websocketConn 实现 net.Conn 接口
// --------------------------------------- // ---------------------------------------
@@ -35,16 +40,20 @@ func (c *websocketConn) Read(p []byte) (int, error) {
if c.readBuffer.Len() == 0 { if c.readBuffer.Len() == 0 {
messageType, data, err := c.ws.ReadMessage() messageType, data, err := c.ws.ReadMessage()
if err != nil { if err != nil {
return 0, err return 0, errors.Join(err, errors.New("wsgrpc read message error"), WSGrpcError)
} }
// 只接受二进制数据 // 只接受二进制数据
if messageType != websocket.BinaryMessage { if messageType != websocket.BinaryMessage {
return 0, fmt.Errorf("unexpected message type: %d", messageType) return 0, errors.Join(fmt.Errorf("unexpected message type: %d", messageType), WSGrpcError)
} }
c.readBuffer.Write(data) c.readBuffer.Write(data)
} }
return c.readBuffer.Read(p) if n, err := c.readBuffer.Read(p); err != nil {
return n, errors.Join(err, WSGrpcError)
} else {
return n, nil
}
} }
// Write 将数据作为单条二进制消息发送 // Write 将数据作为单条二进制消息发送
@@ -54,14 +63,18 @@ func (c *websocketConn) Write(p []byte) (int, error) {
err := c.ws.WriteMessage(websocket.BinaryMessage, p) err := c.ws.WriteMessage(websocket.BinaryMessage, p)
if err != nil { if err != nil {
return 0, err return 0, errors.Join(err, errors.New("wsgrpc write message error"), WSGrpcError)
} }
return len(p), nil return len(p), nil
} }
// Close 关闭 websocket 连接 // Close 关闭 websocket 连接
func (c *websocketConn) Close() error { func (c *websocketConn) Close() error {
return c.ws.Close() err := c.ws.Close()
if err != nil {
return errors.Join(err, errors.New("wsgrpc close error"), WSGrpcError)
}
return nil
} }
// LocalAddr 返回本地地址,通过 websocket 底层连接获取 // LocalAddr 返回本地地址,通过 websocket 底层连接获取
@@ -83,9 +96,12 @@ func (c *websocketConn) RemoteAddr() net.Addr {
// SetDeadline 同时设置读写超时 // SetDeadline 同时设置读写超时
func (c *websocketConn) SetDeadline(t time.Time) error { func (c *websocketConn) SetDeadline(t time.Time) error {
if err := c.ws.SetReadDeadline(t); err != nil { if err := c.ws.SetReadDeadline(t); err != nil {
return err return errors.Join(err, errors.New("wsgrpc set read deadline error"), WSGrpcError)
} }
return c.ws.SetWriteDeadline(t) if err := c.ws.SetWriteDeadline(t); err != nil {
return errors.Join(err, errors.New("wsgrpc set write deadline error"), WSGrpcError)
}
return nil
} }
// SetReadDeadline 设置读超时 // SetReadDeadline 设置读超时
@@ -101,18 +117,26 @@ func (c *websocketConn) SetWriteDeadline(t time.Time) error {
// --------------------------------------- // ---------------------------------------
// 客户端 WebSocket Dialer // 客户端 WebSocket Dialer
// --------------------------------------- // ---------------------------------------
type LogInterface interface {
Infof(format string, args ...interface{})
Errorf(format string, args ...interface{})
Tracef(format string, args ...interface{})
}
// WebsocketDialer 返回一个可以用于 grpc.WithContextDialer 的拨号函数;该函数通过 websocket 建立连接。 // WebsocketDialer 返回一个可以用于 grpc.WithContextDialer 的拨号函数;该函数通过 websocket 建立连接。
// 参数 url 表示 websocket 服务器地址header 可用于传递额外的 header 参数。 // 参数 url 表示 websocket 服务器地址header 可用于传递额外的 header 参数。
func WebsocketDialer(url string, header http.Header, insecure bool) func(ctx context.Context, addr string) (net.Conn, error) { func WebsocketDialer(url string, header http.Header, insecure bool, log LogInterface) func(ctx context.Context, addr string) (net.Conn, error) {
return func(ctx context.Context, addr string) (net.Conn, error) { return func(ctx context.Context, addr string) (net.Conn, error) {
dialer := websocket.Dialer{ dialer := websocket.Dialer{
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure}, TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure},
} }
log.Tracef("dialing websocket server [%s]", url)
ws, _, err := dialer.DialContext(ctx, url, header) ws, _, err := dialer.DialContext(ctx, url, header)
if err != nil { if err != nil {
return nil, err log.Errorf("wsgrpc dialer error: %v", err)
return nil, errors.Join(err, errors.New("wsgrpc dialer error"), WSGrpcError)
} }
log.Tracef("websocket connection connect done")
return &websocketConn{ws: ws}, nil return &websocketConn{ws: ws}, nil
} }
} }
@@ -160,11 +184,11 @@ func (l *WSListener) Accept() (net.Conn, error) {
select { select {
case conn, ok := <-l.connCh: case conn, ok := <-l.connCh:
if !ok { if !ok {
return nil, fmt.Errorf("listener closed") return nil, errors.Join(fmt.Errorf("listener closed"), WSGrpcError)
} }
return conn, nil return conn, nil
case <-l.done: case <-l.done:
return nil, fmt.Errorf("listener closed") return nil, errors.Join(fmt.Errorf("listener closed"), WSGrpcError)
} }
} }