v2.0.0.0000

This commit is contained in:
marmei
2019-08-02 20:12:09 +02:00
parent e396af91cb
commit e001b06b62
85 changed files with 22786 additions and 2 deletions

View File

@@ -0,0 +1,129 @@
package up2date
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"runtime"
"time"
)
// ClientInfo : Information about the key (NAME OS, ARCH, UUID, KEY)
type ClientInfo struct {
Arch string `json:"arch,required"`
Branch string `json:"branch,required"`
CMD string `json:"cmd,omitempty"`
Name string `json:"name,required"`
OS string `json:"os,required"`
URL string `json:"url,required"`
Response ServerResponse `json:"response,omitempty"`
}
//ServerResponse : Response from server after client request
type ServerResponse struct {
Status bool `json:"status,omitempty"`
Reason string `json:"reason,omitempty"`
Version string `json:"version,omitempty"`
UpdateBIN string `json:"update.url.bin,omitempty"`
UpdateZIP string `json:"update.url.zip,omitempty"`
Filename string `json:"filename.bin,omitempty"`
}
// Updater : Client infos
var Updater ClientInfo
// UpdateURL : URL for the new binary
var UpdateURL string
// Init : Init
func Init() {
Updater.OS = runtime.GOOS
Updater.Arch = runtime.GOARCH
}
// GetVersion : Information about the latest version
func GetVersion() (err error) {
Updater.CMD = "getVersion"
err = serverRequest()
return
}
func serverRequest() (err error) {
var serverResponse ServerResponse
jsonByte, err := json.MarshalIndent(Updater, "", " ")
if err == nil {
// Serververbindung prüfen
u, err := url.Parse(Updater.URL)
if err != nil {
return err
}
var server = u.Host
timeout := time.Duration(1 * time.Second)
_, err = net.DialTimeout("tcp", server, timeout)
if err != nil {
return err
}
// Check redirect 301 <---> 308
redirect, err := http.NewRequest("POST", Updater.URL, nil)
client := &http.Client{}
client.CheckRedirect = func(redirect *http.Request, via []*http.Request) error {
return errors.New("Redirect")
}
resp, err := client.Do(redirect)
if err != nil {
// Redirect
if resp.StatusCode >= 301 && resp.StatusCode <= 308 { //status code 301 <---> 308
Updater.URL = resp.Header.Get("Location")
} else {
return err
}
}
// ---
req, err := http.NewRequest("POST", Updater.URL, bytes.NewBuffer(jsonByte))
req.Header.Set("Content-Type", "application/json")
client = &http.Client{}
resp, err = client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
//fmt.Println(resp.StatusCode, Updater.URL, Updater.CMD)
err = fmt.Errorf(fmt.Sprintf("%d: %s (%s)", resp.StatusCode, http.StatusText(resp.StatusCode), Updater.URL))
return err
}
Updater.CMD = ""
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
err = json.Unmarshal(body, &serverResponse)
if err != nil {
return err
}
Updater.Response = serverResponse
}
return
}

View File

