lgq
2026-03-31 e491cdb48129752324c4e3764f99bd9203c56dec
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
//build:20240724
// 负责固件的升级
import log from './dxLogger.js'
import com from './dxCommon.js'
import http from './dxHttp.js'
import * as os from 'os';
 
const ota = {}
//获取当前磁盘剩余大小(k)可能不同的操作系统指令不一样
ota.DF_CMD = `df -k / | awk 'NR==2 {print $4}'`
ota.OTA_ROOT = '/ota'
ota.OTA_RUN = ota.OTA_ROOT + '/run.sh'
 
 
/**
 * HTTP升级:网络下载升级包升级
 * @param {string} url 必填,下载升级包的http url地址 
 * @param {string} md5 必填,升级包的md5标识,下载完通过md5来判断是否完整。32长度的全小写16进制字符串
 * @param {number} size 非必填,升级包的大概大小,单位是k,如果文件太大而剩余磁盘不够,会提前报错误,不会开始启动下载 
 * @param {number} timeout 非必填,尝试链接下载地址的超时时间(不是下载完成的时间),缺省是3秒
 * @param {string} password 非必填,下载安装包的密码,可选,如果设置,下载时需要输入密码
 */
ota.updateHttp = function (url, md5, timeout = 3, password, size) {
    if (!url || !md5) {
        throw new Error("The 'url' and 'md5' param should not be null")
    }
    if (size && (typeof size != 'number')) {
        throw new Error("The 'size' param should be a number")
    }
    //1. 查看磁盘还剩余的大小
    let df = parseInt(com.systemWithRes(ota.DF_CMD, 1000))
    if (size) {
        if (df < (3 * size)) {//大概本地必须有安装包3倍大小的空间
            throw new Error('The upgrade package is too large, and not be enough space on the disk to download it')
        }
    }
    //2. 下载文件到临时目录
    const firmware = '/upgrades.zip'
    const temp = '/upgrades.temp'
    com.systemBrief(`rm -rf ${firmware} && rm -rf ${temp} `) //先删除ota根目录
    
    let downloadRet = http.download(url + (password ? "&password=" + password : '') , temp, null, timeout*1000)
    let fileExist = (os.stat(temp)[1] === 0)
    if (!fileExist) {
        log.error("download result" + downloadRet)
        com.systemBrief(`rm -rf ${firmware} && rm -rf ${temp} `)
        throw new Error('Download failed, please check the url:' + url)
    }
    //3. 计算并比较md5是否一样
    let md5Hash = com.md5HashFile(temp)
    md5Hash = md5Hash.map(v => v.toString(16).padStart(2, 0)).join('')
    if (md5Hash != md5) {
        com.systemBrief(`rm -rf ${firmware} && rm -rf ${temp} `)
        throw new Error('Download failed with wrong md5 value')
    }
    //4. md5校验通过,将升级包放到升级目录下,等待重启升级
    com.systemBrief(`mv ${temp} ${firmware} `)
}
 
 
/**
 * 文件升级:通过其他方式将升级包放到用户目录下,调用此方法升级
 * @param {string} path 必填,下载升级包的http url地址 
 * @param {string} md5 必填,升级包的md5标识,下载完通过md5来判断是否完整。32长度的全小写16进制字符串
 * @param {number} size 非必填,升级包的大概大小,单位是k,如果文件太大而剩余磁盘不够,会提前报错误,不会开始启动下载 
 */
