mirror of Walter-Sparrow / lunar-tear
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Enhance wizard CLI with dynamic port configuration for gRPC, CDN, and Auth services

+143 -21
+16
README.md
··· 26 26 27 27 Your choices are saved so next time you just press Enter to relaunch with the same settings. 28 28 29 + #### Custom Ports 30 + 31 + By default the wizard uses ports 8003 (gRPC), 8080 (CDN), and 3000 (auth). Override any of them with flags: 32 + 33 + ```bash 34 + go run ./cmd/wizard --grpc-port 9003 --cdn-port 9080 35 + ``` 36 + 37 + | Flag | Default | Description | 38 + | ------------- | ------- | ---------------- | 39 + | `--grpc-port` | `8003` | gRPC server port | 40 + | `--cdn-port` | `8080` | CDN server port | 41 + | `--auth-port` | `3000` | Auth server port | 42 + 43 + Custom ports are saved to `.wizard.json` alongside your other settings. On the next run the saved ports are reused automatically — no need to pass the flags again. If you later pass different port flags, the wizard warns you that the ports changed and asks for confirmation before continuing. 44 + 29 45 ### Regenerate protobuf stubs 30 46 31 47 ```bash
+127 -21
server/cmd/wizard/main.go
··· 32 32 ) 33 33 34 34 type config struct { 35 - IP string `json:"ip"` 36 - Device string `json:"device"` 37 - Detail string `json:"detail"` 38 - Summary string `json:"summary"` 35 + IP string `json:"ip"` 36 + Device string `json:"device"` 37 + Detail string `json:"detail"` 38 + Summary string `json:"summary"` 39 + GRPCPort int `json:"grpc_port,omitempty"` 40 + CDNPort int `json:"cdn_port,omitempty"` 41 + AuthPort int `json:"auth_port,omitempty"` 42 + } 43 + 44 + const ( 45 + defaultGRPCPort = 8003 46 + defaultCDNPort = 8080 47 + defaultAuthPort = 3000 48 + ) 49 + 50 + type ports struct { 51 + GRPC int 52 + CDN int 53 + Auth int 39 54 } 40 55 41 56 func main() { 42 57 setupOnly := flag.Bool("setup-only", false, "show patching instructions and exit without building or launching") 58 + grpcPort := flag.Int("grpc-port", defaultGRPCPort, "gRPC server port") 59 + cdnPort := flag.Int("cdn-port", defaultCDNPort, "CDN server port") 60 + authPort := flag.Int("auth-port", defaultAuthPort, "auth server port") 43 61 flag.Parse() 44 62 63 + flagSet := map[string]bool{} 64 + flag.Visit(func(f *flag.Flag) { flagSet[f.Name] = true }) 65 + 45 66 lipgloss.EnableLegacyWindowsANSI(os.Stdout) 46 67 lipgloss.EnableLegacyWindowsANSI(os.Stderr) 47 68 ··· 58 79 59 80 ip, cfg, firstRun := resolveIP() 60 81 82 + p := resolvePorts(flagSet, *grpcPort, *cdnPort, *authPort, cfg) 83 + savedPorts := portsFromConfig(cfg) 84 + 85 + if !firstRun && (p.GRPC != savedPorts.GRPC || p.CDN != savedPorts.CDN || p.Auth != savedPorts.Auth) { 86 + if !warnPortChange(savedPorts, p) { 87 + os.Exit(0) 88 + } 89 + } 90 + 91 + cfg.GRPCPort = p.GRPC 92 + cfg.CDNPort = p.CDN 93 + cfg.AuthPort = p.Auth 61 94 saveConfig(cfg) 62 95 63 96 labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8")).Width(14) 64 97 addrStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("12")) 65 98 66 99 fmt.Println() 67 - fmt.Printf(" %s %s\n", labelStyle.Render("Game server:"), addrStyle.Render(ip+":8003")) 68 - fmt.Printf(" %s %s\n", labelStyle.Render("CDN:"), addrStyle.Render(ip+":8080")) 69 - fmt.Printf(" %s %s\n", labelStyle.Render("Auth:"), addrStyle.Render(ip+":3000")) 100 + fmt.Printf(" %s %s\n", labelStyle.Render("Game server:"), addrStyle.Render(fmt.Sprintf("%s:%d", ip, p.GRPC))) 101 + fmt.Printf(" %s %s\n", labelStyle.Render("CDN:"), addrStyle.Render(fmt.Sprintf("%s:%d", ip, p.CDN))) 102 + fmt.Printf(" %s %s\n", labelStyle.Render("Auth:"), addrStyle.Render(fmt.Sprintf("%s:%d", ip, p.Auth))) 70 103 fmt.Println() 71 104 72 105 if firstRun || *setupOnly { 73 - showPatcherHint(ip, !*setupOnly) 106 + showPatcherHint(ip, p, !*setupOnly) 74 107 } 75 108 76 109 if *setupOnly { 77 110 return 78 111 } 79 112 80 - launchDev(ip) 113 + launchDev(ip, p) 81 114 } 82 115 83 116 type assetCheck struct { ··· 348 381 349 382 switch action { 350 383 case "update": 351 - warnRepatch(cfg.IP, current) 384 + warnRepatch(cfg.IP, current, portsFromConfig(cfg)) 352 385 var ack bool 353 386 _ = huh.NewConfirm(). 354 387 Title("Continue launching the server?"). ··· 368 401 } 369 402 } 370 403 371 - func warnRepatch(oldIP, newIP string) { 404 + func warnPortChange(old, new ports) bool { 405 + warnStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("11")) 406 + dimStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8")) 407 + hlStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("12")) 408 + 409 + portLine := func(label string, oldP, newP int) string { 410 + if oldP == newP { 411 + return dimStyle.Render(fmt.Sprintf(" %-7s %d (unchanged)", label+":", oldP)) 412 + } 413 + return hlStyle.Render(fmt.Sprintf(" %-7s %d → %d", label+":", oldP, newP)) 414 + } 415 + 416 + var b strings.Builder 417 + b.WriteString("\n") 418 + b.WriteString(warnStyle.Render(" ⚠ Port configuration changed from last run.")) 419 + b.WriteString("\n\n") 420 + b.WriteString(portLine("gRPC", old.GRPC, new.GRPC)) 421 + b.WriteString("\n") 422 + b.WriteString(portLine("CDN", old.CDN, new.CDN)) 423 + b.WriteString("\n") 424 + b.WriteString(portLine("Auth", old.Auth, new.Auth)) 425 + b.WriteString("\n\n") 426 + b.WriteString(dimStyle.Render(" Your APK was patched for the old ports. You may need to re-patch.")) 427 + b.WriteString("\n\n") 428 + fmt.Print(b.String()) 429 + 430 + cont := true 431 + err := huh.NewConfirm(). 432 + Title("Continue with new ports?"). 433 + Affirmative("Yes, continue"). 434 + Negative("No, exit"). 435 + Value(&cont). 436 + Run() 437 + if err != nil { 438 + os.Exit(1) 439 + } 440 + return cont 441 + } 442 + 443 + func warnRepatch(oldIP, newIP string, p ports) { 372 444 warnStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("11")) 373 445 dimStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8")) 374 446 hlStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("12")) ··· 386 458 b.WriteString("\n\n") 387 459 b.WriteString(dimStyle.Render(" Update the Configuration cell with the new addresses:")) 388 460 b.WriteString("\n\n") 389 - b.WriteString(hlStyle.Render(fmt.Sprintf(" grpc_addr = \"%s:8003\"", newIP))) 461 + b.WriteString(hlStyle.Render(fmt.Sprintf(" grpc_addr = \"%s:%d\"", newIP, p.GRPC))) 390 462 b.WriteString("\n") 391 - b.WriteString(hlStyle.Render(fmt.Sprintf(" http_addr = \"%s:8080\"", newIP))) 463 + b.WriteString(hlStyle.Render(fmt.Sprintf(" http_addr = \"%s:%d\"", newIP, p.CDN))) 392 464 b.WriteString("\n") 393 - b.WriteString(hlStyle.Render(fmt.Sprintf(" auth_host = \"%s:3000\"", newIP))) 465 + b.WriteString(hlStyle.Render(fmt.Sprintf(" auth_host = \"%s:%d\"", newIP, p.Auth))) 394 466 b.WriteString("\n\n") 395 467 fmt.Print(b.String()) 396 468 } 397 469 398 - func showPatcherHint(ip string, askLaunch bool) { 470 + func showPatcherHint(ip string, p ports, askLaunch bool) { 399 471 headStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("11")) 400 472 dimStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8")) 401 473 hlStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("12")) ··· 420 492 b.WriteString("\n\n") 421 493 b.WriteString(dimStyle.Render(" Set these in the notebook's Configuration cell:")) 422 494 b.WriteString("\n\n") 423 - b.WriteString(hlStyle.Render(fmt.Sprintf(" grpc_addr = \"%s:8003\"", ip))) 495 + b.WriteString(hlStyle.Render(fmt.Sprintf(" grpc_addr = \"%s:%d\"", ip, p.GRPC))) 424 496 b.WriteString("\n") 425 - b.WriteString(hlStyle.Render(fmt.Sprintf(" http_addr = \"%s:8080\"", ip))) 497 + b.WriteString(hlStyle.Render(fmt.Sprintf(" http_addr = \"%s:%d\"", ip, p.CDN))) 426 498 b.WriteString("\n") 427 - b.WriteString(hlStyle.Render(fmt.Sprintf(" auth_host = \"%s:3000\"", ip))) 499 + b.WriteString(hlStyle.Render(fmt.Sprintf(" auth_host = \"%s:%d\"", ip, p.Auth))) 428 500 b.WriteString("\n\n") 429 501 b.WriteString(dimStyle.Render(" Then run all cells — a patched APK will download automatically.")) 430 502 b.WriteString("\n\n") ··· 683 755 return cfg, nil 684 756 } 685 757 758 + func portsFromConfig(cfg config) ports { 759 + p := ports{GRPC: cfg.GRPCPort, CDN: cfg.CDNPort, Auth: cfg.AuthPort} 760 + if p.GRPC == 0 { 761 + p.GRPC = defaultGRPCPort 762 + } 763 + if p.CDN == 0 { 764 + p.CDN = defaultCDNPort 765 + } 766 + if p.Auth == 0 { 767 + p.Auth = defaultAuthPort 768 + } 769 + return p 770 + } 771 + 772 + func resolvePorts(flagSet map[string]bool, grpcFlag, cdnFlag, authFlag int, saved config) ports { 773 + resolve := func(name string, flagVal, savedVal, defaultVal int) int { 774 + if flagSet[name] { 775 + return flagVal 776 + } 777 + if savedVal != 0 { 778 + return savedVal 779 + } 780 + return defaultVal 781 + } 782 + return ports{ 783 + GRPC: resolve("grpc-port", grpcFlag, saved.GRPCPort, defaultGRPCPort), 784 + CDN: resolve("cdn-port", cdnFlag, saved.CDNPort, defaultCDNPort), 785 + Auth: resolve("auth-port", authFlag, saved.AuthPort, defaultAuthPort), 786 + } 787 + } 788 + 686 789 func saveConfig(cfg config) { 687 790 data, err := json.MarshalIndent(cfg, "", " ") 688 791 if err != nil { ··· 691 794 _ = os.WriteFile(configFile, append(data, '\n'), 0644) 692 795 } 693 796 694 - func launchDev(ip string) { 797 + func launchDev(ip string, p ports) { 695 798 cmd := exec.Command("go", "run", "./cmd/dev", 696 - "--cdn.public-addr", ip+":8080", 697 - "--grpc.public-addr", ip+":8003", 799 + "--grpc.listen", fmt.Sprintf("0.0.0.0:%d", p.GRPC), 800 + "--grpc.public-addr", fmt.Sprintf("%s:%d", ip, p.GRPC), 801 + "--cdn.listen", fmt.Sprintf("0.0.0.0:%d", p.CDN), 802 + "--cdn.public-addr", fmt.Sprintf("%s:%d", ip, p.CDN), 803 + "--auth.listen", fmt.Sprintf("0.0.0.0:%d", p.Auth), 698 804 ) 699 805 cmd.Stdout = os.Stdout 700 806 cmd.Stderr = os.Stderr