generated from dave/wails-template
Compare commits
2 Commits
c691125b10
...
4134c39721
Author | SHA1 | Date | |
---|---|---|---|
4134c39721 | |||
20ede32890 |
182
addon.go
Normal file
182
addon.go
Normal 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
17
addonService.go
Normal 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
213
main.go
@@ -1,18 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/zip"
|
|
||||||
"bytes"
|
|
||||||
"embed"
|
"embed"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
@@ -36,196 +31,36 @@ func init() {
|
|||||||
//go:embed all:frontend/dist
|
//go:embed all:frontend/dist
|
||||||
var assets embed.FS
|
var assets embed.FS
|
||||||
var gamePath string
|
var gamePath string
|
||||||
var versionRegex = regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
var addonService *AddonService
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
addonService = NewAddonService()
|
||||||
gamePath = filepath.Join("C:\\", "Games", "WoWRuski")
|
gamePath = filepath.Join("C:\\", "Games", "WoWRuski")
|
||||||
// for _, addon := range addons {
|
for _, addon := range addonService.Addons {
|
||||||
// log.Printf("%#v", addon.IsUpToDate())
|
localVersion, err := addon.GetLocalVersion()
|
||||||
// log.Printf("%#v", addon.GetRemoteReleaseURL())
|
if err != nil {
|
||||||
// }
|
Error.Printf("error getting local version: %s", err)
|
||||||
file, err := os.ReadFile("Heimdall.zip")
|
continue
|
||||||
if err != nil {
|
}
|
||||||
log.Printf("error reading file: %s", err)
|
log.Printf("%#v", localVersion)
|
||||||
return
|
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
|
return
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
|
|
||||||
err = wails.Run(&options.App{
|
err := wails.Run(&options.App{
|
||||||
Title: "wails-template",
|
Title: "wails-template",
|
||||||
Width: 1024,
|
Width: 1024,
|
||||||
Height: 768,
|
Height: 768,
|
||||||
|
3
utils.go
3
utils.go
@@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,5 +12,5 @@ func GetVersion(data string) (version string, err error) {
|
|||||||
return version, nil
|
return version, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("no version found")
|
return "0.0.0", nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user