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  }