// inp2pc — INP2P P2P Client package main import ( "encoding/json" "flag" "fmt" "log" "os" "os/signal" "syscall" "github.com/openp2p-cn/inp2p/internal/client" "github.com/openp2p-cn/inp2p/pkg/auth" "github.com/openp2p-cn/inp2p/pkg/config" ) func main() { cfg := config.DefaultClientConfig() flag.StringVar(&cfg.ServerHost, "serverhost", "", "Server hostname or IP (required)") flag.IntVar(&cfg.ServerPort, "serverport", cfg.ServerPort, "Server WSS port") flag.StringVar(&cfg.Node, "node", "", "Node name (default: hostname)") token := flag.Uint64("token", 0, "Authentication token (uint64)") user := flag.String("user", "", "Username for token generation") pass := flag.String("password", "", "Password for token generation") flag.BoolVar(&cfg.Insecure, "insecure", false, "Skip TLS verification") flag.BoolVar(&cfg.RelayEnabled, "relay", false, "Enable relay capability") flag.BoolVar(&cfg.SuperRelay, "super", false, "Register as super relay node (implies -relay)") flag.IntVar(&cfg.RelayPort, "relay-port", cfg.RelayPort, "Relay listen port") flag.IntVar(&cfg.MaxRelayLoad, "relay-max", cfg.MaxRelayLoad, "Max concurrent relay sessions") flag.IntVar(&cfg.ShareBandwidth, "bw", cfg.ShareBandwidth, "Share bandwidth (Mbps)") flag.IntVar(&cfg.STUNUDP1, "stun-udp1", cfg.STUNUDP1, "UDP STUN port 1") flag.IntVar(&cfg.STUNUDP2, "stun-udp2", cfg.STUNUDP2, "UDP STUN port 2") flag.IntVar(&cfg.STUNTCP1, "stun-tcp1", cfg.STUNTCP1, "TCP STUN port 1") flag.IntVar(&cfg.STUNTCP2, "stun-tcp2", cfg.STUNTCP2, "TCP STUN port 2") flag.IntVar(&cfg.LogLevel, "log-level", cfg.LogLevel, "Log level") configFile := flag.String("config", "config.json", "Config file path") newConfig := flag.Bool("newconfig", false, "Ignore existing config, use command line args only") version := flag.Bool("version", false, "Print version and exit") flag.Parse() if *version { fmt.Printf("inp2pc version %s\ncommit: %s\nbuild: %s\ngo: %s\n", config.Version, config.GitCommit, config.BuildTime, config.GoVersion) os.Exit(0) } // Load config file first (unless -newconfig) if !*newConfig { if data, err := os.ReadFile(*configFile); err == nil { var fileCfg config.ClientConfig if err := json.Unmarshal(data, &fileCfg); err == nil { cfg = fileCfg // fill defaults for missing fields if cfg.ServerPort == 0 { cfg.ServerPort = config.DefaultWSPort } if cfg.STUNUDP1 == 0 { cfg.STUNUDP1 = config.DefaultSTUNUDP1 } if cfg.STUNUDP2 == 0 { cfg.STUNUDP2 = config.DefaultSTUNUDP2 } if cfg.STUNTCP1 == 0 { cfg.STUNTCP1 = config.DefaultSTUNTCP1 } if cfg.STUNTCP2 == 0 { cfg.STUNTCP2 = config.DefaultSTUNTCP2 } if cfg.RelayPort == 0 { cfg.RelayPort = config.DefaultRelayPort } if cfg.MaxRelayLoad == 0 { cfg.MaxRelayLoad = config.DefaultMaxRelayLoad } if cfg.ShareBandwidth == 0 { cfg.ShareBandwidth = 10 } if cfg.LogLevel == 0 { cfg.LogLevel = 1 } log.Printf("[main] loaded config from %s", *configFile) } } } // Command line flags override config file flag.Visit(func(f *flag.Flag) { switch f.Name { case "serverhost": cfg.ServerHost = f.Value.String() case "serverport": fmt.Sscanf(f.Value.String(), "%d", &cfg.ServerPort) case "node": cfg.Node = f.Value.String() case "insecure": cfg.Insecure = true case "relay": cfg.RelayEnabled = true case "super": cfg.SuperRelay = true cfg.RelayEnabled = true // super implies relay case "bw": fmt.Sscanf(f.Value.String(), "%d", &cfg.ShareBandwidth) } }) // Token from flag or credentials if *token > 0 { cfg.Token = *token } else if *user != "" && *pass != "" { cfg.Token = auth.MakeToken(*user, *pass) log.Printf("[main] token: %d", cfg.Token) } if err := cfg.Validate(); err != nil { log.Fatalf("[main] config error: %v", err) } log.Printf("[main] inp2pc v%s starting", config.Version) log.Printf("[main] node=%s server=%s:%d relay=%v super=%v", cfg.Node, cfg.ServerHost, cfg.ServerPort, cfg.RelayEnabled, cfg.SuperRelay) // Save config if data, err := json.MarshalIndent(cfg, "", " "); err == nil { os.WriteFile(*configFile, data, 0644) } // Create and run client c := client.New(cfg) // Handle shutdown sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) go func() { <-sigCh log.Println("[main] shutting down...") c.Stop() }() if err := c.Run(); err != nil { log.Fatalf("[main] client error: %v", err) } log.Println("[main] goodbye") }