本身動手開發更好用的markdown編輯器-06(自動更新)

這裏文章都是從我的的github博客直接複製過來的,排版可能有點亂. 原始地址  http://benq.im/2015/05/12/hexomd-06/
 
文章目錄
  1. 1. 自動更新方案
  2. 2. 實現
    1. 2.1. 安裝依賴模塊
    2. 2.2. 自定義package.json
    3. 2.3. updater.js
    4. 2.4. 綁定更新按鈕
  3. 3. 總結
  4. 4. 附件

上一篇咱們實現了粘貼上傳圖片功能.javascript

今天將實現自動更新的功能,有了這個功能之後我再發博客就不須要每次都把最新的程序從新打包上傳了.html

對於不想看如何實現的朋友,直接下載打包好的程序就行,之後更新能夠點擊軟件右上角的第一個按鈕便可(手動).
java

自動更新方案

在作上一個軟件Gungnir的時候,爲了能夠顯示更新進度,自動更新的方案是列出全部須要更新的文件,而後自動下載每一個文件並覆蓋,可是在須要更新一些node模塊(文件通常都不少)時就至關麻煩了,有一個文件傳輸失敗就會致使更新出錯.實現起來至關麻煩,並且也並不能帶來什麼優點.node

因此作這個軟件的自動更新的時候,我用了更爲簡單粗暴的方案:將須要更新的文件打包成zip文件,直接下載並解壓覆蓋便可.git

實現

自動更新做爲較單獨的功能模塊,我把所有代碼放在modules/updater.js,這裏就不把所有代碼貼出來了,須要的本身點連接看,裏面有註釋. 我只講一些實現細節.github

安裝依賴模塊

首先是安裝兩個新增了的node模塊依賴whenbufferhelper,第一個是promise模塊,第二個看名字就知道,無須解釋.npm

1
npm install when --save

 

1
npm install bufferhelper --save

7z.exe放到軟件根目錄備用
json

自定義package.json

增長了updater配置節點,配置最新的版本號version和對應的補丁文件地址package,因爲我這個軟件功能不多,代碼並很少,所以我如今每次更新都是包含以前全部補丁的文件打包,加起來也才1m多,這樣實現比較簡單,只要下載最新的包便可.promise

1
2
3
4
5
...
"updater":{
"version":"0.6.0.1",
"package":"http://7xit5q.com1.z0.glb.clouddn.com/update.zip"
}

 

updater.js

updater.js裏實現了hmd.updater模塊,包含4個方法hexo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//配置文件,用於判斷是否有新版本
var packageFile = 'https://raw.githubusercontent.com/benqy/hexomd/master/package.json',
//當前程序的運行目錄
execPath = require('path').dirname(process.execPath),
//補丁文件存放目錄
updatePath = execPath + '\\update',
fs = require('fs'),
util = require('./helpers/util'),
when = require('./node_modules/when');
var checkUpdateTimer;
hmd.updater = {
//下載指定url的內容並返回promise對象
get: function (url) {
...
},
//檢查更新
checkUpdate: function () {
...
},
//下載補丁包
update:function(packageUrl){
...
},
//安裝補丁包
install: function () {
...
}
};

更新的流程爲 : checkUpdate檢查是否有更新 > update下載補丁包 > install安裝補丁包

get方法裏要注意的是下載下來的內容要判斷是否通過GZIP壓縮,若是是,則要用node自帶的zlib解壓.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
req = protocolModule.get(urlOpt, function (res) {
//是否通過gzip壓縮
var isGzip = !!res.headers['content-encoding'] && !!~res.headers['content-encoding'].indexOf('gzip');
...
if (isGzip) {
require('zlib').unzip(buffer, function (err, buffer) {
gzipDeferred.resolve(buffer);
});
}
else {
gzipDeferred.resolve(buffer);
}
...
return deferred.promise;

 

checkUpdate方法裏先下載線上的package.json文件與本地進行比較,若是版本號不一致,則提示用戶更新.若是用戶選擇更新,則下載package.json到本地,而後調用update方法下載補丁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
checkUpdate: function () {
hmd.msg('===正在檢查更新===');
//超時檢查
checkUpdateTimer =setTimeout(function(){
hmd.msg('===更新失敗,可能github被牆了===', hmd.MSG_LEVEL.error);
}, 10000);
var locPackage = require('nw.gui').App.manifest;
//獲取版本信息和更新文件列表
hmd.updater.get(packageFile)
.then(function (packageData) {
clearTimeout(checkUpdateTimer);
packageData.text = packageData.buffer.toString();
if (!packageData.text) return;
var remotePackage = JSON.parse(packageData.text);
if (remotePackage.updater.version != locPackage.updater.version){
if (confirm('是否更新到最新版本:' + remotePackage.updater.version)) {
//若是update目錄不存在則建立
if (!fs.existsSync(updatePath)) {
util.mkdir(updatePath, true);
}
//保存最新的配置文件
fs.writeFileSync(updatePath + '\\package.json', packageData.buffer);
//下載補丁包
hmd.updater.update(remotePackage.updater.package);
}
}
else {
hmd.msg('當前版本:' + remotePackage.updater.version + ',已是最新版');
}
});
}

update方法下載補丁包到update目錄,而後調用install安裝補丁

1
2
3
4
5
6
7
8
update:function(packageUrl){
hmd.msg('===正在下載更新文件===', hmd.MSG_LEVEL.warnings);
hmd.updater.get(packageUrl + '?' + new Date() * 1)
.then(function (data) {
fs.writeFileSync(updatePath + '\\update.zip',data.buffer);
hmd.updater.install();
});
},

 

install將補丁包經過7z.exe解壓覆蓋到程序目錄,而後提示用戶重啓軟件.

1
2
3
4
5
6
7
8
9
install: function () {
//移動配置文件
require("child_process").exec('xcopy "' + updatePath + '\\package.json" "' + execPath + '\\package.json" /s /e /y');
//解壓縮補丁文件
var unzip = execPath + '\\7z.exe x '+ updatePath +'\\update.zip -y';
require("child_process").exec(unzip,function(){
hmd.msg('===更新完成,重啓後生效===');
});
}

 

這裏我直接用7z.exe,反正也不大,也可使用一些開源的node壓縮模塊.

綁定更新按鈕

更新模塊完成了,如今將功能綁定到按鈕上.
先在modules/directives增長新的directivehmdUpdate

1
2
3
4
5
6
7
8
angular.module('hmd.directives', [])
.directive('hmdUpdate', [function () {
return function (scope, elem) {
$(elem[0]).on('click', function () {
hmd.updater.checkUpdate();
});
};
}])

 

而後將index.html上的更新按鈕與directive綁定

1
<a class="btn rectbtn" href="javascript://" title="點擊檢查更新" hmd-update>...</a>

 

別忘了引用updater.js

1
2
3
<script src="modules/app.js"></script>
<script src="modules/updater.js"></script>
<script src="modules/directives.js"></script>

總結

基本的自動更新的功能比圖片上傳更爲簡單,可是今天作的這個功能還有不少細節問題,好比:

  1. 沒法自動刪除新版本不須要的文件
  2. 之後若是程序大了,更新補丁每次都全量打包會致使更新很慢
  3. 更新後不會自動重啓軟件.
  4. 更好的方案是自動根據git的提交信息生成更新列表,而且根據版本號管理.

接下來的計劃:

  1. 雲同步.
  2. 插件機制
  3. 表情插件.

附件

本篇程序打包.
項目地址

相關文章
相關標籤/搜索