Skip to content

Commit 676f839

Browse files
committed
add autoupdate
1 parent d154573 commit 676f839

File tree

2 files changed

+177
-5
lines changed

2 files changed

+177
-5
lines changed

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: go
2+
go:
3+
- '1.10'
4+
env:
5+
- _GOOS=windows _GOARCH=amd64 ARCH=win64 EXT=.exe
6+
- _GOOS=windows _GOARCH=386 ARCH=win32 EXT=.exe
7+
- _GOOS=linux _GOARCH=amd64 ARCH=linux64 EXT=.run
8+
- _GOOS=linux _GOARCH=386 ARCH=linux32 EXT=.run
9+
script:
10+
- GOOS=$_GOOS GOARCH=$_GOARCH go build -ldflags "-X main.ProgramVersion=$TRAVIS_TAG -X main.ProgramArch=$ARCH" -o "proxypunch.${ARCH}${EXT}" main.go
11+
deploy:
12+
provider: releases
13+
api_key:
14+
secure: Y2CmvDkJDq1TI/il+JvheT9L6Voks72lkSCtUIoxTW3XIy4jbMCFJpkvyEy4xPWlScu0YDZXxLRwL3m7WQw9u97e+smKSp/gzVvfQQbbkd4/NMrjgpVXGVIcHUgohvM7vTEjT/SKUw6vjG83UGV77l8wQMBpvDtCM6xET/d3civ5RcoArLK1ZPEOiesoKngmu8O3ecTtn33UpD0b0aPgf59zvXUfBjvpPqoVzX2daqIOzyGw+S9nFTV2R95vP239KK9oc4hzijSAnXu3/ccJlCrlZ970WOjt58si+ptDd3oDLXfqI/Huh54hYOau8/2GFhkozq0V/FQoU2UJU5vwMCZVa4QYV1HnNUdjDfAFVdMiyStaZ18uyiOX1NdBwL1wPaV8EFH3EnewZG6KcglzWhz8bovdPOh65SnuCfWMk7Uw6q2NdXAGQYsPW/7MCP1o51x0lldn9NS3eUMZanPlMb6t1qVfz/VhCkpGzaGmX3OnrSMRr2vB+qMU9x/gsr1lN5EwFLDsmA2BX4HHBW4mXv/gxHSIZoV5p6pprFx3MJ7CZjFuF5xB9ulnO0Vh0+O4iEAUBhyH3XIqffUJRjhC0kE3DuXn+FEVXmG0/b4x0eCQclZ1kBDFL8Jpux5ykzgeHFJFItXa+f9f0jDrCX4qXDRLFG7kEU62e2YRsoc8ywM=
15+
file: "proxypunch.${ARCH}${EXT}"
16+
skip_cleanup: true
17+
on:
18+
tags: true

main.go

Lines changed: 159 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,24 @@ package main
33
import (
44
"bufio"
55
"encoding/binary"
6+
"encoding/json"
67
"flag"
78
"fmt"
89
"gopkg.in/yaml.v2"
10+
"io"
11+
"io/ioutil"
912
"log"
1013
"net"
14+
"net/http"
1115
"os"
16+
"os/exec"
17+
"path/filepath"
18+
"runtime"
1219
"strconv"
1320
"strings"
1421
"time"
1522
)
1623

17-
const version = "0.0.1"
18-
1924
const relayHost = "delthas.fr:14761"
2025

2126
const defaultPort = 41254
@@ -228,23 +233,174 @@ func server(port int) {
228233
}
229234
}
230235

