Skip to content

Commit

Permalink
Add check for newer release
Browse files Browse the repository at this point in the history
This is a crude implementation to test release integration.
  • Loading branch information
iaincollins committed Nov 17, 2021
1 parent 5d265c5 commit 09de3a2
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 8 deletions.
2 changes: 1 addition & 1 deletion resources/installer.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

!define APP_NAME "ICARUS Terminal"
!define COMP_NAME "ICARUS"
!define VERSION "00.00.00.00"
!define VERSION "0.1.1.0"
!define COPYRIGHT "ICARUS"
!define DESCRIPTION "Application"
!define INSTALLER_NAME "..\dist\ICARUS Setup.exe"
Expand Down
11 changes: 6 additions & 5 deletions scripts/lib/build-options.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
const path = require('path')

const ROOT_DIR = path.join(__dirname, '..', '..')
const PRODUCT_VERSION = '0.1.1.0'
const APP_FILE_VERSION = PRODUCT_VERSION
const SERVICE_FILE_VERSION = PRODUCT_VERSION

// Development builds are faster, larger and can contain debug routines
const DEVELOPMENT_BUILD = process.env.DEVELOPMENT || false
const DEBUG_CONSOLE = DEVELOPMENT_BUILD

const ROOT_DIR = path.join(__dirname, '..', '..')
const BUILD_DIR = path.join(ROOT_DIR, 'build') // For intermediate build steps
const BIN_DIR = path.join(BUILD_DIR, 'bin') // For final binary build
const DIST_DIR = path.join(ROOT_DIR, 'dist') // For distributable build
Expand All @@ -16,8 +19,6 @@ const ASSETS_BUILD_DIR = path.join(BUILD_DIR, 'assets')
const INSTALLER_NSI = path.join(RESOURCES_DIR, 'installer.nsi') // Installer config
const INSTALLER_EXE = path.join(DIST_DIR, 'ICARUS Setup.exe') // Should match INSTALLER_NAME in .nsi

const PRODUCT_VERSION = '0.0.0.1'

