Files
BedrockFetch/main.go
Matheus Sampaio Queiroga 3a0a80f888
All checks were successful
Find and Upload Minecraft Server versions / build (push) Successful in 2m7s
Update files
Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2025-03-03 17:27:44 -03:00

230 lines
5.5 KiB
Go

package main
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"maps"
"os"
"path/filepath"
"slices"
"strings"
"sync"
"sirherobrine23.com.br/go-bds/go-bds/bedrock"
"sirherobrine23.com.br/go-bds/go-bds/request/v2"
"sirherobrine23.com.br/go-bds/go-bds/semver"
"sirherobrine23.com.br/go-bds/go-bds/utils/slice"
"sirherobrine23.com.br/go-bds/bedrockfetch/tea"
)
type ConvertToTar bedrock.VersionPlatform
func (version *ConvertToTar) Convert(platformTarget string, client *tea.GiteaRelease) error {
fmt.Printf("Downloading %q\n", version.ZipFile)
localFile, _, err := request.SaveTmp(version.ZipFile, "", &request.Options{Header: bedrock.MojangHeaders})
if err != nil {
return err
}
defer func() {
fmt.Printf("Deleting %q\n", version.ZipFile)
localFile.Close() // Close file to delete
os.Remove(localFile.Name()) // Delete file
}()
tarGzFile, err := os.CreateTemp(os.TempDir(), "bedrock*fetch.tgz")
if err != nil {
return err
}
defer func() {
tarGzFile.Close()
os.Remove(tarGzFile.Name())
}()
stat, _ := localFile.Stat()
zipFile, err := zip.NewReader(localFile, stat.Size())
if err != nil {
return err
}
tarSha1 := sha1.New()
gz := gzip.NewWriter(io.MultiWriter(tarSha1, tarGzFile))
defer gz.Close()
tarball := tar.NewWriter(gz)
defer tarball.Close()
for _, file := range zipFile.File {
node := file.FileInfo()
head, err := tar.FileInfoHeader(node, "")
if err != nil {
return err
}
head.Name = filepath.ToSlash(file.Name)
if err := tarball.WriteHeader(head); err != nil {
return err
} else if node.IsDir() {
continue
}
// Open file
fileRead, err := file.Open()
if err != nil {
return err
}
// Copy data
_, err = io.Copy(tarball, io.LimitReader(fileRead, node.Size()))
fileRead.Close()
if err != nil {
return err
}
}
if err := tarball.Close(); err != nil {
return err
} else if err = gz.Close(); err != nil {
return err
} else if _, err = tarGzFile.Seek(0, 0); err != nil {
return err
}
version.TarSHA1 = hex.EncodeToString(tarSha1.Sum(nil))
filename := fmt.Sprintf("%s.tgz", strings.ToLower(strings.ReplaceAll(platformTarget, "/", "_")))
if client.ExistsFile(filename) {
if remoteSha1, err := client.GetFile(filename).Sha1(); err == nil {
if remoteSha1 == version.TarSHA1 {
fmt.Printf("%q exist in %s\n", filename, client.TagName)
version.TarFile = client.GetFile(filename).FileUrl
return nil
}
}
fmt.Printf("Deleting %q, from %s\n", filename, client.TagName)
client.DeleteAsset(client.GetFile(filename))
}
fmt.Printf("Uploading %q to %s\n", filename, client.TagName)
asset, err := client.Upload(filename, tarGzFile)
if err != nil {
return err
}
version.TarFile = asset.FileUrl
return nil
}
func processMain() error {
fmt.Println("Fetching versions from minecraft site...")
fromMojang, err := bedrock.FetchFromWebsite()
if err != nil {
return err
}
convertedFromMojang, err := fromMojang.ConvertToVersions()
if err != nil {
return err
}
fmt.Println("loadding versions json...")
oldVersionFile, err := os.OpenFile("./versions.json", os.O_RDWR, 0)
if err != nil {
return err
}
defer oldVersionFile.Close()
var versions bedrock.Versions
if err = json.NewDecoder(oldVersionFile).Decode(&versions); err != nil {
return err
}
for _, version := range convertedFromMojang {
fmt.Printf("Checking %s...", version.ServerVersion)
if versions.Has(version.ServerVersion) {
fmt.Println(" ignoring, ared released!")
continue
}
fmt.Println(" Creating Release")
release, err := tea.Release(version.IsPreview, false, version.ServerVersion, "", "")
if err != nil {
fmt.Println("cannot create release!")
return err
}
fmt.Printf("Converting %s\n", version.ServerVersion)
var locker sync.Mutex
var waiter sync.WaitGroup
waiter.Add(len(version.Platforms))
for platformIndex := range version.Platforms {
go func() {
data := ConvertToTar(version.Platforms[platformIndex])
if err2 := data.Convert(platformIndex, release); err == nil && err2 != nil {
err = err2
}
locker.Lock()
defer locker.Unlock()
version.Platforms[platformIndex] = bedrock.VersionPlatform(data)
waiter.Done()
}()
}
// Wait convertions
waiter.Wait()
if err != nil {
release.DeleteRelease()
return err
}
versions = append(versions, version)
}
// Sort versions slice
semver.SortStruct(versions)
// Delete no related files
for _, version := range versions {
release, err := tea.Release(version.IsPreview, false, version.ServerVersion, "", "")
if err != nil {
fmt.Printf("cannot get release to %s!\n", version.ServerVersion)
return err
}
teaAssets := slice.Slice[tea.GiteaAsset](release.FileAssets)
filesToDelete := teaAssets.Filter(func(asset tea.GiteaAsset) bool {
return slice.Slice[string](slices.Collect(maps.Keys(version.Platforms))).FindIndex(func(input string) bool {
return fmt.Sprintf("%s.tgz", strings.ToLower(strings.ReplaceAll(input, "/", "_"))) == asset.FileName
}) == -1
}).Orin()
for _, asset := range filesToDelete {
fmt.Printf("Deleting %q from %s\n", asset.FileName, release.TagName)
if err = release.DeleteAsset(&asset); err != nil {
return err
}
}
}
if _, err = oldVersionFile.Seek(0, 0); err != nil {
return err
} else if err = oldVersionFile.Truncate(0); err != nil {
return err
}
enc := json.NewEncoder(oldVersionFile)
enc.SetIndent("", " ")
return enc.Encode(versions)
}
func main() {
if err := processMain(); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
}