Code Monkey home page Code Monkey logo

nwjs-autoupdater's Introduction

Tiny golang app, which can be bundled with your NWJS application (actually, any application) and used for "autoupdates." I really hope that we will have something like this out-of-the box in NWJS!

Problem

NWJS is amazing platform for building desktop applications using web technologies. However, it is missing one important feature - an ability to seamlessly deliver updates for users. There were several attempts to solve this problem. For example - https://github.com/edjafarov/node-webkit-updater. But it does have issues when updater itself needs to be updated or NWJS platform needs to be updated (nwjs/nw.js#233).

Solution

This tiny golang application (when built it is just ~2MB) can be bundled with your NWJS application and then used to unpack updates. To update target application updater needs to know two things - where zip archive with the new version is located and where is the app's executable to restart application after update. These can be passed to updater via command line arguments --bundle and --inst-dir, where --bundle is the path to the zip archive with the new app version and --inst-dir is the path to app's executable.

Build

  1. You need to have golang installed and properely configured ;)
  2. Install glide https://github.com/Masterminds/glide#install
  3. Install rsrc go get github.com/akavel/rsrc
  4. Clone this repo
  5. Go to src/nwjs-autoupdater and edit nwjs-autoupdater.exe.manifest as you like. WARNING: don't touch the requestedExecutionLevel value.
  6. Execute rsrc -manifest nwjs-autoupdater.exe.manifest -ico <path to your icon> -o nwjs-autoupdater.syso to generate a .syso file with specified resources embedded and to make it WORK ON WINDOWS.
  7. Execute glide install to install dependencies
  8. Go back to the root folder and run GOPATH=$(pwd) go build nwjs-autoupdater to build for current platform. To build for other platforms use appropriate flags:
    GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -o updater 
    GOOS=windows GOARCH=386 go build -ldflags "-s -w -H=windowsgui" -o updater.exe
    GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -H=windowsgui" -o updater.exe

Full list of the platforms and archetectures, which is possible to cross-compile to can be found here https://github.com/golang/go/blob/master/src/go/build/syslist.go

Example

