nw.js桌面程序自動更新(node.js表白記)

2020-10-20 博客園

 

Hello Google 

  Node.js 一個基於Google V8 的JavaScript引擎。
  一個偉大的端至端語言,或許我對你的熱愛源自於web這門極富情感的技術吧!

 

註:

  光陰似水,人生若夢,又是人間年尾。許久未說過如此矯情而生硬的話- -

  如此篇幅實在無法寫明白我扭曲的心理,2017望我還能繼續邁進!

  喜慶的話不多說,今天給大家分享一個大致3周前,初次涉足Node.js實現的nw.js桌面程序的自動更新模塊吧。

  本文不做教學,僅用於打臉!希望以此得到各位大神的幫助。

  我本沒有打算寫如此博客來誤人子弟,這裡感謝@老畢(=^ ^=)

  下面說的這個模塊是基於angular.js的,如此粗鄙的幾行代碼,還望各位同仁瞄眼之後便使勁的噴!

  

 

一、機制分析

  此機制的優劣性暫且不議,這僅是目前我唯一能想到的!

  已經說了太多無聊的話,這個機制我就畫個簡單的草圖來呈現吧。

  

  從圖中不難看出,我所謂的這個自動更新機制其實僅4步而已:

  1.確定本地版本號與遠端版本號

  2.檢測版本與平臺

  3.判斷版本差異性

  4.是否存在差異的進一步處理

 

 

二、模塊實現

 

  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 >'+ 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); });},

 

三、完整模塊代碼

