Refactor things into separate files

This commit is contained in:
2025-01-11 20:09:47 +01:00
parent c691125b10
commit 20ede32890
3 changed files with 223 additions and 189 deletions

182
addon.go Normal file
View File

@@ -0,0 +1,182 @@
package main
import (
"archive/zip"
"bytes"
"fmt"
"io"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"regexp"
"strings"
)
type Addon struct {
Name string `json:"name"`
URL *url.URL `json:"url"`
}
var versionRegex = regexp.MustCompile(`(\d+\.\d+\.\d+)`)
func NewAddon(name, aurl string) *Addon {
a := &Addon{Name: name}
var err error
a.URL, err = url.Parse(aurl)
if err != nil {
Error.Printf("invalid url: %s", aurl)
return nil
}
return a
}
func (a *Addon) GetRemoteTocURL() *url.URL {
return a.URL.JoinPath("raw", "branch", "master", a.Name+".toc")
}
func (a *Addon) GetRemoteReleaseURL() *url.URL {
return a.URL.JoinPath("media", "branch", "master", a.Name+".zip")
}
func (a *Addon) GetRemoteRelease() (body []byte, err error) {
url := a.GetRemoteReleaseURL()
response, err := http.Get(url.String())
if err != nil {
return nil, fmt.Errorf("error getting remote release: %w", err)
}
return io.ReadAll(response.Body)
}
func (a *Addon) HasBreakingChanges(lhsToc, rhsToc string) bool {
lhsLines := strings.Split(lhsToc, "\n")
rhsLines := strings.Split(rhsToc, "\n")
for i, lhsLine := range lhsLines {
rhsLine := rhsLines[i]
lhsLine = strings.TrimSpace(lhsLine)
rhsLine = strings.TrimSpace(rhsLine)
// We don't care about ## lines
if strings.HasPrefix(lhsLine, "#") && strings.HasPrefix(rhsLine, "#") {
continue
}
// Nor do we care about empty lines
if lhsLine == "" && rhsLine == "" {
continue
}
log.Printf("%s %s", lhsLine, rhsLine)
if i >= len(rhsLines) || rhsLine != lhsLine {
return true
}
}
return false
}
func UpdateFile(localPath string, data []byte) (err error) {
err = os.MkdirAll(filepath.Dir(localPath), 0755)
if err != nil {
return fmt.Errorf("error creating directory: %w", err)
}
fileHandle, err := os.OpenFile(localPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return fmt.Errorf("error opening file: %w", err)
}
defer fileHandle.Close()
_, err = fileHandle.Write(data)
if err != nil {
return fmt.Errorf("error writing file: %w", err)
}
return nil
}
func (a *Addon) Update(body []byte) (err error) {
log.Printf("Updating %s", a.Name)
zipReader, err := zip.NewReader(bytes.NewReader(body), int64(len(body)))
if err != nil {
return fmt.Errorf("error creating zip reader: %w", err)
}
log.Printf("Found %d files", len(zipReader.File))
hasBreakingChanges := false
for _, file := range zipReader.File {
if file.FileInfo().IsDir() {
continue
}
log.Printf("Found file %s", file.Name)
fileHandle, err := file.Open()
if err != nil {
return fmt.Errorf("error opening file: %w", err)
}
fileData, err := io.ReadAll(fileHandle)
if err != nil {
return fmt.Errorf("error reading file: %w", err)
}
if strings.HasSuffix(file.Name, ".toc") {
localToc, err := os.ReadFile(a.GetLocalTocPath())
if err != nil {
if os.IsNotExist(err) {
localToc = []byte{}
} else {
return fmt.Errorf("error reading local toc: %w", err)
}
}
if a.HasBreakingChanges(string(localToc), string(fileData)) {
log.Printf("Has breaking changes")
hasBreakingChanges = true
}
}
localPath := filepath.Join(gamePath, "Interface", "AddOns", file.Name)
log.Printf("Updating file %s", localPath)
err = UpdateFile(localPath, fileData)
if err != nil {
return fmt.Errorf("error updating file: %w", err)
}
}
if hasBreakingChanges {
Warning.Printf("Has breaking changes")
}
return nil
}
func (a *Addon) GetLocalTocPath() string {
return filepath.Join(gamePath, "Interface", "AddOns", a.Name, a.Name+".toc")
}
func (a *Addon) GetRemoteVersion() (version string, err error) {
url := a.GetRemoteTocURL()
log.Printf("Fetching remote version from %s", url.String())
response, err := http.Get(url.String())
if err != nil {
return "", fmt.Errorf("error getting remote version: %w", err)
}
if response.StatusCode != http.StatusOK {
return "", fmt.Errorf("error getting remote version with status: %s", response.Status)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
return "", fmt.Errorf("error reading remote version: %w", err)
}
return GetVersion(string(body))
}
func (a *Addon) GetLocalVersion() (version string, err error) {
file, err := os.Open(a.GetLocalTocPath())
if err != nil {
if os.IsNotExist(err) {
return "0.0.0", nil
}
return "", fmt.Errorf("error opening local toc: %w", err)
}
defer file.Close()
body, err := io.ReadAll(file)
if err != nil {
return "", fmt.Errorf("error reading local toc: %w", err)
}
return GetVersion(string(body))
}
func (a *Addon) IsUpToDate() bool {
remoteVersion, err := a.GetRemoteVersion()
if err != nil {
return false
}
localVersion, err := a.GetLocalVersion()
if err != nil {
return false
}
return remoteVersion == localVersion
}

