diff --git a/internal/vpn/client.go b/internal/vpn/client.go index 3a3e1226ec..e13d85181a 100644 --- a/internal/vpn/client.go +++ b/internal/vpn/client.go @@ -20,9 +20,6 @@ import ( "github.com/skycoin/skywire-utilities/pkg/netutil" "github.com/skycoin/skywire/pkg/app" "github.com/skycoin/skywire/pkg/app/appnet" - "github.com/skycoin/skywire/pkg/app/appserver" - "github.com/skycoin/skywire/pkg/routefinder/rfclient" - "github.com/skycoin/skywire/pkg/router" "github.com/skycoin/skywire/pkg/routing" "github.com/skycoin/skywire/pkg/skyenv" ) @@ -189,17 +186,9 @@ func (c *Client) Serve() error { c.setAppStatus(ClientStatusConnecting) - errNoTransportFound := appserver.RPCErr{ - Err: router.ErrNoTransportFound.Error(), - } - - errTransportNotFound := appserver.RPCErr{ - Err: rfclient.ErrTransportNotFound.Error(), - } - r := netutil.NewRetrier(c.log, netutil.DefaultInitBackoff, netutil.DefaultMaxBackoff, 3, netutil.DefaultFactor). WithErrWhitelist(errHandshakeStatusForbidden, errHandshakeStatusInternalError, errHandshakeNoFreeIPs, - errHandshakeStatusBadRequest, errNoTransportFound, errTransportNotFound) + errHandshakeStatusBadRequest, errNoTransportFound, errTransportNotFound, errErrSetupNode) err := r.Do(context.Background(), func() error { if c.isClosed() { @@ -209,7 +198,7 @@ func (c *Client) Serve() error { if err := c.dialServeConn(); err != nil { switch err { case errHandshakeStatusForbidden, errHandshakeStatusInternalError, errHandshakeNoFreeIPs, - errHandshakeStatusBadRequest, errNoTransportFound, errTransportNotFound: + errHandshakeStatusBadRequest, errNoTransportFound, errTransportNotFound, errErrSetupNode: c.setAppError(err) c.resetConnDuration() return err diff --git a/internal/vpn/errors.go b/internal/vpn/errors.go index 30ec471af5..2d0407c49f 100644 --- a/internal/vpn/errors.go +++ b/internal/vpn/errors.go @@ -1,6 +1,13 @@ package vpn -import "errors" +import ( + "errors" + + "github.com/skycoin/skywire/pkg/app/appserver" + "github.com/skycoin/skywire/pkg/routefinder/rfclient" + "github.com/skycoin/skywire/pkg/router" + "github.com/skycoin/skywire/pkg/setup/setupclient" +) var ( errCouldFindDefaultNetworkGateway = errors.New("Could not find default network gateway") @@ -9,4 +16,14 @@ var ( errHandshakeNoFreeIPs = errors.New("No free IPs left to serve") errHandshakeStatusBadRequest = errors.New("Request was malformed") errTimeout = errors.New("Internal error: Timeout") + + errNoTransportFound = appserver.RPCErr{ + Err: router.ErrNoTransportFound.Error(), + } + errTransportNotFound = appserver.RPCErr{ + Err: rfclient.ErrTransportNotFound.Error(), + } + errErrSetupNode = appserver.RPCErr{ + Err: setupclient.ErrSetupNode.Error(), + } ) diff --git a/pkg/setup/setupclient/client.go b/pkg/setup/setupclient/client.go index 9e6db0441f..0958d1f188 100644 --- a/pkg/setup/setupclient/client.go +++ b/pkg/setup/setupclient/client.go @@ -16,6 +16,9 @@ import ( const rpcName = "RPCGateway" +// ErrSetupNode is used when the visor is unable to connect to a setup node +var ErrSetupNode = errors.New("failed to dial to a setup node") + // Client is an RPC client for setup node. type Client struct { log *logging.Logger @@ -55,7 +58,7 @@ func (c *Client) dial(ctx context.Context, dmsgC *dmsg.Client) (net.Conn, error) return conn, nil } - return nil, errors.New("failed to dial to a setup node") + return nil, ErrSetupNode } // Close closes a Client. diff --git a/pkg/visor/api.go b/pkg/visor/api.go index b141a2b0c7..9164eab4e3 100644 --- a/pkg/visor/api.go +++ b/pkg/visor/api.go @@ -49,6 +49,7 @@ type API interface { SetAppKillswitch(appName string, killswitch bool) error LogsSince(timestamp time.Time, appName string) ([]string, error) GetAppStats(appName string) (appserver.AppStats, error) + GetAppError(appName string) (string, error) GetAppConnectionsSummary(appName string) ([]appserver.ConnectionSummary, error) TransportTypes() ([]string, error) @@ -508,6 +509,12 @@ func (v *Visor) GetAppStats(appName string) (appserver.AppStats, error) { return stats, nil } +// GetAppError implements API. +func (v *Visor) GetAppError(appName string) (string, error) { + appErr, _ := v.procM.ErrorByName(appName) + return appErr, nil +} + // GetAppConnectionsSummary implements API. func (v *Visor) GetAppConnectionsSummary(appName string) ([]appserver.ConnectionSummary, error) { cSummary, err := v.procM.ConnectionsSummary(appName) diff --git a/pkg/visor/rpc.go b/pkg/visor/rpc.go index e3485d9787..5e4f3d363a 100644 --- a/pkg/visor/rpc.go +++ b/pkg/visor/rpc.go @@ -298,6 +298,18 @@ func (r *RPC) GetAppStats(appName *string, out *appserver.AppStats) (err error) return err } +// GetAppError gets app runtime error. +func (r *RPC) GetAppError(appName *string, out *string) (err error) { + defer rpcutil.LogCall(r.log, "GetAppError", appName)(out, &err) + + stats, err := r.visor.GetAppError(*appName) + if err != nil { + *out = stats + } + + return err +} + // GetAppConnectionsSummary returns connections stats for the app. func (r *RPC) GetAppConnectionsSummary(appName *string, out *[]appserver.ConnectionSummary) (err error) { defer rpcutil.LogCall(r.log, "GetAppConnectionsSummary", appName)(out, &err) diff --git a/pkg/visor/rpc_client.go b/pkg/visor/rpc_client.go index ea4e21906e..0534b4dba8 100644 --- a/pkg/visor/rpc_client.go +++ b/pkg/visor/rpc_client.go @@ -223,6 +223,16 @@ func (rc *rpcClient) GetAppStats(appName string) (appserver.AppStats, error) { return stats, nil } +func (rc *rpcClient) GetAppError(appName string) (string, error) { + var appErr string + + if err := rc.Call("GetAppError", &appName, &appErr); err != nil { + return appErr, err + } + + return appErr, nil +} + // GetAppConnectionsSummary get connections stats for the app. func (rc *rpcClient) GetAppConnectionsSummary(appName string) ([]appserver.ConnectionSummary, error) { var summary []appserver.ConnectionSummary @@ -787,6 +797,10 @@ func (mc *mockRPCClient) GetAppStats(_ string) (appserver.AppStats, error) { return appserver.AppStats{}, nil } +func (mc *mockRPCClient) GetAppError(_ string) (string, error) { + return "", nil +} + // GetAppConnectionsSummary get connections stats for the app. func (mc *mockRPCClient) GetAppConnectionsSummary(_ string) ([]appserver.ConnectionSummary, error) { return nil, nil