Hello Google
Node.js 一個基於Google V8 的JavaScript引擎。
一個偉大的端至端語言,或許我對你的熱愛源自於web這門極富情感的技術吧!
注:html
光陰似水,人生若夢,又是人間年尾。許久未說過如此矯情而生硬的話- -node
如此篇幅實在沒法寫明白我扭曲的心理,2017望我還能繼續邁進!web
喜慶的話很少說,今天給你們分享一個大體3周前,初次涉足Node.js實現的nw.js桌面程序的自動更新模塊吧。promise
本文不作教學,僅用於打臉!但願以此獲得各位大神的幫助。網絡
我本沒有打算寫如此博客來誤人子弟,這裏感謝@老畢(=^ ^=)ide
下面說的這個模塊是基於angular.js的,如此粗鄙的幾行代碼,還望各位同仁瞄眼以後便使勁的噴!ui
1、機制分析spa
此機制的優劣性暫且不議,這僅是目前我惟一能想到的!code
已經說了太多無聊的話,這個機制我就畫個簡單的草圖來呈現吧。orm
從圖中不難看出,我所謂的這個自動更新機制其實僅4步而已:
1.肯定本地版本號與遠端版本號
2.檢測版本與平臺
3.判斷版本差別性
4.是否存在差別的進一步處理
2、模塊實現
1.模塊依賴
fs = require('fs'); path = require('path'); request = require('request'); child_process = require('child_process');
如下爲依賴模塊的簡要釋義:
fs: node.js 文件系統模塊
path: node.js 文件路徑模塊
request: node.js http模塊
child_process: node.js 子進程模塊
2.版本對比(使用文件讀寫模塊對本地版本號的寫入與更新)
compareVer: function(RequestUrl) { var remoteURL = RequestUrl; var deferred = $q.defer(); fs.readFile(path.join(nwDir, 'version.txt'), function(err, data) { if(err) { fs.writeFile(path.join(nwDir, 'version.txt'), '0.0.1', function(err) { if(err) throw err; }); alert("系統檢測到重要文件丟失,請手動重啓應用!");
process.exit(0); }else { version.localVer = data; $http.get(remoteURL).success(function(items) { if(items.code == 200) { version.remoteVer = items.data.version; var isUpdate = version.localVer && version.remoteVer && version.localVer != version.remoteVer ? true : false; items.isUpdate = isUpdate; if(isUpdate) { fs.writeFile(path.join(nwDir, 'version.txt'), version.remoteVer, function(err) { if(err) throw err; }); } deferred.resolve(items); } }).error(function(data, status, headers, config) { alert("程序初始化失敗,請檢查網絡鏈接!"); }); } }); return deferred.promise; },
3.執行升級(使用http模塊對差別版進行下載並執行文件流寫入操做)
update: function(DownloadUrl, total) { request(DownloadUrl, function (error, response) { if(!error && response.statusCode == 200) { angular.element('.title').html('升級完成'); angular.element('#progress > span').html('100'); $interval.cancel(timer); var t = 3; var interval = $interval(function() { angular.element('.title').html('自動重啓'); angular.element('#progress').html('<span style="font-size: 5em;">'+ t-- +'</span>'); if(t < 0) { win.hide() child_process.exec(file, function(err, stdout, stderr) { process.exit(0); }); $interval.cancel(interval); } }, 1000) } }).pipe(fs.createWriteStream(file)); var timer = $interval(function() { var loaded = fs.statSync(file).size; var percentComplete = loaded / total; var downloadProgress = (percentComplete * 100).toFixed(1); angular.element('#progress > span').html(downloadProgress); }, 100); return; }
4.無差別性處理(隱藏主進程並建立子進程)
normal: function() { win.hide(); child_process.exec(file, function(err, stdout, stderr) { process.exit(0); }); },
3、完整模塊代碼
/* nw.js桌面程序自動更新module for angular Author: BGONLINE 2016-12-29 */ (function(angular, factory) { if(typeof define === 'function' && define.amd) { define('bgo-update', ['angular'], function(angular) { return factory(angular); }); }else { return factory(angular); } }(typeof angular === 'undefined' ? null : angular, function(angular) { var module = angular.module('bgoUpdate', []); 'use strict'; module .factory('bgoAutoUpdate', ['$http', '$q', '$interval', '$timeout', function($http, $q, $interval, $timeout) { var version = { localVer: '', remoteVer: '' } var fs = require('fs'); var path = require('path'); var request = require('request'); var child_process = require('child_process'); var nwPath = process.execPath; var nwDir = path.dirname(nwPath); var file = path.join(nwDir, 'current.exe'); return { normal: function() { var str = ''; var interval = $interval(function() { str += '.'; angular.element('#progress > span').html(str); if(str.length > 3) { win.hide() child_process.exec(file, function(err, stdout, stderr) { process.exit(0); $interval.cancel(interval); }); } }, 1000) }, compareVer: function(RequestUrl) { var remoteURL = RequestUrl; var deferred = $q.defer(); fs.readFile(path.join(nwDir, 'version.txt'), function(err, data) { if(err) { fs.writeFile(path.join(nwDir, 'version.txt'), '0.0.1', function(err) { if(err) throw err; }); layer.alert("系統檢測到重要文件丟失,請手動重啓應用!", {closeBtn: 0, icon: 5, shade: 0}, function() { layer.closeAll(); process.exit(0); }); }else { version.localVer = data; $http.get(remoteURL).success(function(items) { if(items.code == 200) { version.remoteVer = items.data.version; var isUpdate = version.localVer && version.remoteVer && version.localVer != version.remoteVer ? true : false; items.isUpdate = isUpdate; if(isUpdate) { fs.writeFile(path.join(nwDir, 'version.txt'), version.remoteVer, function(err) { if(err) throw err; }); } deferred.resolve(items); } }).error(function(data, status, headers, config) { layer.msg("程序初始化失敗,請檢查網絡鏈接!", function() {}); }); } }); return deferred.promise; }, update: function(DownloadUrl, total) { request(DownloadUrl, function (error, response) { if(!error && response.statusCode == 200) { angular.element('.title').html('升級完成'); angular.element('#progress > span').html('100'); $interval.cancel(timer); var t = 3; var interval = $interval(function() { angular.element('.title').html('自動重啓'); angular.element('#progress').html('<span style="font-size: 5em;">'+ t-- +'</span>'); if(t < 0) { win.hide() angular.element('.title').html('學籍系統保護模塊'); angular.element('#progress > span').html('請勿關閉!'); child_process.exec(file, function(err, stdout, stderr) { process.exit(0); }); $interval.cancel(interval); } }, 1000) } }).pipe(fs.createWriteStream(file)); var timer = $interval(function() { var loaded = fs.statSync(file).size; var percentComplete = loaded / total; var downloadProgress = (percentComplete * 100).toFixed(1); angular.element('#progress > span').html(downloadProgress); }, 100); return; } } }]) return module; }));
4、模塊調用
App.controller('UpdateController', ["$rootScope", "$scope", 'bgoAutoUpdate', function($rootScope, $scope, bgoAutoUpdate) { bgoAutoUpdate.compareVer($rootScope.rootUrl + 'index/login/getVersion?platform=' + process.platform).then(function(res) { // 判斷版本 $scope.isUpdate = res.isUpdate; if($scope.isUpdate) { bgoAutoUpdate.update(res.data.fileUrl, res.data.fileSize, res.data.version); // 執行更新 }else { bgoAutoUpdate.normal(); } }); }]);
如此可愛的node.js,感謝Google!