github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/cmd/yuhaiin/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "flag" 6 "fmt" 7 "net" 8 "net/http" 9 "os" 10 "os/signal" 11 "runtime" 12 "strings" 13 "syscall" 14 15 "github.com/Asutorufa/yuhaiin/internal/app" 16 "github.com/Asutorufa/yuhaiin/internal/appapi" 17 "github.com/Asutorufa/yuhaiin/internal/version" 18 "github.com/Asutorufa/yuhaiin/pkg/components/config" 19 "github.com/Asutorufa/yuhaiin/pkg/log" 20 "github.com/Asutorufa/yuhaiin/pkg/net/netapi" 21 "github.com/Asutorufa/yuhaiin/pkg/net/netlink" 22 pc "github.com/Asutorufa/yuhaiin/pkg/protos/config" 23 "github.com/Asutorufa/yuhaiin/pkg/utils/yerror" 24 "golang.org/x/net/http2" 25 "golang.org/x/net/http2/h2c" 26 "google.golang.org/grpc" 27 ) 28 29 var install = func(args []string) error { panic("not implement") } 30 var uninstall = func(args []string) error { panic("not implement") } 31 var restart = func(args []string) error { 32 if err := stop(args); err != nil { 33 return err 34 } 35 return start(args) 36 } 37 var stop = func(args []string) error { panic("not implement") } 38 var start = func(args []string) error { panic("not implement") } 39 var showVersion = func(args []string) error { fmt.Print(version.String()); return nil } 40 41 var subCommand = map[string]*func(args []string) error{ 42 "install": &install, 43 "uninstall": &uninstall, 44 "restart": &restart, 45 "version": &showVersion, 46 "-v": &showVersion, 47 "start": &start, 48 "stop": &stop, 49 } 50 51 func main() { 52 host := flag.String("host", "0.0.0.0:50051", "gRPC and http listen host") 53 path := flag.String("path", pc.DefaultConfigDir(), "save data path") 54 webdir := flag.String("eweb", "", "external web page") 55 flag.Parse() 56 57 if len(os.Args) > 1 { 58 if x, ok := subCommand[strings.ToLower(os.Args[1])]; ok { 59 var args []string 60 for _, v := range os.Args[1:] { 61 if v == "install" || v == "uninstall" || v == "restart" { 62 continue 63 } 64 65 args = append(args, v) 66 } 67 68 if err := (*x)(args); err != nil { 69 log.Error(err.Error()) 70 panic(err) 71 } 72 return 73 } 74 } 75 76 if *webdir != "" && os.Getenv("EXTERNAL_WEB") == "" { 77 os.Setenv("EXTERNAL_WEB", *webdir) 78 } 79 80 setting := config.NewConfig(app.PathGenerator.Config(*path)) 81 grpcserver := grpc.NewServer() 82 83 app, err := app.Start(appapi.Start{ 84 ConfigPath: *path, 85 Host: *host, 86 Setting: setting, 87 GRPCServer: grpcserver, 88 ProcessDumper: getPorcessDumper(), 89 }) 90 if err != nil { 91 log.Error(err.Error()) 92 return 93 } 94 defer app.Close() 95 96 // _ = os.Rename(filepath.Join(*savepath, "pbo.pprof"), 97 // filepath.Join(*savepath, fmt.Sprintf("pbo_%d.pprof", time.Now().Unix()))) 98 // f, err := os.Create(filepath.Join(*savepath, "pbo.pprof")) 99 // if err == nil { 100 // defer f.Close() // error handling omitted for example 101 // // runtime.SetCPUProfileRate(100) 102 // if err := pprof.StartCPUProfile(f); err == nil { 103 // log.Debug("start pprof") 104 // defer pprof.StopCPUProfile() 105 // } else { 106 // f.Close() 107 // log.Error(err.Error()) 108 // } 109 // } else { 110 // log.Error(err.Error()) 111 // } 112 113 errChan := make(chan error) 114 115 go func() { 116 // h2c for grpc insecure mode 117 errChan <- http.Serve(app.HttpListener, h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 118 log.Debug("http request", "host", r.Host, "method", r.Method, "path", r.URL.Path) 119 120 if grpcserver != nil && r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") { 121 grpcserver.ServeHTTP(w, r) 122 } else { 123 app.Mux.ServeHTTP(w, r) 124 } 125 }), &http2.Server{})) 126 }() 127 128 // listen system signal 129 signChannel := make(chan os.Signal, 1) 130 signal.Notify(signChannel, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) 131 132 run(app, errChan, signChannel) 133 } 134 135 var run = func(app *appapi.Components, errChan chan error, signChannel chan os.Signal) { 136 select { 137 case err := <-errChan: 138 log.Error("http server error", "err", err) 139 case <-signChannel: 140 if app.HttpListener != nil { 141 app.HttpListener.Close() 142 } 143 } 144 } 145 146 func getPorcessDumper() netapi.ProcessDumper { 147 if os.Getenv("YUHAIIN_LITE") == "true" { 148 return nil 149 } 150 151 switch runtime.GOOS { 152 case "linux", "darwin", "windows": 153 return processDumperImpl{} 154 } 155 156 return nil 157 } 158 159 type processDumperImpl struct{} 160 161 func (processDumperImpl) ProcessName(network string, src, dst netapi.Address) (string, error) { 162 if src.Type() != netapi.IP || dst.Type() != netapi.IP { 163 return "", fmt.Errorf("source or destination address is not ip") 164 } 165 166 ip := yerror.Ignore(src.IP(context.TODO())) 167 to := yerror.Ignore(dst.IP(context.TODO())) 168 169 if to.IsUnspecified() { 170 if ip.To4() != nil { 171 to = net.IPv4(127, 0, 0, 1) 172 } else { 173 to = net.IPv6loopback 174 } 175 } 176 177 return netlink.FindProcessName(network, ip, src.Port().Port(), 178 to, dst.Port().Port()) 179 }