package gitService import ( "encoding/json" "fmt" "g-launcher/pkg/constant" "g-launcher/pkg/models" "io" "net/http" "os" "path/filepath" "strings" "time" "github.com/wailsapp/wails/v3/pkg/application" ) func (g *GitService) GetLatestServerVersion() (bool, string, string) { client := &http.Client{Timeout: 15 * time.Second} resp, err := client.Get(constant.ServerGitUrl) if err != nil { return false, "", err.Error() } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return false, "", err.Error() } var releases []models.ReleaseType err = json.Unmarshal(body, &releases) if err != nil { return false, "", err.Error() } if len(releases) == 0 { return false, "", "no releases found" } return true, releases[0].TagName, "" } func (g *GitService) DownloadServerProgress(version string) (bool, string) { client := &http.Client{Timeout: 15 * time.Second} resp, err := client.Get(constant.ServerGitUrl) if err != nil { return false, fmt.Sprintf("fetch server releases: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return false, fmt.Sprintf("read server releases: %v", err) } var releases []*models.ReleaseType if err := json.Unmarshal(body, &releases); err != nil || len(releases) == 0 { return false, "no releases found on server repository" } var targetRelease *models.ReleaseType for _, rel := range releases { if rel.TagName == version { targetRelease = rel break } } if targetRelease == nil && len(releases) > 0 { targetRelease = releases[0] } if targetRelease == nil { return false, "could not find server release matching version " + version } if err := os.MkdirAll(constant.ServerStorageUrl, 0755); err != nil { return false, err.Error() } // 1. Search for .zip asset var zipAsset *models.AssetType for _, asset := range targetRelease.Assets { if strings.HasSuffix(strings.ToLower(asset.Name), ".zip") { aCopy := asset zipAsset = &aCopy break } } if zipAsset != nil { // Case A: ZIP archive found saveZipPath := filepath.Join(constant.ServerStorageUrl, zipAsset.Name) tmpPath, err := g.downloadFileParallel(saveZipPath, zipAsset.BrowserDownloadURL, 4, func(percent float64, speed string) { application.Get().Event.Emit("download:server", map[string]interface{}{ "percent": fmt.Sprintf("%.2f", percent), "speed": speed, }) }) if err != nil { return false, fmt.Sprintf("download server zip: %v", err) } renamed := false for i := 0; i < 3; i++ { if err := os.Rename(tmpPath, saveZipPath); err == nil { renamed = true break } time.Sleep(300 * time.Millisecond) } if !renamed { os.Remove(tmpPath) return false, "failed to rename downloaded server zip" } // Unzip immediately if err := g.unzipParallel(saveZipPath, constant.ServerStorageUrl); err != nil { return false, fmt.Sprintf("unzip server: %v", err) } os.Remove(saveZipPath) return true, "" } // Case B: No ZIP archive, download sdkserver and server executables var sdkAsset, serverAsset *models.AssetType for _, asset := range targetRelease.Assets { nameLower := strings.ToLower(asset.Name) if strings.Contains(nameLower, "sdkserver") { aCopy := asset sdkAsset = &aCopy } else if strings.Contains(nameLower, "server") { aCopy := asset serverAsset = &aCopy } } if sdkAsset == nil && serverAsset == nil { return false, "no zip or server executable assets found in release" } if sdkAsset != nil { saveSdk := filepath.Join(constant.ServerStorageUrl, sdkAsset.Name) tmpPath, err := g.downloadFileParallel(saveSdk, sdkAsset.BrowserDownloadURL, 4, func(percent float64, speed string) { application.Get().Event.Emit("download:server", map[string]interface{}{ "percent": fmt.Sprintf("%.2f", percent*0.5), "speed": speed, }) }) if err == nil { _ = os.Rename(tmpPath, saveSdk) } } if serverAsset != nil { saveServer := filepath.Join(constant.ServerStorageUrl, serverAsset.Name) tmpPath, err := g.downloadFileParallel(saveServer, serverAsset.BrowserDownloadURL, 4, func(percent float64, speed string) { application.Get().Event.Emit("download:server", map[string]interface{}{ "percent": fmt.Sprintf("%.2f", 50.0+percent*0.5), "speed": speed, }) }) if err == nil { _ = os.Rename(tmpPath, saveServer) } } return true, "" } func (g *GitService) UnzipServer() { entries, err := os.ReadDir(constant.ServerStorageUrl) if err != nil { return } for _, entry := range entries { if !entry.IsDir() && strings.HasSuffix(strings.ToLower(entry.Name()), ".zip") { zipPath := filepath.Join(constant.ServerStorageUrl, entry.Name()) _ = g.unzipParallel(zipPath, constant.ServerStorageUrl) _ = os.Remove(zipPath) } } } func (g *GitService) FindServerExecutables() (string, string) { serverDir := constant.ServerStorageUrl var gameServer, sdkServer string // Candidate filenames for game server for _, name := range []string{"gameserver-go.exe", "server.exe", "gameserver.exe", "firefly-go_win.exe"} { p := filepath.Join(serverDir, name) if info, err := os.Stat(p); err == nil && !info.IsDir() { gameServer = p break } } // Candidate filenames for sdk server for _, name := range []string{"sdkserver-go.exe", "sdkserver.exe"} { p := filepath.Join(serverDir, name) if info, err := os.Stat(p); err == nil && !info.IsDir() { sdkServer = p break } } return gameServer, sdkServer }