145 lines
2.8 KiB
Go
145 lines
2.8 KiB
Go
package gotunnelmobile
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/gotunnel/internal/client/tunnel"
|
|
"github.com/gotunnel/pkg/crypto"
|
|
)
|
|
|
|
// Service exposes a gomobile-friendly wrapper around the Go tunnel client.
|
|
type Service struct {
|
|
mu sync.Mutex
|
|
|
|
server string
|
|
token string
|
|
dataDir string
|
|
clientName string
|
|
clientID string
|
|
disableTLS bool
|
|
|
|
client *tunnel.Client
|
|
cancel context.CancelFunc
|
|
running bool
|
|
status string
|
|
lastError string
|
|
}
|
|
|
|
// NewService creates a mobile client service wrapper.
|
|
func NewService() *Service {
|
|
return &Service{status: "stopped"}
|
|
}
|
|
|
|
// Configure stores the parameters used by Start.
|
|
func (s *Service) Configure(server, token, dataDir, clientName, clientID string, disableTLS bool) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
s.server = strings.TrimSpace(server)
|
|
s.token = strings.TrimSpace(token)
|
|
s.dataDir = strings.TrimSpace(dataDir)
|
|
s.clientName = strings.TrimSpace(clientName)
|
|
s.clientID = strings.TrimSpace(clientID)
|
|
s.disableTLS = disableTLS
|
|
}
|
|
|
|
// Start launches the tunnel loop in the background.
|
|
func (s *Service) Start() string {
|
|
s.mu.Lock()
|
|
if s.running {
|
|
s.mu.Unlock()
|
|
return ""
|
|
}
|
|
if s.server == "" || s.token == "" {
|
|
s.mu.Unlock()
|
|
return "server and token are required"
|
|
}
|
|
|
|
features := tunnel.MobilePlatformFeatures()
|
|
client := tunnel.NewClientWithOptions(s.server, s.token, tunnel.ClientOptions{
|
|
DataDir: s.dataDir,
|
|
ClientID: s.clientID,
|
|
ClientName: s.clientName,
|
|
Features: &features,
|
|
})
|
|
if !s.disableTLS {
|
|
client.TLSEnabled = true
|
|
client.TLSConfig = crypto.ClientTLSConfig()
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
s.client = client
|
|
s.cancel = cancel
|
|
s.running = true
|
|
s.status = "running"
|
|
s.lastError = ""
|
|
s.mu.Unlock()
|
|
|
|
go func() {
|
|
err := client.RunContext(ctx)
|
|
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.running = false
|
|
s.cancel = nil
|
|
s.client = nil
|
|
|
|
if err != nil {
|
|
s.status = "error"
|
|
s.lastError = err.Error()
|
|
return
|
|
}
|
|
|
|
if s.status != "stopped" {
|
|
s.status = "stopped"
|
|
}
|
|
}()
|
|
|
|
return ""
|
|
}
|
|
|
|
// Stop cancels the running tunnel loop.
|
|
func (s *Service) Stop() string {
|
|
s.mu.Lock()
|
|
cancel := s.cancel
|
|
s.cancel = nil
|
|
s.running = false
|
|
s.status = "stopped"
|
|
s.mu.Unlock()
|
|
|
|
if cancel != nil {
|
|
cancel()
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// Restart restarts the service with the stored configuration.
|
|
func (s *Service) Restart() string {
|
|
s.Stop()
|
|
return s.Start()
|
|
}
|
|
|
|
// IsRunning reports whether the tunnel loop is active.
|
|
func (s *Service) IsRunning() bool {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
return s.running
|
|
}
|
|
|
|
// Status returns a coarse-grained runtime status.
|
|
func (s *Service) Status() string {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
return s.status
|
|
}
|
|
|
|
// LastError returns the last background error string, if any.
|
|
func (s *Service) LastError() string {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
return s.lastError
|
|
}
|