@@ -0,0 +1,271 @@
package up2date
import (
"archive/zip"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"syscall"
"github.com/kardianos/osext"
)
// DoUpdate : Update binary
func DoUpdate(fileType, filenameBIN string) (err error) {
var url string
switch fileType {
case "bin":
url = Updater.Response.UpdateBIN
case "zip":
url = Updater.Response.UpdateZIP
}
switch runtime.GOOS {
case "windows":
filenameBIN = filenameBIN + ".exe"
}
if len(url) > 0 {
log.Println("["+strings.ToUpper(fileType)+"]", "New version ("+Updater.Name+"):", Updater.Response.Version)
// Download new binary
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
log.Println("["+strings.ToUpper(fileType)+"]", "Download new version...")
if resp.StatusCode != http.StatusOK {
log.Println("["+strings.ToUpper(fileType)+"]", "Download new version...OK")
return fmt.Errorf("bad status: %s", resp.Status)
}
// Change binary filename to .filename
binary, err := osext.Executable()
var filename = getFilenameFromPath(binary)
var path = getPlatformPath(binary)
var oldBinary = path + "_old_" + filename
var newBinary = binary
// ZIP
var tmpFolder = path + "tmp"
var tmpFile = tmpFolder + string(os.PathSeparator) + filenameBIN
//fmt.Println(binary, path+"."+filename)
os.Rename(newBinary, oldBinary)
// Save the new binary with the old file name
out, err := os.Create(binary)
if err != nil {
restorOldBinary(oldBinary, newBinary)
return err
}
defer out.Close()
// Write the body to file
_, err = io.Copy(out, resp.Body)
if err != nil {
restorOldBinary(oldBinary, newBinary)
return err
}
// Update as a ZIP file
if fileType == "zip" {
log.Println("["+strings.ToUpper(fileType)+"]", "Update file:", filenameBIN)
log.Println("["+strings.ToUpper(fileType)+"]", "Unzip ZIP file...")
err = extractZIP(binary, tmpFolder)
binary = newBinary
if err != nil {
log.Println("["+strings.ToUpper(fileType)+"]", "Unzip ZIP file...ERROR")
restorOldBinary(oldBinary, newBinary)
return err
} else {
log.Println("["+strings.ToUpper(fileType)+"]", "Unzip ZIP file...OK")
log.Println("["+strings.ToUpper(fileType)+"]", "Copy binary file...")
err = copyFile(tmpFile, binary)
if err == nil {
log.Println("["+strings.ToUpper(fileType)+"]", "Copy binary file...OK")
} else {
log.Println("["+strings.ToUpper(fileType)+"]", "Copy binary file...ERROR")
restorOldBinary(oldBinary, newBinary)
return err
}
os.RemoveAll(tmpFolder)
}
}
// Set the permission
err = os.Chmod(binary, 0755)
// Close the new file !Windows
out.Close()
log.Println("["+strings.ToUpper(fileType)+"]", "Update Successful")
// Restart binary (Windows)
if runtime.GOOS == "windows" {
bin, err := os.Executable()
if err != nil {
restorOldBinary(oldBinary, newBinary)
return err
}
var pid = os.Getpid()
var process, _ = os.FindProcess(pid)
if proc, err := start(bin); err == nil {
os.RemoveAll(oldBinary)
process.Kill()
proc.Wait()
} else {
restorOldBinary(oldBinary, newBinary)
}
} else {
// Restart binary (Linux and UNIX)
file, _ := osext.Executable()
os.RemoveAll(oldBinary)
err = syscall.Exec(file, os.Args, os.Environ())
if err != nil {
restorOldBinary(oldBinary, newBinary)
log.Fatal(err)
return err
}
}
}
return
}
func start(args ...string) (p *os.Process, err error) {
if args[0], err = exec.LookPath(args[0]); err == nil {
//fmt.Println(args[0])
var procAttr os.ProcAttr
procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}
p, err := os.StartProcess(args[0], args, &procAttr)
if err == nil {
return p, nil
}
}
return nil, err
}
func restorOldBinary(oldBinary, newBinary string) {
os.RemoveAll(newBinary)
os.Rename(oldBinary, newBinary)
}
func getPlatformFile(filename string) string {
path, file := filepath.Split(filename)
var newPath = filepath.Dir(path)
var newFileName = newPath + string(os.PathSeparator) + file
return newFileName
}
func getFilenameFromPath(path string) string {
file := filepath.Base(path)
return file
}
func getPlatformPath(path string) string {
var newPath = filepath.Dir(path) + string(os.PathSeparator)
return newPath
}
func copyFile(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
return out.Close()
}
func extractZIP(archive, target string) (err error) {
reader, err := zip.OpenReader(archive)
if err != nil {
return err
}
if err := os.MkdirAll(target, 0755); err != nil {
return err
}
for _, file := range reader.File {
path := filepath.Join(target, file.Name)
if file.FileInfo().IsDir() {
os.MkdirAll(path, file.Mode())
continue
}
fileReader, err := file.Open()
if err != nil {
return err
}
defer fileReader.Close()
targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer targetFile.Close()
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
}
return
}