package main import ( "bytes" "crypto/sha1" "encoding/hex" "encoding/json" "fmt" "io" "net/http" "os" "path/filepath" "strings" wruntime "github.com/wailsapp/wails/v2/pkg/runtime" ) type Fabric struct { } type FabricDefinition struct { Separator string Build int Maven string Version string Stable bool } type FabricLibrary struct { Name string Url string Sha1 string } type FabricLibraries struct { Client []FabricLibrary Common []FabricLibrary Server []FabricLibrary } type FabricMeta struct { Version int Libraries FabricLibraries MainClass map[string]string } type FabricVersion struct { Loader FabricDefinition Intermediary FabricDefinition LauncherMeta FabricMeta } func (Fabric) GetFabricVersions(mcVersion string) ([]FabricVersion, error) { resp, err := http.Get("https://meta.fabricmc.net/v2/versions/loader/" + mcVersion) if err != nil { return []FabricVersion{}, fmt.Errorf("Unable to pull fabric version manifest: %s\n", err) } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) versions := []FabricVersion{} json.Unmarshal(data, &versions) return versions, nil } func GetFabricMetadata(mcVersion string, fabricVersion string) (FabricVersion, error) { versions, err := Fabric{}.GetFabricVersions(mcVersion) if err != nil { return FabricVersion{}, fmt.Errorf("unable to download versions manifest: %e\n", err) } for _, version := range versions { if version.Loader.Version == fabricVersion { return version, nil } } return FabricVersion{}, fmt.Errorf("Unable to find requested version.\n") } func InstallLib(lib FabricLibrary, libDir string, a *App) { a.Status(fmt.Sprintf("Checking %s\n", lib.Name)) path := filepath.Join(ProcessMavenPath(lib.Name), ProcessMavenFilename(lib.Name)) if _, err := os.Stat(filepath.Join(libDir, path)); err == nil { f, _ := os.OpenFile(filepath.Join(libDir, path), os.O_RDONLY, 0755) defer f.Close() data, _ := io.ReadAll(f) sha := sha1.Sum(data) if hex.EncodeToString(sha[:20]) == lib.Sha1 { return } } a.Status(fmt.Sprintf("Downloading %s\n", lib.Name)) resp, err := http.Get(lib.Url + path) if err != nil { return } defer resp.Body.Close() buff := new(bytes.Buffer) downloaded := 0 for { count, err := io.CopyN(buff, resp.Body, BlockSize) if err == io.EOF { downloaded += int(count) break } if err != nil { fmt.Printf("Error Downloading libs: %e\n", err) return } downloaded += int(count) wruntime.EventsEmit(a.Ctx, "download", downloaded, resp.ContentLength) } os.MkdirAll(filepath.Join(libDir, ProcessMavenPath(lib.Name)), 0755) f, _ := os.OpenFile(filepath.Join(libDir, path), os.O_CREATE|os.O_RDWR, 0755) defer f.Close() io.Copy(f, buff) wruntime.EventsEmit(a.Ctx, "download_complete") } func InstallFabricLibs(mcVersion string, fabricVersion string, libDir string, a *App) { metadata, _ := GetFabricMetadata(mcVersion, fabricVersion) for _, lib := range metadata.LauncherMeta.Libraries.Client { InstallLib(lib, libDir, a) } for _, lib := range metadata.LauncherMeta.Libraries.Common { InstallLib(lib, libDir, a) } InstallLib(FabricLibrary{Name: metadata.Loader.Maven, Sha1: "", Url: "https://maven.fabricmc.net/"}, libDir, a) InstallLib(FabricLibrary{Name: metadata.Intermediary.Maven, Sha1: "", Url: "https://maven.fabricmc.net/"}, libDir, a) } func ProcessMavenPath(maven string) string { tokens := strings.Split(maven, ":") path := filepath.Join(strings.Split(tokens[0], ".")...) pack := tokens[1] version := tokens[2] path = filepath.Join(path, pack, version) path = strings.ReplaceAll(path, "\\", "/") return path } func ProcessMavenFilename(maven string) string { tokens := strings.Split(maven, ":") pack := tokens[1] version := tokens[2] return pack + "-" + version + ".jar" }