const APP_BINARY_NAME = 'ICARUS Terminal.exe'
const APP_UNOPTIMIZED_BUILD = path.join(BUILD_DIR, `~UNOPT_${safeBinaryName(APP_BINARY_NAME)}`)
const APP_OPTIMIZED_BUILD = path.join(BUILD_DIR, `~OPT_${safeBinaryName(APP_BINARY_NAME)}`)
Expand All @@ -28,7 +29,7 @@ const APP_VERSION_INFO = {
CompanyName: 'ICARUS',
ProductName: 'ICARUS Terminal',
FileDescription: 'ICARUS Terminal',
FileVersion: '0.0.0.1',
FileVersion: APP_FILE_VERSION,
ProductVersion: PRODUCT_VERSION,
OriginalFilename: 'ICARUS Terminal.exe',
InternalName: 'ICARUS Terminal',
Expand All @@ -45,7 +46,7 @@ const SERVICE_VERSION_INFO = {
CompanyName: 'ICARUS',
ProductName: 'ICARUS Terminal Service',
FileDescription: 'ICARUS Terminal Service',
FileVersion: '0.0.0.1',
FileVersion: SERVICE_FILE_VERSION,
ProductVersion: PRODUCT_VERSION,
OriginalFilename: 'ICARUS Service.exe',
InternalName: 'ICARUS Service',
Expand Down
4 changes: 3 additions & 1 deletion src/app/go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
module iaincollins.com/m/v2
module iaincollins.com/icarus-terminal/v2

go 1.17

require github.com/webview/webview v0.0.0-20210330151455-f540d88dde4e

require (
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf // indirect
github.com/gonutz/w32/v2 v2.2.2 // indirect
github.com/jchv/go-webview2 v0.0.0-20211023023319-977d8719321f // indirect
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect
github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e // indirect
github.com/nvsoft/win v0.0.0-20160111051136-23d143e32c41 // indirect
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 // indirect
github.com/sqweek/dialog v0.0.0-20211002065838-9a201b55ab91 // indirect
Expand Down
4 changes: 4 additions & 0 deletions src/app/go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf h1:FPsprx82rdrX2jiKyS17BH6IrTmUBYqZa/CXT4uvb+I=
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf/go.mod h1:peYoMncQljjNS6tZwI9WVyQB3qZS6u79/N3mBOcnd3I=
github.com/gonutz/w32/v2 v2.2.2 h1:y6Y337TpuCXjYdFTq5p5NmcujEdAQiTB43kisovMk+0=
github.com/gonutz/w32/v2 v2.2.2/go.mod h1:MgtHx0AScDVNKyB+kjyPder4xIi3XAcHS6LDDU2DmdE=
github.com/jchv/go-webview2 v0.0.0-20211023023319-977d8719321f h1:wF7bbDOcRcRlamAwWMNagyFVQubISAlisj6Ix8O8Hn0=
github.com/jchv/go-webview2 v0.0.0-20211023023319-977d8719321f/go.mod h1:7Q5nFip7HvzGJDYVfa22s/pb9T2X+XhEjLhylNf5dV8=
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e h1:ZZCvgaRDZg1gC9/1xrsgaJzQUCQgniKtw0xjWywWAOE=
github.com/jmoiron/jsonq v0.0.0-20150511023944-e874b168d07e/go.mod h1:+rHyWac2R9oAZwFe1wGY2HBzFJJy++RHBg1cU23NkD8=
github.com/nvsoft/win v0.0.0-20160111051136-23d143e32c41 h1:s0qXnW0MxcRPYZpqbrITRo3tAbAdlQBPUCKf/akNMKg=
github.com/nvsoft/win v0.0.0-20160111051136-23d143e32c41/go.mod h1:bI2vvx1dagFt7tydvy947C0q6ET6k5MfIvWmmpLelpw=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
Expand Down
2 changes: 2 additions & 0 deletions src/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ var processGroup ProcessGroup
func main() {
startTime := time.Now()

CheckForUpdate()

_processGroup, err := NewProcessGroup()
if err != nil {
panic(err)
Expand Down
186 changes: 186 additions & 0 deletions src/app/updater.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package main

import (
"strings"
"encoding/json"
"github.com/jmoiron/jsonq"
"github.com/sqweek/dialog"
"github.com/gonutz/w32/v2"
"io/ioutil"
"net/http"
"time"
"regexp"
"os/exec"
"errors"
"io"
"os"
)

const LATEST_RELEASE_URL = "https://api.github.com/repos/iaincollins/icarus/releases/latest"

type Release struct {
productVersion string
downloadUrl string
}

func CheckForUpdate() {
currentProductVersion := GetCurrentAppVersion()
release, releaseErr := GetLatestRelease(LATEST_RELEASE_URL)
if releaseErr != nil {
return
}

// If we are already running the latest release, do nothing
if (currentProductVersion == release.productVersion) {
return
}

ok := dialog.Message("%s", "A new version of ICARUS Terminal is available.\n\nWould you like to download the update?").Title("New version available").YesNo()
if (ok) {
downloadUrl := release.downloadUrl // In future may redirect to webpage instead
exec.Command("rundll32", "url.dll,FileProtocolHandler", downloadUrl).Start()

// This is disabled as we can't actually run the current installer this way
// because it requires escalated privilages. This could be addressed by
// using a different type of installer.
/*
downloadedFile, downloadErr := DownloadRelease(release)
if downloadErr != nil {
fmt.Println("Error downloading update", downloadErr.Error())
}
installerCmdInstance := exec.Command(downloadedFile)
installerCmdErr := installerCmdInstance.Start()
if installerCmdErr != nil {
fmt.Println("Error installing update", installerCmdErr.Error())
}
*/
}

return
}

func GetCurrentAppVersion() string {
const path = "ICARUS Terminal.exe"

size := w32.GetFileVersionInfoSize(path)
if size <= 0 {
panic("GetFileVersionInfoSize failed")
}

info := make([]byte, size)
ok := w32.GetFileVersionInfo(path, info)
if !ok {
panic("GetFileVersionInfo failed")
}

/*
fixed, ok := w32.VerQueryValueRoot(info)
if !ok {
panic("VerQueryValueRoot failed")
}
version := fixed.FileVersion()
fileVersion := fmt.Sprintf(
"%d.%d.%d.%d",
version&0xFFFF000000000000>>48,
version&0x0000FFFF00000000>>32,
version&0x00000000FFFF0000>>16,
version&0x000000000000FFFF>>0,
)
*/

translations, ok := w32.VerQueryValueTranslations(info)
if !ok {
panic("VerQueryValueTranslations failed")
}
if len(translations) == 0 {
panic("no translation found")
}
t := translations[0]

productVersion, ok := w32.VerQueryValueString(info, t, w32.ProductVersion)
if !ok {
panic("cannot get product version")
}

// Convert from version with build number (0.0.0.0) to semver version (0.0.0)
productVersion = regexp.MustCompile(`(\.[^\.]+)$`).ReplaceAllString(productVersion, ``)

return productVersion
}

func GetLatestRelease(releasesUrl string) (Release, error) {
release := Release{}

httpClient := http.Client{Timeout: time.Second * 5}

req, reqErr := http.NewRequest(http.MethodGet, releasesUrl, nil)
if reqErr != nil {
return release, reqErr
}

res, getErr := httpClient.Do(req)
if getErr != nil {
return release, getErr
}

if res.Body != nil {
defer res.Body.Close()
}

body, readErr := ioutil.ReadAll(res.Body)
if readErr != nil {
return release, readErr
}

// Hackery to convert the response into JSON that jsonq can parse
jsonObjectAsString := string(body)
// jsonObjectAsString = regexp.MustCompile(`^\[`).ReplaceAllString(jsonObjectAsString, `{"releases":[`)
// jsonObjectAsString = regexp.MustCompile(`\]$`).ReplaceAllString(jsonObjectAsString, `]}`)

// Use jsonq to access JSON
data := map[string]interface{}{}
dec := json.NewDecoder(strings.NewReader(jsonObjectAsString))
dec.Decode(&data)
jq := jsonq.NewQuery(data)

// Get properties from from JSON
// tag, _ := jq.String("releases", "0", "tag_name")
// productVersion := regexp.MustCompile(`^v`).ReplaceAllString(tag, ``)
// downloadUrl, _ := jq.String("releases", "0", "assets", "0", "browser_download_url")
tag, _ := jq.String("tag_name")
productVersion := regexp.MustCompile(`^v`).ReplaceAllString(tag, ``) // Converts tag (v0.0.0) to semver version (0.0.0) for easier comparion
downloadUrl, _ := jq.String("assets", "0", "browser_download_url")

if (downloadUrl == "") {
return release, errors.New("Could not get download URL")
}

release.productVersion = productVersion
release.downloadUrl = downloadUrl

return release, nil
}

func DownloadRelease(release Release) (string, error) {
pathToDownloadedFile := "ICARUS Update.exe"

// Get file to download
resp, err := http.Get(release.downloadUrl)
if err != nil {
return "", err
}
defer resp.Body.Close()

// Create file
out, err := os.Create(pathToDownloadedFile)
if err != nil {
return "", err
}
defer out.Close()

// Write to file
_, err = io.Copy(out, resp.Body)

return pathToDownloadedFile, nil
}
2 changes: 1 addition & 1 deletion src/web/public/launcher.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ <h1>ICARUS</h1>
<button onClick="window.app_quit()">Quit Application</button>
</p>
<p>
<small>Preview Build 0.0.0.1</small>
<small>Preview Build 0.1.1.0</small>
</p>
</div>
</body>
Expand Down

0 comments on commit 09de3a2

Please sign in to comment.