github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/cmd/android/yuhaiin.go (about)

     1  package yuhaiin
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"runtime"
     9  	"sync"
    10  	"sync/atomic"
    11  
    12  	"github.com/Asutorufa/yuhaiin/internal/app"
    13  	"github.com/Asutorufa/yuhaiin/internal/appapi"
    14  	"github.com/Asutorufa/yuhaiin/pkg/log"
    15  	"github.com/Asutorufa/yuhaiin/pkg/net/dialer"
    16  	"google.golang.org/protobuf/types/known/wrapperspb"
    17  )
    18  
    19  type App struct {
    20  	app *appapi.Components
    21  	lis *http.Server
    22  
    23  	mu      sync.Mutex
    24  	started atomic.Bool
    25  }
    26  
    27  func (a *App) Start(opt *Opts) error {
    28  	a.mu.Lock()
    29  	defer a.mu.Unlock()
    30  
    31  	if a.started.Load() {
    32  		return errors.New("yuhaiin is already running")
    33  	}
    34  
    35  	errChan := make(chan error)
    36  
    37  	go func() {
    38  		defer a.started.Store(false)
    39  
    40  		dialer.DefaultMarkSymbol = opt.TUN.SocketProtect.Protect
    41  
    42  		app, err := app.Start(
    43  			appapi.Start{
    44  				ConfigPath:    opt.Savepath,
    45  				Setting:       fakeSetting(opt, app.PathGenerator.Config(opt.Savepath)),
    46  				Host:          opt.Host,
    47  				ProcessDumper: NewUidDumper(opt.TUN.UidDumper),
    48  			})
    49  		if err != nil {
    50  			errChan <- err
    51  			return
    52  		}
    53  		defer app.Close()
    54  
    55  		a.app = app
    56  
    57  		lis := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    58  			log.Debug("http request", "host", r.Host, "method", r.Method, "path", r.URL.Path)
    59  			app.Mux.ServeHTTP(w, r)
    60  		})}
    61  		defer lis.Close()
    62  
    63  		a.lis = lis
    64  		a.started.Store(true)
    65  
    66  		close(errChan)
    67  		defer opt.CloseFallback.Close()
    68  
    69  		if err := a.lis.Serve(app.HttpListener); err != nil {
    70  			log.Error("yuhaiin serve failed", "err", err)
    71  		}
    72  	}()
    73  
    74  	return <-errChan
    75  }
    76  
    77  func (a *App) Stop() error {
    78  	a.mu.Lock()
    79  	defer a.mu.Unlock()
    80  
    81  	if !a.Running() {
    82  		return nil
    83  	}
    84  
    85  	if a.lis != nil {
    86  		err := a.lis.Close()
    87  		if err != nil {
    88  			return err
    89  		}
    90  	}
    91  
    92  	for a.Running() {
    93  		runtime.Gosched()
    94  	}
    95  
    96  	a.app = nil
    97  	a.lis = nil
    98  
    99  	return nil
   100  }
   101  
   102  func (a *App) Running() bool { return a.started.Load() }
   103  
   104  func (a *App) SaveNewBypass(link string) error {
   105  	if !a.Running() || a.app == nil || a.app.Tools == nil {
   106  		return fmt.Errorf("proxy service is not start")
   107  	}
   108  
   109  	_, err := a.app.Tools.SaveRemoteBypassFile(context.TODO(), &wrapperspb.StringValue{Value: link})
   110  	return err
   111  }