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 }