ota.updateFile = function (path, md5, size) {
    if (!path || !md5) {
        throw new Error("The 'path' and 'md5' param should not be null")
    }
    if (size && (typeof size != 'number')) {
        throw new Error("The 'size' param should be a number")
    }
 
    //1. 查看磁盘还剩余的大小
    let df = parseInt(com.systemWithRes(ota.DF_CMD, 1000))
    if (size) {
        if (df < (3 * size)) {//大概本地必须有安装包3倍大小的空间
            throw new Error('The upgrade package is too large, and not be enough space on the disk to download it')
        }
    }
    
    //2. 计算并比较md5是否一样
    let md5Hash = com.md5HashFile(path)
    md5Hash = md5Hash.map(v => v.toString(16).padStart(2, 0)).join('')
    if (md5Hash != md5) {
        throw new Error('With wrong md5 value')
    }
    
    //3. md5校验通过,将升级包放到升级目录下,等待重启升级
    const firmware = '/upgrades.zip'
    com.systemBrief(`mv ${path} ${firmware} `)
}
 
 
/**
 * 注意:此方法即将过期,用于兼容旧版本,新版本不推荐使用
 * 升级分二大步骤,第一步是在应用端下载升级包(zip),解压升级包
 * 第二步包括重启设备,利用脚本复制目录和文件或额外一些操作
 * 如果在升级包根目录下放一个custom_update.sh,就会先执行这个shell文件,我们可以在这个文件里放一些自定义的升级动作
 * @param {string} url 必填,下载升级包的http url地址 
 * @param {string} md5 必填,升级包的md5标识,下载完通过md5来判断是否完整。32长度的全小写16进制字符串
 * @param {number} size 非必填,升级包的大概大小,单位是k,如果文件太大而剩余磁盘不够,会提前报错误,不会开始启动下载 
 * @param {string} shell 非必填,重启设备后的升级脚本内容,解压后的文件夹缺省是 /ota/temp,升级会缺省把/ota/temp下所有文件拷贝复制到/app/code/下
 * @param {number} timeout 非必填,尝试链接下载地址的超时时间(不是下载完成的时间),缺省是3秒
 */
ota.update = function (url, md5, size, shell, timeout = 3) {
    if (!url || !md5) {
        throw new Error("The 'url' and 'md5' param should not be null")
    }
    if (size && (typeof size != 'number')) {
        throw new Error("The 'size' param should be a number")
    }
    //1. 查看磁盘还剩余的大小
    let df = parseInt(com.systemWithRes(ota.DF_CMD, 1000))
    if (size) {
        if (df < (3 * size)) {//大概本地必须有安装包3倍大小的空间
            throw new Error('The upgrade package is too large, and not be enough space on the disk to download it')
        }
    }
    //2. 下载文件到特定目录
    const firmware = ota.OTA_ROOT + '/download.zip'
    const temp = ota.OTA_ROOT + '/temp'
    com.systemBrief(`rm -rf ${ota.OTA_ROOT} && mkdir ${ota.OTA_ROOT} `) //先删除ota根目录
    let download = `wget --no-check-certificate --timeout=${timeout} -c "${url}" -O ${firmware} 2>&1`
    com.systemBrief(download, 1000)
    let fileExist = (os.stat(firmware)[1] === 0)
    let downloadRet
    if (!fileExist) {
        downloadRet = http.download(url, firmware, null, timeout*1000)
    }
    fileExist = (os.stat(firmware)[1] === 0)
    if (!fileExist) {
        log.error("download result" + downloadRet)
        throw new Error('Download failed, please check the url:' + url)
    }
    //3. 计算并比较md5是否一样
    let md5Hash = com.md5HashFile(firmware)
    md5Hash = md5Hash.map(v => v.toString(16).padStart(2, 0)).join('')
    if (md5Hash != md5) {
        log.error("download result" + downloadRet)
        throw new Error('Download failed with wrong md5 value')
    }
    //4. 解压
    com.systemBrief(`mkdir ${temp} && unzip -o ${firmware} -d ${temp}`)
    //5. 执行自定义的升级脚本
    const custom_update = temp+'/custom_update.sh'
    if(os.stat(custom_update)[1] === 0){
        com.systemBrief(`chmod +x ${custom_update}`)
        com.systemWithRes(`${custom_update}`)
    }
    //6. 构建脚本文件
    if (!shell) {
        //缺省只是拷贝目录并删除ota根目录
        shell = `cp -r ${temp}/* /app/code \n rm -rf ${ota.OTA_ROOT}`
    }
 
    com.systemBrief(`echo "${shell}" > ${ota.OTA_RUN} && chmod +x ${ota.OTA_RUN}`)
    fileExist = (os.stat(ota.OTA_RUN)[1] === 0)
    if (!fileExist) {
        throw new Error('Build shell file failed')
    }
    com.systemWithRes(`${ota.OTA_RUN}`)
}
 
