diff --git a/packages/vue-cli-plugin-uni/lib/check-update.js b/packages/vue-cli-plugin-uni/lib/check-update.js index d0170a2da68ed3a2b5f7ebec1ac6e1bd0b6884ff..5d327fa72873de0b009f3b53f0a354dd8760d56a 100644 --- a/packages/vue-cli-plugin-uni/lib/check-update.js +++ b/packages/vue-cli-plugin-uni/lib/check-update.js @@ -1,34 +1,261 @@ -module.exports = async function checkUpdate () { - const { - isInHBuilderX - } = require('@dcloudio/uni-cli-shared') - - if (isInHBuilderX) { // 仅 cli 提供检测更新 - return - } - - const pkg = require('../package.json') - const checkForUpdate = require('update-check') - let update = null - - try { - const options = {} - if (pkg.version.indexOf('alpha') !== -1) { - options.distTag = 'alpha' - } - update = await checkForUpdate(pkg, options) - } catch (err) { - // console.error(`检查更新失败: ${err}`) - } - - if (update) { - if (pkg.version.split('.')[0] !== update.latest.split('.')[0]) { - console.log(`发现 uni-app cli 新版本 ${update.latest}`) - console.log(`1.修改 package.json 中 @dcloudio 相关包版本为 ^${update.latest}`) - console.log('2.删除 package-lock.json 或 yarn.lock') - console.log('3.执行 npm install 或 yarn') - } else { - console.log(`发现 uni-app cli 新版本 ${update.latest}. 请执行 npm update 升级`) - } - } +const fs = require('fs') +const os = require('os') +const path = require('path') + +class Upate { + constructor () { + this._https = null + this._crypto = null + this._interval = this.DEFAULT_INTERVAL + this._platform = process.env.UNI_PLATFORM + this._fileData = {} + this._compilerVersion = '' + this._isAlpha = false + this._uniId = '' + this._appId = '' + } + + get uniId () { + return this._uniId + } + + set uniId (value) { + this._uniId = value + } + + get appId () { + return this._appId + } + + set appId (value) { + this._appId = value + } + + get compilerVersion () { + return this._compilerVersion + } + + set compilerVersion (value) { + this._compilerVersion = value + } + + get isAlpha () { + return this._isAlpha + } + + set isAlpha (value) { + this._isAlpha = value + } + + get versionType () { + return (this.isAlpha ? 'a' : 'r') + } + + get https () { + if (this._https == null) { + this._https = require('https') + } + return this._https + } + + get crypto () { + if (this._crypto == null) { + this._crypto = require('crypto') + } + return this._crypto + } + + getBuildType () { + return (process.env.NODE_ENV === 'production' ? 'build' : 'dev') + } + + async check () { + await this.readFile() + + const fileData = this._fileData + const currentDate = Date.now() + + if (!fileData.lastCheck || (Math.abs(currentDate - fileData.lastCheck) > this._interval)) { + this._fileData.lastCheck = currentDate + this.checkUpdate() + } else { + if (fileData.newVersion && fileData.newVersion !== this.compilerVersion) { + console.log() + console.log(fileData.note) + } + } + + await this.update() + } + + async readFile () { + const filePath = await this.getFilePath() + let fileData = {} + if (fs.existsSync(filePath)) { + fileData = require(filePath) + } else { + fileData.vid = this._buildUUID() + } + + if (!fileData[this._platform]) { + fileData[this._platform] = {} + } + + this._fileData = fileData + } + + async update () { + const bt = this.getBuildType() + const info = this._fileData[this._platform] + const count = parseInt(info[bt] || 0) + info[bt] = (count + 1) + + this.writeFile() + } + + async writeFile (file) { + try { + const filePath = await this.getFilePath() + const content = JSON.stringify(file || this._fileData) + fs.writeFileSync(filePath, content, 'utf8') + } catch (error) { + } + } + + checkUpdate () { + const postData = JSON.stringify({ + id: this.getPostData() + }) + + var responseData = '' + const req = this.https.request({ + hostname: this.HOST, + path: this.PATH, + port: 443, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': postData.length + } + }, (res) => { + res.setEncoding('utf8') + res.on('data', (chunk) => { + responseData += chunk + }) + res.on('end', () => { + this.checkUpdateSuccess(JSON.parse(responseData)) + }) + }) + req.write(postData) + req.end() + } + + getPostData () { + var data = JSON.parse(JSON.stringify(this._fileData)) + data.device = this._getMD5(this._getMac()) + data.appid = this.uniId + data.vtype = this.versionType + data.vcode = this.compilerVersion + + delete data.lastCheck + + if (this.appId) { + data[this._platform].appid = this.appId + } + if (data.appid) { + delete data.vid + } else { + delete data.appid + } + + return JSON.stringify(data) + } + + checkUpdateSuccess (data) { + if (data.code !== 0) { + return + } + + var fileData = { + vid: this._fileData.vid, + lastCheck: this._fileData.lastCheck + } + + if (data.isUpdate === true) { + fileData.newVersion = data.newVersion + fileData.note = data.note + } + + this.writeFile(fileData) + } + + async getFilePath () { + const rootDir = os.tmpdir() + const fileName = this._getMD5(process.env.UNI_INPUT_DIR) + return path.join(rootDir, `${this.UPDATE_FILE_NAME}_${fileName}.json`) + } + + _getMac () { + let mac + const network = os.networkInterfaces() + for (const key in network) { + const array = network[key] + for (let i = 0; i < array.length; i++) { + const item = array[i] + if (!item.family || (item.mac && item.mac === '00:00:00:00:00:00')) { + continue + } + if (item.family === 'IPv4' || item.family === 'IPv6') { + mac = item.mac + break + } + } + } + return mac + } + + _getMD5 (str) { + return this.crypto.createHash('md5').update(str).digest('hex') + } + + _buildUUID () { + var result = '' + for (let i = 0; i < 4; i++) { + result += (65536 * (1 + Math.random()) | 0).toString(16).substring(1) + } + return 'UNI_' + result.toUpperCase() + } +} +Object.assign(Upate.prototype, { + HOST: 'uniapp.dcloud.net.cn', + PATH: '/update/cli', + UPDATE_FILE_NAME: 'uni_app_cli_update', + DEFAULT_TIME: 2000, + DEFAULT_INTERVAL: 1000 * 60 * 60 * 24 +}) + +module.exports = async function checkUpdate () { + const { + isInHBuilderX, + getManifestJson + } = require('@dcloudio/uni-cli-shared') + + if (isInHBuilderX) { // 仅 cli 提供检测更新 + return + } + + const plp = require('@dcloudio/webpack-uni-pages-loader/package.json') + const ppj = require(path.join(process.env.UNI_CLI_CONTEXT, 'package.json')) + const manifest = getManifestJson() + + try { + const update = new Upate() + update.compilerVersion = plp['uni-app'].compilerVersion + update.isAlpha = ppj.devDependencies['@dcloudio/vue-cli-plugin-uni'].includes('alpha') + update.uniId = manifest.appid + const appIdKey = process.env.UNI_PLATFORM.includes('quickapp') ? 'package' : 'appid' + update.appId = manifest[process.env.UNI_PLATFORM] ? (manifest[process.env.UNI_PLATFORM][appIdKey] || '') : '' + update.check() + } catch (e) { + } }