分享

nw.js桌面程序自动更新(node.js表白记)

 愤怒的葱花 2017-05-15

 

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 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);
    });
},
复制代码

 

三、完整模块代码

复制代码
/*
    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;
}));
复制代码

 

四、模块调用

复制代码
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!

 

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约