/**
 * 注意:此方法即将过期,用于兼容旧版本,新版本不推荐使用
 * 特殊:兼容旧的升级格式,必须是tar.xz格式,且只用来升级资源文件
 * 升级分二大步骤,第一步是在应用端下载升级包(zip),解压升级包
 * 第二步包括重启设备,利用脚本复制目录和文件或额外一些操作
 * 如果在升级包根目录下放一个custom_update.sh,就会先执行这个shell文件,我们可以在这个文件里放一些自定义的升级动作
 * @param {string} url 必填,下载升级包的http url地址 
 * @param {string} md5 必填,升级包的md5标识,下载完通过md5来判断是否完整。32长度的全小写16进制字符串
 * @param {number} size 非必填,升级包的大概大小,单位是k,如果文件太大而剩余磁盘不够,会提前报错误,不会开始启动下载 
 * @param {string} shell 非必填,重启设备后的升级脚本内容,解压后的文件夹缺省是 /ota/temp,升级会缺省把/ota/temp下所有文件拷贝复制到/app/code/下
 * @param {number} timeout 非必填,尝试链接下载地址的超时时间(不是下载完成的时间),缺省是3秒
 */
ota.updateResource = function (url, md5, size, shell, timeout = 3) {
    if (!url || !md5) {
        throw new Error("The 'url' and 'md5' param should not be null")
    }
    if (size && (typeof size != 'number')) {
        throw new Error("The 'size' param should be a number")
    }
    //1. 查看磁盘还剩余的大小
    let df = parseInt(com.systemWithRes(ota.DF_CMD, 1000))
    if (size) {
        if (df < (3 * size)) {//大概本地必须有安装包3倍大小的空间
            throw new Error('The upgrade package is too large, and not be enough space on the disk to download it')
        }
    }
    //2. 下载文件到特定目录
    const firmware = ota.OTA_ROOT + '/download.tar.xz'
    const temp = ota.OTA_ROOT + '/temp'
    com.systemBrief(`rm -rf ${ota.OTA_ROOT} && mkdir ${ota.OTA_ROOT} `) //先删除ota根目录
    let download = `wget --no-check-certificate --timeout=${timeout} -c "${url}" -O ${firmware} 2>&1`
    com.systemBrief(download, 1000)
    let fileExist = (os.stat(firmware)[1] === 0)
    if (!fileExist) {
        http.download(url, firmware, null, timeout*1000)
    }
    fileExist = (os.stat(firmware)[1] === 0)
    if (!fileExist) {
        throw new Error('Download failed, please check the url:' + url)
    }
 
    //3. 计算并比较md5是否一样
    let md5Hash = com.md5HashFile(firmware)
    md5Hash = md5Hash.map(v => v.toString(16).padStart(2, 0)).join('')
    if (md5Hash != md5) {
        throw new Error('Download failed with wrong md5 value')
    }
    //4. 解压
    //tar -xJvf test.tar.xz -C /path/
    com.systemBrief(`mkdir ${temp} && tar -xJvf ${firmware} -C ${temp}`)
    //5. 构建脚本文件
    if (!shell) {
        shell = `
        source=${temp}/vgapp/res/image/bk.png
        target=/app/code/resource/image/bg.png
        if test -e "\\$source"; then
            cp "\\$source" "\\$target"
        fi
        source=${temp}/vgapp/res/image/bk_90.png
        target=/app/code/resource/image/bg_90.png
        if test -e "\\$source"; then
            cp "\\$source" "\\$target"
        fi
        source=${temp}/vgapp/res/font/AlibabaPuHuiTi-2-65-Medium.ttf
        target=/app/code/resource/font.ttf
        if test -e "\\$source"; then
            cp "\\$source" "\\$target"
        fi
        source=${temp}/vgapp/wav/*.wav
        target=/app/code/resource/wav/
        cp "\\$source" "\\$target"
        rm -rf ${ota.OTA_ROOT}
        `
    }
 
    com.systemBrief(`echo "${shell}" > ${ota.OTA_RUN} && chmod +x ${ota.OTA_RUN}`)
    fileExist = (os.stat(ota.OTA_RUN)[1] === 0)
    if (!fileExist) {
        throw new Error('Build shell file failed')
    }
    com.systemWithRes(`${ota.OTA_RUN}`)
}
/**
 * 由调用者来启动重启,一般是update函数没有错误,运行完成并向北向汇报结果后再调用重启
 */
ota.reboot = function () {
    com.asyncReboot(2)
}
//-------------------------private-------------------
 
export default ota