236+
func update(scanner *bufio.Scanner) bool {
237+
httpClient := http.Client{Timeout: 2 * time.Second}
238+
r, err := httpClient.Get("https://api.github.com/repos/delthas/proxypunch/releases")
239+
if err != nil {
240+
// throw error even if the user is just disconnected from the internet
241+
fmt.Fprintln(os.Stderr, "Error while looking for updates: "+err.Error())
242+
return false
243+
}
244+
var releases []struct {
245+
TagName string `json:"tag_name"`
246+
Name string `json:"name"`
247+
Assets []struct {
248+
Name string `json:"name"`
249+
DownloadUrl string `json:"browser_download_url"`
250+
} `json:"assets"`
251+
}
252+
decoder := json.NewDecoder(r.Body)
253+
err = decoder.Decode(&releases)
254+
r.Body.Close()
255+
if err != nil {
256+
fmt.Fprintln(os.Stderr, "Error while processing updates list: "+err.Error())
257+
return false
258+
}
259+
for _, v := range releases {
260+
if v.TagName == ProgramVersion {
261+
return false
262+
}
263+
for _, asset := range v.Assets {
264+
if strings.Contains(asset.Name, ProgramArch) {
265+
update := ""
266+
for update != "y" && update != "yes" && update != "n" && update != "no" {
267+
fmt.Println("proxypunch update " + v.Name + " is available! Download and update now? y(es) / n(o) [yes]")
268+
if !scanner.Scan() {
269+
return false
270+
}
271+
update = strings.ToLower(scanner.Text())
272+
if update == "" {
273+
update = "y"
274+
}
275+
}
276+
if update != "y" && update != "yes" {
277+
return false
278+
}
279+
r, err = httpClient.Get(asset.DownloadUrl)
280+
if err != nil {
281+
// throw error even if the user is just disconnected from the internet
282+
fmt.Fprintln(os.Stderr, "Error while downloading update (http get): "+err.Error())
283+
return false
284+
}
285+
f, err := ioutil.TempFile("", "")
286+
if err != nil {
287+
r.Body.Close()
288+
// throw error even if the user is just disconnected from the internet
289+
fmt.Fprintln(os.Stderr, "Error while downloading update (file open): "+err.Error())
290+
return false
291+
}
292+
_, err = io.Copy(f, r.Body)
293+
r.Body.Close()
294+
f.Close()
295+
if err != nil {
296+
// throw error even if the user is just disconnected from the internet
297+
fmt.Fprintln(os.Stderr, "Error while downloading update (io copy): "+err.Error())
298+
return false
299+
}
300+
301+
exe, err := os.Executable()
302+
if err != nil {
303+
fmt.Fprintln(os.Stderr, "Error while downloading update (exe path get): "+err.Error())
304+
return false
305+
}
306+
exe, err = filepath.EvalSymlinks(exe)
307+
if err != nil {
308+
fmt.Fprintln(os.Stderr, "Error while downloading update (exe path eval): "+err.Error())
309+
return false
310+
}
311+
312+
var perm os.FileMode
313+
if info, err := os.Stat(exe); err != nil {
314+
perm = info.Mode()
315+
} else {
316+
perm = 0777
317+
}
318+
319+
if runtime.GOOS == "windows" {
320+
err = os.Rename(exe, "proxypunch_old.exe")
321+
if err != nil {
322+
fmt.Fprintln(os.Stderr, "Error while downloading update (move current file): "+err.Error())
323+
return false
324+
}
325+
} else {
326+
err = os.Remove(exe)
327+
if err != nil {
328+
fmt.Fprintln(os.Stderr, "Error while downloading update (unlink current file): "+err.Error())
329+
return false
330+
}
331+
}
332+
333+
w, err := os.OpenFile(exe, os.O_RDWR|os.O_CREATE|os.O_TRUNC, perm)
334+
if err != nil {
335+
fmt.Fprintln(os.Stderr, "Error while downloading update (create new file): "+err.Error())
336+
return false
337+
}
338+
339+
r, err := os.Open(f.Name())
340+
if err != nil {
341+
w.Close()
342+
fmt.Fprintln(os.Stderr, "Error while downloading update (open update file): "+err.Error())
343+
return false
344+
}
345+
346+
_, err = io.Copy(w, r)
347+
r.Close()
348+
w.Close()
349+
if err != nil {
350+
fmt.Fprintln(os.Stderr, "Error while downloading update (copy update file): "+err.Error())
351+
return false
352+
}
353+
354+
cmd := exec.Command(exe, os.Args[1:]...)
355+
cmd.Stdin = os.Stdin
356+
cmd.Stdout = os.Stdout
357+
cmd.Stderr = os.Stderr
358+
cmd.Run()
359+
return true
360+
}
361+
}
362+
}
363+
return false
364+
}
365+
366+
var ProgramVersion string
367+
var ProgramArch string
368+
231369
func main() {
232-
fmt.Println("ProxyPunch v" + version)
370+
if ProgramVersion == "" {
371+
ProgramVersion = "[Custom Build]"
372+
}
373+
fmt.Println("ProxyPunch " + ProgramVersion + " by delthas")
233374
fmt.Println()
234375

376+
if runtime.GOOS == "windows" {
377+
// cleanup old update file, ignore error
378+
os.Remove("proxypunch_old.exe")
379+
}
380+
235381
var mode string
236382
var host string
237383
var port int
238384
var noSave bool
385+
var noUpdate bool
239386
var configFile string
240387

241388
flag.StringVar(&mode, "mode", "", "connect mode: server, client")
242389
flag.StringVar(&host, "host", "", "remote host for client mode: ipv4 or ipv6 or hostname")
243390
flag.IntVar(&port, "port", 0, "port for client or server mode")
244391
flag.BoolVar(&noSave, "nosave", false, "disable saving configuration to file")
392+
flag.BoolVar(&noUpdate, "noupdate", false, "disable automatic update")
245393
flag.StringVar(&configFile, "config", "proxypunch.yml", "load configuration from file")
246394
flag.Parse()
247395

396+
scanner := bufio.NewScanner(os.Stdin)
397+
398+
if !noUpdate && ProgramArch != "" && ProgramVersion != "[Custom Build]" {
399+
if update(scanner) {
400+
return
401+
}
402+
}
403+
248404
var config Config
249405

250406
noConfig := (mode == "server" && port != 0) || (mode == "client" && host != "" && port != 0)
@@ -277,8 +433,6 @@ func main() {
277433
saveHost := host == ""
278434
savePort := port == 0
279435

280-
scanner := bufio.NewScanner(os.Stdin)
281-
282436
for mode != "s" && mode != "server" && mode != "c" && mode != "client" {
283437
if config.Mode != "" {
284438
fmt.Println("Mode? s(erver) / c(lient) [" + config.Mode + "]")

0 commit comments

Comments
 (0)