119 lines
3.1 KiB
Go
119 lines
3.1 KiB
Go
package diffService
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/wailsapp/wails/v3/pkg/application"
|
|
)
|
|
|
|
const ziftExecutablePath = "bin/zift.exe"
|
|
|
|
var ziftPercentPattern = regexp.MustCompile(`(?i)(\d+(?:\.\d+)?)\s*%`)
|
|
var ziftANSIPattern = regexp.MustCompile(`\x1b\[[0-?]*[ -/]*[@-~]`)
|
|
|
|
func (h *DiffService) ApplyDiffZiff(gamePath, patchPath string) (bool, string) {
|
|
launcherPath, err := os.Executable()
|
|
if err != nil {
|
|
return false, fmt.Sprintf("locate launcher directory: %v", err)
|
|
}
|
|
launcherDir := filepath.Dir(launcherPath)
|
|
ziftPath := filepath.Join(launcherDir, filepath.FromSlash(ziftExecutablePath))
|
|
if _, err := os.Stat(ziftPath); err != nil {
|
|
if cwdPath, cwdErr := filepath.Abs(filepath.FromSlash(ziftExecutablePath)); cwdErr == nil {
|
|
if _, statErr := os.Stat(cwdPath); statErr == nil {
|
|
ziftPath = cwdPath
|
|
}
|
|
}
|
|
}
|
|
if _, err := os.Stat(ziftPath); err != nil {
|
|
return false, fmt.Sprintf("Zift executable not found at %s: %v", ziftPath, err)
|
|
}
|
|
if info, err := os.Stat(patchPath); err != nil || !info.Mode().IsRegular() {
|
|
if err != nil {
|
|
return false, fmt.Sprintf("patch file is unavailable: %v", err)
|
|
}
|
|
return false, "selected patch is not a file"
|
|
}
|
|
cmd := exec.Command(ziftPath, "-a", "-y", patchPath, gamePath)
|
|
cmd.Dir = launcherDir
|
|
outputReader, outputWriter := io.Pipe()
|
|
cmd.Stdout = outputWriter
|
|
cmd.Stderr = outputWriter
|
|
application.Get().Event.Emit("diff:ziff-progress", map[string]interface{}{
|
|
"message": "Starting Zift…",
|
|
"percent": -1.0,
|
|
})
|
|
outputDone := make(chan string, 1)
|
|
go func() { outputDone <- collectZiftOutput(outputReader) }()
|
|
if err := cmd.Start(); err != nil {
|
|
_ = outputWriter.Close()
|
|
message := <-outputDone
|
|
if message != "" {
|
|
return false, fmt.Sprintf("run Zift: %v\n%s", err, message)
|
|
}
|
|
return false, fmt.Sprintf("run Zift: %v", err)
|
|
}
|
|
err = cmd.Wait()
|
|
_ = outputWriter.Close()
|
|
message := strings.TrimSpace(<-outputDone)
|
|
if err != nil {
|
|
if message == "" {
|
|
return false, fmt.Sprintf("run Zift: %v", err)
|
|
}
|
|
return false, fmt.Sprintf("Zift failed: %v\n%s", err, message)
|
|
}
|
|
if message == "" {
|
|
message = "Ziff patch applied successfully"
|
|
}
|
|
return true, message
|
|
}
|
|
|
|
func collectZiftOutput(reader io.Reader) string {
|
|
buffered := bufio.NewReader(reader)
|
|
var output strings.Builder
|
|
var line strings.Builder
|
|
emitLine := func() {
|
|
text := strings.TrimSpace(ziftANSIPattern.ReplaceAllString(line.String(), ""))
|
|
line.Reset()
|
|
if text == "" {
|
|
return
|
|
}
|
|
output.WriteString(text)
|
|
output.WriteByte('\n')
|
|
progress := -1.0
|
|
if match := ziftPercentPattern.FindStringSubmatch(text); len(match) > 1 {
|
|
if value, err := strconv.ParseFloat(match[1], 64); err == nil && value >= 0 && value <= 100 {
|
|
progress = value
|
|
}
|
|
}
|
|
application.Get().Event.Emit("diff:ziff-progress", map[string]interface{}{
|
|
"message": text,
|
|
"percent": progress,
|
|
})
|
|
}
|
|
|
|
for {
|
|
value, err := buffered.ReadByte()
|
|
if err != nil {
|
|
if line.Len() > 0 {
|
|
emitLine()
|
|
}
|
|
break
|
|
}
|
|
if value == '\r' || value == '\n' {
|
|
emitLine()
|
|
continue
|
|
}
|
|
line.WriteByte(value)
|
|
}
|
|
return output.String()
|
|
}
|