mirror of
https://github.com/anotherhadi/proton-vpn-tui.git
synced 2026-10-05 19:28:28 +02:00
init
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DefaultTimeout = 15 * time.Second
|
||||
|
||||
var BinaryName = "protonvpn"
|
||||
|
||||
var ErrTimeout = errors.New("protonvpn: command timeout")
|
||||
|
||||
var ErrNotFound = errors.New("protonvpn: binary not found in PATH")
|
||||
|
||||
type Result struct {
|
||||
Stdout string
|
||||
Stderr string
|
||||
}
|
||||
|
||||
type CommandError struct {
|
||||
Result *Result
|
||||
Err error
|
||||
}
|
||||
|
||||
const unexpectedErrorBanner = "An unexpected error occurred. Please try again."
|
||||
|
||||
func (e *CommandError) Error() string {
|
||||
if strings.HasPrefix(e.Result.Stderr, unexpectedErrorBanner) ||
|
||||
strings.HasPrefix(e.Result.Stdout, unexpectedErrorBanner) {
|
||||
return unexpectedErrorBanner
|
||||
}
|
||||
if e.Result.Stderr != "" {
|
||||
return fmt.Sprintf("%v (stderr: %q)", e.Err, e.Result.Stderr)
|
||||
}
|
||||
if e.Result.Stdout != "" {
|
||||
return e.Result.Stdout
|
||||
}
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e *CommandError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func IsAuthRequired(err error) bool {
|
||||
var cmdErr *CommandError
|
||||
if !errors.As(err, &cmdErr) {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(cmdErr.Result.Stderr, "protonvpn signin") ||
|
||||
strings.Contains(cmdErr.Result.Stdout, "protonvpn signin")
|
||||
}
|
||||
|
||||
func IsFreePlanRestricted(err error) bool {
|
||||
var cmdErr *CommandError
|
||||
if !errors.As(err, &cmdErr) {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(cmdErr.Result.Stderr, "not available on the free plan") ||
|
||||
strings.Contains(cmdErr.Result.Stdout, "not available on the free plan")
|
||||
}
|
||||
|
||||
func Available() error {
|
||||
if _, err := exec.LookPath(BinaryName); err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Run(ctx context.Context, args ...string) (*Result, error) {
|
||||
if ctx == nil {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(context.Background(), DefaultTimeout)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(ctx, BinaryName, args...)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
runErr := cmd.Run()
|
||||
|
||||
res := &Result{
|
||||
Stdout: strings.TrimSpace(stdout.String()),
|
||||
Stderr: strings.TrimSpace(stderr.String()),
|
||||
}
|
||||
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
return res, &CommandError{Result: res, Err: ErrTimeout}
|
||||
}
|
||||
|
||||
if runErr != nil {
|
||||
return res, &CommandError{Result: res, Err: runErr}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(res.Stdout, "Error:") {
|
||||
return res, &CommandError{Result: res, Err: errors.New(res.Stdout)}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
Reference in New Issue
Block a user