zoukankan      html  css  js  c++  java
  • nw.js桌面程序自动更新(node.js表白记)

    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!

  • 相关阅读:
    mysql 函数 存储过程 事件(event) job 模板
    protobuf 无proto 解码 decode 语言 java python
    mitmproxy fiddler 抓包 填坑
    android adb 常用命令
    android机器人 模拟 踩坑过程
    RabbitMQ添加新用户并支持远程访问
    Windows下RabbitMQ安装及配置
    Java mybatis mysql 常用数据类型对应关系
    easyExcel 踩坑
    linux防火墙查看状态firewall、iptable
  • 原文地址:https://www.cnblogs.com/BGOnline/p/6291242.html
Copyright © 2011-2022 走看看