/* 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 >'+ 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;}));

 

四、模塊調用

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!

 

相關焦點

  • 輕量級桌面應用開發的捷徑——nw.js
    開發者(KaiFaX)面向開發者、程式設計師的專業平臺!每個程式設計師都希望用自己喜歡的語言,自己喜歡的平臺、工具,寫自己喜歡的程序。
  • 什麼是伺服器端JavaScript Node.js?
    優點2可以進行實時處理,  例如,在使用PHP接收消息等情況下,如果不更新頁面就不知道是否接收消息,如果使用Node.js,則消息接收狀態將自動更新而不更新頁面將被更新。我想如果您想像使用SNS應用程式或G-mail會更容易理解。 缺點1:如果要 需要使用Node.js兼容伺服器的租賃伺服器上使用Node.js ,則在明顯的情況下,您需要使用VPS伺服器,或者即使可以使用它,響應速度也很慢。
  • Node.js 學習資料和教程(值得收藏)
    Node.jsHomePageNode官網七牛鏡像Infoq深入淺出Node.js系列(進階必讀)Node.js中文文檔框架meteorHomePageMeteor-DDP翻譯Meteor 非官方中文文檔(不包含API部分)基於meteor開發的開源項目列表  基於Express
  • 使用Chrome DevTools有效調試Node.js
    特別是,它們允許您在代碼中的特定位置暫停執行應用程式,並在程序仍在運行時檢查並修改變量的值。Node.js的內置調試器Node.js附帶一個內置的調試工具。如果您在命令行上啟動應用程式,並且應用程式的起點node debug index.js,那麼它將以調試模式啟動。
  • 10+ 最佳的 Node.js 教程結合實例
    (點擊尾部閱讀原文前往)原文:noeticforce.com/best-nodejs-tutorial-with-examples如果你正在找Node.js的學習資料及指南,那麼請繼續(閱讀),我們的教程將會覆蓋即時聊天應用、API服務編寫、投票問卷應用、人物投票APP、社交授權、 Node.js on Raspberry
  • 推薦一些Node.js超好用的工具庫
    開源地址:https://github.com/axios/axiosnodemailernodemailer是我用過最好用的 node.js 發郵件庫,上代碼!開源地址:https://github.com/showdownjs/showdownpm2pm2可以守護node.js程序,一旦node.js程序崩潰,pm2可以自動重啟Node.js程序.
  • Node.js發布2021年第一個安全更新,包括兩個高危漏洞
    近日,Node.js 發布了2021年第一個安全更新,其中包括一個 TLSWrap 的 use-after-free 高危漏洞,可能被利用來破壞內存,從而導致拒絕服務攻擊。
  • Node.JS快速入門
    1.2 NodeJS安裝(我們現在使用的版本是8.9.4)選安裝目錄進行安裝默認即可測試,在e盤創建文件夾nodedemo ,創建文本文件demo1.js,代碼內容我們在命令提示符下輸入命令node demo1.js ,結果如下:2.2 使用函數我們剛才的例子非常簡單,咱們這裡再看一下函數的使用:我們在命令提示符下輸入命令
  • centos7編程實踐:安裝nodejs
    Node.js是一個javascript運行環境。它讓javascript可以開發後端程序,實現幾乎其他後端語言實現的所有功能,可以與PHP、Java、Python、.NET、Ruby等後端語言平起平坐。
  • 實戰:在Node.js和Vue.js中構建文件壓縮應用程式
    Node.js為我們提供了一個模塊來協助文件壓縮。在本文中,我們將構建一個應用程式,用戶可以在該應用程式中上傳他們想要壓縮的文件,然後使用Node.js Zlib模塊下載該文件的壓縮版本。在桌面上,為應用程式創建一個文件夾,群毆取名為 compressor,並通過運行 npm init -y設置一個新的Node.js項目。我們先編寫後端服務,所以在項目中再建立一個 server 目錄。
  • Node.js對於Java開發者而言是什麼?
    (點擊尾部閱讀原文前往)英文原文:https://dzone.com/articles/what-is-nodejs-for-java-developers翻譯作者:碼農網 – 小峰因此,在本文中,我將嘗試為Java開發人員詮釋Node.js。運行時環境我們知道Java需要一個稱為JRE的運行時環境來運行Java程序。JRE有一個稱為Java Virtual Machine(JVM)的虛擬機。JVM有許多組件,如垃圾回收器(GC),即時(JIT)編譯器,解釋器,類裝載器,線程管理器,異常處理器,用於在不同時間執行不同的任務。
  • 專門針對初學者的Node.js教程
    安裝結束後,你可以輸入一個新命令「node」。使用該「node」命令有兩種不同的方法。第一種不帶任何參數,將打開一個交互式Shell「>」(REPL: read-eval-print-loop),你可以在這裡執行JavaScript代碼。
  • 【Node.js系列】Express 介紹
    :"scripts": {    "start": "node ./bin/www"  }路由Express 的主要內容有兩個:先來說路由路由(Routing)是由一個 URI(或者叫路徑)和一個特定的 HTTP 方法(GET、POST 等)組成的,涉及到應用如何響應客戶端對某個網站節點的訪問。
  • 如何在Windows系統安裝最新版本的Node.js
    工具windows作業系統Node.js技術JavaScript在使用vue框架、react框架和angularjs框架時,隨著框架版本不斷更新,對應的Node.js版本也在不斷更新;如果版本不對應,搭建框架的項目就啟動不了。
  • Node.js學習筆記第一天
    01-導入node模塊使用流程// node.js中將不同功能的代碼放在不同的js文件中,也叫模塊化,核心模塊會隨著安裝node.js時一併安裝// 1. fs');// 2.讀取文件// fs.readFile('文件路徑', options, 回調函數(err, data) => {})fs.readFile('./123.txt', 'utf-8', (err, data) => {  // 沒有錯誤信息 err 為 null  // 如果有錯誤信息 if成立 執行 throw 程序終止並拋出異常
  • Haiku 作業系統現已支持 Node.js
    不過從現在起,Haiku 作業系統將長期以來的缺席補上了,我們可以從 Haiku 的包管理系統 HaikuDepot 下載 Node.js 並進行安裝使用(目前僅支持 64 位版本,對 32 位版本的支持正在開發中)。當前可用的版本是 12.3.1,在撰寫本文時,該版本已更新為最新版本 12.10.0,並且也將支持即將推出的 LTS 版本。
  • node.js、MongoDB下一代的LAMP
    node.js、MongoDB下一代的LAMP 我們大部分人在做網站時,都用的是LAMP,殊不知LAMP已成過去式,新一代的小生:nix、node.js、MongoDB誕生了,讓我們走進他們,知道他們的故事!
  • 10 個最適合 Web 和 APP 開發的 NodeJS 框架
    Node.js Express 對於一個已經在使用 node.js 的開發人員來說,Express 或者」node.js express」並不是一個新鮮事。Express 框架提供了對 node.js 原生 API 的比較好的封裝,從而使開發者更加容易地使用node.js。 Express 框架提供了用來開發強壯的 web/移動應用,以及 API 的所有功能。
  • Node.js中的Stream
    以文件讀寫為例,文件讀寫的時候,stream並不是一次性地把一個文件中的所有內容都讀取到內存中再進行處理(就是再寫入到另外一個文件中),而是一塊數據一塊數據的進行讀取,讀取完一塊數據就處理一塊數據(把這塊數據寫入到另外一個文件中),而不會讓它一直在內存中。相比於傳統方式,使用stream來處理數據,可以高效的使用內存,更有可能來處理大文件。再以網絡數據傳輸(網上看視頻)為例。
  • 最新Node.js框架:Koa 2 實用入門
    Koa2是目前Node.js世界最火的web框架,無論從性能,還是流程控制上,koa 2和它的後宮(中間件)都是非常好的解決方案。