Let's consider the small example to see how it can be used.

  • Start application from the index.js (instead of directly pointing it to the .html file) (Example)
  • Open main window (so user will not have to wait)
  • Create temporary folder in the system's temp directory (let's call it T)
  • Create updates folder in the T folder.
  • Download manifest file from the remote location. It has the format, which is similar to the one used in https://github.com/edjafarov/updater. For example:
{
  "version": "1.1.0",
  "createdAt": "2016-09-15T15:02:02.365Z",
  "win32": {
    "url": "https://example.com/windows-x32-v1.1.0.zip",
    "sha256": "a5db62bbe2c382534162d921ae6319ae83384256ab7f40e928a323603653e22b"
  },
  "darwin": {
    "url": "https://example.com/darwin-x64-v1.1.0.zip",
    "sha256": "e9efa23c40cf17a1d0c77227c962b5659c099959ec199782e03f162dcbbdae19"
  }
}
  • Compare local app's version with the one from manifest file
  • If app has the latest version from manifest - do nothing
  • If app is outdated - download zip archive to the updates folder created before. When it is downloaded - show notification for user using new Notification or chrome.notifications.create. If user clicks on notification - proceed.
  • Copy bundled updater executable to the folder T (don't move it because temp folders sometimes can be, you know, - cleaned :)
  • Run copy of the updater executable using spawn in detached mode and close application. Pass path to the downloaded archive and path to the main app executable to updater using command line arguments.
  • When updater starts it unpacks zip archive to the temp directory. Than it creates backup of the old app by renaming parent directory to .bak (on macOS the Application.app will be renamed itself)
  • Move unpacked files to the new location. If all went well - delete bak, delete temp files, delete zip archive and start main application.

Due to the fact that we copy and run updater from the temp directory - any files in application can be updated!

Windows updates

Autoupdates on windows were really painfull. All those "Run as Administrator" and issues with replacing executable, which is running :( But, this tiny updater solves this issue too. In the root of the repo you can find updater.exe.manifest, which defines metadata of the binary and one important (for Windows) thing - permissions level. The line <requestedExecutionLevel level="asInvoker" uiAccess="false"/> will allow your app to run updater on windows without admin rights. To embed this information in your updater's binary you need to use https://github.com/akavel/rsrc - amazing tool for embedding binary resources in Go programs. Also you can pass the path to the .ico file and updater's binary will get a nice icon ;)

Why golang?

Because it is simple and more importantly - it can be compiled from any platform for any platform.

Credits

I'm not very proficient in the golang (yet) so I've used and slightly modified several packages from the go community (all credits are going to them):

https://github.com/skratchdot/open-golang - Open a file, directory, or URI using the OS's default application for that object type. Optionally, you can specify an application to use.
https://github.com/ivaxer/go-xattr - Extended attribute support for Go #golang
And very simple zip unpacker (can't find the source)

nwjs-autoupdater's People

Contributors

oaleynik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

nwjs-autoupdater's Issues

License information

I didn't see any kind of license attached to this updater. Can you please provide a license file ?

One note to add to docs maybe

One thing that just tripped me up - The executable on Windows has to be compiled for the same processor platform as your NW.js. (Or, at least in my case, the 64-bit updater couldn't rename the folder for a 32-bit app.) Otherwise you'll get an "access denied" error.

Making sure the app always restarts

I think that, currently, the updater just fails with a log when there's a problem, right? Is there a way to make sure it always restarts the app, even if the update failed? I ask because I have infrequent problems with Windows permissions (sometimes will update, sometimes not?), and if it doesn't work, I want it to just go back into the app.

The process cannot access the file because it is being used by another process

Hello,

I have tried to follow the steps provided in the readme. However, when the updater is finished I get the following message in updater.log:

2017/03/30 18:55:09 C:\Users\Even\AppData\Roaming\vnpc2\VNPCv2.exe: creating new file: open C:\Users\Even\AppData\Roaming\vnpc2\VNPCv2.exe: The process cannot access the file because it is being used by another process.

Am I doing something wrong in my code? I assume the reason is that my NW client is not 100% closed when the updater is trying to replace VNPCv2.exe.

This is the code I use to start the update:

if(newUpdate) {
	alert("Update found! I will now download the update...");

	var url = global.va.getUpdateUrl();
	var TMP_DIR = require('os').tmpdir() + "/vnpcUpdate";

	var download = require('download-file')
	
	download(url, { directory: TMP_DIR, filename: "update.zip" }, function(err){
		const shell = nw.require('shelljs');
		const path = nw.require('path');

		const APPDIR = path.dirname(process.execPath);
		const UPDATER_BIN = TMP_DIR + '/updater.exe';
		
		shell.cp(APPDIR + '/updater.exe', UPDATER_BIN);
		shell.chmod(755 & ~process.umask(), UPDATER_BIN);

		const spawn = require('child_process').spawn;
		alert("Update downloaded. I will now quit in order to install the new update.");

		spawn(UPDATER_BIN, [
			'--bundle', 'update.zip',
			'--inst-dir', APPDIR
		], {
			cwd: path.dirname(UPDATER_BIN),
			detached: true,
			stdio: 'ignore'
		}).unref();
		
		nw.App.quit();
	});
}

updater.exe is built using GOOS=windows GOARCH=386 go build -ldflags "-s -w -H=windowsgui" -o updater.exe nwjs-autoupdater with the <requestedExecutionLevel level="asInvoker" uiAccess="false"/> set in the manifest-file.

I have also tried with <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>, however this gives me this error in my application when trying to execute the updater:

Error: spawn EACCES
unless I run my app "As administrator" - In that case I get the same problem as described earlier.

My application executable (VNPCv2.exe) is built using nw-builder

Support for delta updates ?

Hello,

I wanted to ask if this updater supports delta updates such as the need to update a single binary or a file ?

At the moment if there's just a single line change then i will have to push down more than 70 MBs of data over the wire for client to update his app ?

Suggestion: pre-build binaries

I think since there are a number of tools unfamiliar to Node.js / NW.js authors required for builds (For instance, I haven't gotten the rsrc thing working yet nor do I really understand it) that you should actually distribute the pre-built binaries. In an ideal scenario, someone would add this to their NW.js project via NPM, and NPM can't really build a .go project. However, it would be trivial to get the binary path if it's already in the Node project (and copy it to the temp installation directory).

Obviously, you can include the source .go files with the binaries so that people can still do custom builds, but just add the binaries (e.g. /dist/win32/updater.exe) for each NW.js-supported platform.

The updater script needs a bit of abstraction to use this in a generic way (removing hard-coded installation folders and app names, for example), but it works really well!

Clarification on documentation

I'm confused about this.

The line <requestedExecutionLevel level="asInvoker" uiAccess="false"/> will allow your app to run updater on windows without admin rights. To embed this information in your updater's binary you need to use https://github.com/akavel/rsrc

Are you saying you can't just use the build script? Some other action is needed with the output .exe file? If so, why?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.