17
addonService.go Normal file
View File

@@ -0,0 +1,17 @@
package main
type AddonService struct {
Addons []*Addon
}
var addons = []*Addon{
NewAddon("Channeler", "https://git.site.quack-lab.dev/dave/wow_channeler"),
NewAddon("Heimdall", "https://git.site.quack-lab.dev/dave/wow-Heimdall"),
NewAddon("Dechickenator", "https://git.site.quack-lab.dev/dave/wow_dechickenator"),
}
func NewAddonService() *AddonService {
return &AddonService{
Addons: addons,
}
}

213
main.go
View File

@@ -1,18 +1,13 @@
package main
import (
"archive/zip"
"bytes"
"embed"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
@@ -36,196 +31,36 @@ func init() {
//go:embed all:frontend/dist
var assets embed.FS
var gamePath string
var versionRegex = regexp.MustCompile(`(\d+\.\d+\.\d+)`)
type Addon struct {
Name string
URL *url.URL
}
func NewAddon(name, aurl string) *Addon {
a := &Addon{Name: name}
var err error
a.URL, err = url.Parse(aurl)
if err != nil {
Error.Printf("invalid url: %s", aurl)
return nil
}
return a
}
var addons = []*Addon{
NewAddon("Channeler", "https://git.site.quack-lab.dev/dave/wow_channeler"),
}
func (a *Addon) GetRemoteTocURL() *url.URL {
return a.URL.JoinPath("raw", "branch", "master", a.Name+".toc")
}
func (a *Addon) GetRemoteReleaseURL() *url.URL {
return a.URL.JoinPath("media", "branch", "master", a.Name+".zip")
}
func (a *Addon) GetRemoteRelease() (body []byte, err error) {
url := a.GetRemoteReleaseURL()
response, err := http.Get(url.String())
if err != nil {
return nil, fmt.Errorf("error getting remote release: %w", err)
}
return io.ReadAll(response.Body)
}
func (a *Addon) HasBreakingChanges(lhsToc, rhsToc string) bool {
lhsLines := strings.Split(lhsToc, "\n")
rhsLines := strings.Split(rhsToc, "\n")
for i, lhsLine := range lhsLines {
rhsLine := rhsLines[i]
lhsLine = strings.TrimSpace(lhsLine)
rhsLine = strings.TrimSpace(rhsLine)
// We don't care about ## lines
if strings.HasPrefix(lhsLine, "#") && strings.HasPrefix(rhsLine, "#") {
continue
}
// Nor do we care about empty lines
if lhsLine == "" && rhsLine == "" {
continue
}
log.Printf("%s %s", lhsLine, rhsLine)
if i >= len(rhsLines) || rhsLine != lhsLine {
return true
}
}
return false
}
func UpdateFile(localPath string, data []byte) (err error) {
err = os.MkdirAll(filepath.Dir(localPath), 0755)
if err != nil {
return fmt.Errorf("error creating directory: %w", err)
}
fileHandle, err := os.OpenFile(localPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return fmt.Errorf("error opening file: %w", err)
}
defer fileHandle.Close()
_, err = fileHandle.Write(data)
if err != nil {
return fmt.Errorf("error writing file: %w", err)
}
return nil
}
func (a *Addon) Update(body []byte) (err error) {
log.Printf("Updating %s", a.Name)
zipReader, err := zip.NewReader(bytes.NewReader(body), int64(len(body)))
if err != nil {
return fmt.Errorf("error creating zip reader: %w", err)
}
log.Printf("Found %d files", len(zipReader.File))
hasBreakingChanges := false
for _, file := range zipReader.File {
if file.FileInfo().IsDir() {
continue
}
log.Printf("Found file %s", file.Name)
fileHandle, err := file.Open()
if err != nil {
return fmt.Errorf("error opening file: %w", err)
}
fileData, err := io.ReadAll(fileHandle)
if err != nil {
return fmt.Errorf("error reading file: %w", err)
}
if strings.HasSuffix(file.Name, ".toc") {
localToc, err := os.ReadFile(a.GetLocalTocPath())
if err != nil {
if os.IsNotExist(err) {
localToc = []byte{}
} else {
return fmt.Errorf("error reading local toc: %w", err)
}
}
if a.HasBreakingChanges(string(localToc), string(fileData)) {
log.Printf("Has breaking changes")
hasBreakingChanges = true
}
}
localPath := filepath.Join(gamePath, "Interface", "AddOns", file.Name)
log.Printf("Updating file %s", localPath)
err = UpdateFile(localPath, fileData)
if err != nil {
return fmt.Errorf("error updating file: %w", err)
}
}
if hasBreakingChanges {
Warning.Printf("Has breaking changes")
}
return nil
}
func (a *Addon) GetLocalTocPath() string {
return filepath.Join(gamePath, "Interface", "AddOns", a.Name, a.Name+".toc")
}
func (a *Addon) GetRemoteVersion() (version string, err error) {
url := a.GetRemoteTocURL()
log.Printf("Fetching remote version from %s", url.String())
response, err := http.Get(url.String())
if err != nil {
return "", fmt.Errorf("error getting remote version: %w", err)
}
if response.StatusCode != http.StatusOK {
return "", fmt.Errorf("error getting remote version with status: %s", response.Status)
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
return "", fmt.Errorf("error reading remote version: %w", err)
}
return GetVersion(string(body))
}
func (a *Addon) GetLocalVersion() (version string, err error) {
file, err := os.Open(a.GetLocalTocPath())
if err != nil {
return "", fmt.Errorf("error opening local toc: %w", err)
}
defer file.Close()
body, err := io.ReadAll(file)
if err != nil {
return "", fmt.Errorf("error reading local toc: %w", err)
}
return GetVersion(string(body))
}
func (a *Addon) IsUpToDate() bool {
remoteVersion, err := a.GetRemoteVersion()
if err != nil {
return false
}
localVersion, err := a.GetLocalVersion()
if err != nil {
return false
}
return remoteVersion == localVersion
}
var addonService *AddonService
func main() {
addonService = NewAddonService()
gamePath = filepath.Join("C:\\", "Games", "WoWRuski")
// for _, addon := range addons {
// log.Printf("%#v", addon.IsUpToDate())
// log.Printf("%#v", addon.GetRemoteReleaseURL())
// }
file, err := os.ReadFile("Heimdall.zip")
if err != nil {
log.Printf("error reading file: %s", err)
return
for _, addon := range addonService.Addons {
localVersion, err := addon.GetLocalVersion()
if err != nil {
Error.Printf("error getting local version: %s", err)
continue
}
log.Printf("%#v", localVersion)
remoteVersion, err := addon.GetRemoteVersion()
if err != nil {
Error.Printf("error getting remote version: %s", err)
continue
}
log.Printf("%#v", remoteVersion)
body, err := json.Marshal(addon)
if err != nil {
Error.Printf("error marshalling addon: %s", err)
continue
}
log.Printf("%s", string(body))
}
err = addons[0].Update(file)
if err != nil {
log.Printf("error updating addon: %s", err)
return
}
log.Printf("Addon updated")
return
app := NewApp()
err = wails.Run(&options.App{
err := wails.Run(&options.App{
Title: "wails-template",
Width: 1024,
Height: 768,