Files
tailscale-vpn/internal/services/vpn_service.go
2026-04-10 01:46:57 +09:00

67 lines
1.5 KiB
Go

package services
import (
"bytes"
"context"
"log/slog"
"os/exec"
"strings"
)
type VPNService struct{
Config *ConfigService
}
func NewVPNService(cfg *ConfigService) *VPNService {
return &VPNService{
Config: cfg,
}
}
func (v *VPNService) CheckStatus(ctx context.Context) (bool, error) {
cmd := exec.CommandContext(ctx, "tailscale", "exit-node", "list")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
slog.ErrorContext(ctx, "failed to check VPN status", "error", err)
return false, err
}
output := out.String()
return strings.Contains(output, "selected"), nil
}
func (v *VPNService) TurnOn(ctx context.Context) error {
selectedServer, _ := v.Config.GetSelectedServer()
cmd := exec.CommandContext(ctx, "sudo", "tailscale", "set", "--exit-node="+selectedServer.Host)
if err := cmd.Run(); err != nil {
slog.ErrorContext(ctx, "failed to turn on VPN", "error", err)
return err
}
return nil
}
func (v *VPNService) TurnOff(ctx context.Context) error {
cmd := exec.CommandContext(ctx, "sudo", "tailscale", "set", "--exit-node=")
if err := cmd.Run(); err != nil {
slog.ErrorContext(ctx, "failed to turn off VPN", "error", err)
return err
}
return nil
}
func (v *VPNService) ExitNodeList(ctx context.Context) (string, error) {
cmd := exec.CommandContext(ctx, "tailscale", "exit-node", "list")
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
slog.ErrorContext(ctx, "failed to get exit node list", "error", err)
return "", err
}
return out.String(), nil
}