updateInstall.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. 'use strict'
  2. /**
  3. * 读取注册表获取纵横软件
  4. *
  5. * @author EllisRan.
  6. * @date 2018/6/20
  7. * @version
  8. */
  9. import db from '../../database'
  10. const fs = require('fs')
  11. const fse = require('fs-extra')
  12. const path = require('path')
  13. const ffi = require('ffi')
  14. const electron = require('electron')
  15. const ipcMain = electron.ipcMain
  16. const regeditPath64 = 'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall'
  17. const regeditPath32 = 'HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall'
  18. const regeditPath = isOSWin64() ? regeditPath64 : regeditPath32
  19. const regedit = require('regedit')
  20. let globalNUM = 0
  21. let globalSoftware = []
  22. let globalExe = []
  23. const updateInstall = function (win) {
  24. ipcMain.on('updateInstall', function () {
  25. regedit.list(regeditPath).on('data', async function (result) {
  26. try {
  27. // let flag = false
  28. // 每次自动获取更新软件内容先让数据库isshow都为false,然后再执行getExeDataList方法里把isshow包含的变true,
  29. // 最后再检测把还是false的软件进行判断文件夹和软件是否还在,有则保留,否则删除,完成已删除软件功能(手动添加的exe信息除外)
  30. await productAndExeDataIsshow()
  31. let softwarelist = result.data.keys
  32. let promiseArr = []
  33. let promiseArr2 = []
  34. for (let i in softwarelist) {
  35. if (softwarelist[i].indexOf('SmartCost_') !== -1) {
  36. promiseArr2.push(getExeDataList(softwarelist[i]))
  37. }
  38. }
  39. await sleep(2000)
  40. await Promise.all(promiseArr2)
  41. .then(async function (result) {
  42. await sleep(5000)
  43. if (globalSoftware !== []) {
  44. console.log(globalSoftware)
  45. for (let i in globalSoftware) {
  46. (async function () {
  47. globalSoftware[i].exeName = globalExe[i]
  48. await promiseArr.push(insertData(globalSoftware[i]))
  49. })(i)
  50. }
  51. }
  52. let one = globalSoftware.length
  53. console.log(one)
  54. await sleep(2000)
  55. let two = globalSoftware.length
  56. console.log(two)
  57. if (one !== two) {
  58. console.log(globalSoftware)
  59. }
  60. await Promise.all(promiseArr)
  61. .then(async function (result) {
  62. // console.log(globalSoftware)
  63. let delnum = await delProductAndExeDataAsync()
  64. await db.read().set('sc_hadInstall.first', false).write()
  65. let exeInfo = await db.read().get('sc_exeData').last().value()
  66. let gourl = exeInfo === '{}' || exeInfo.pid === undefined ? 1 : exeInfo.pid
  67. await db.read().set('sc_hadInstall.url', '/softwarestartup/' + gourl).write()
  68. if (promiseArr !== undefined && promiseArr.length !== 0) {
  69. win.webContents.send('successUpdate', {id: gourl, num: globalNUM, delnum: delnum})
  70. // console.log(globalSoftware)
  71. } else {
  72. win.webContents.send('failedUpdate', {id: '1', error: 200})
  73. }
  74. globalNUM = 0
  75. globalSoftware = []
  76. globalExe = []
  77. })
  78. .catch(function (err) {
  79. win.webContents.send('failedUpdate', {id: '1', error: err})
  80. console.log(err)
  81. globalNUM = 0
  82. globalSoftware = []
  83. globalExe = []
  84. })
  85. })
  86. .catch(function (err) {
  87. console.log(err)
  88. })
  89. } catch (error) {
  90. console.log(error)
  91. }
  92. })
  93. })
  94. /**
  95. * make all data isshow: true=>false
  96. */
  97. async function productAndExeDataIsshow () {
  98. await db.read().get('sc_productData').updateWhere({ isshow: true }, { isshow: false }).write()
  99. await db.read().get('sc_exeData').updateWhere({ auto: true, isshow: true }, { isshow: false }).write()
  100. }
  101. /**
  102. * delete data by isshow=false
  103. * @return {int}
  104. */
  105. async function delProductAndExeDataAsync () {
  106. // 这里必须静止1s等Promise.all里的getExeDataList方法所有获取执行完才可以获取正确的num,原因不明......
  107. await sleep(1000)
  108. let num = await db.read().get('sc_exeData').filter({ auto: true, isshow: false }).size().value()
  109. // 先让默认的“未分类” isshow:true,免于被删除,当不存在手动添加的软件或自动检测软件的时候,暂时隐藏“未分类”,
  110. // 当启动器不存在任何软件时,默认显示“未分类”
  111. // let manualnum = db.read().get('sc_exeData').filter({ auto: false }).size().value()
  112. // let flag = db.read().get('sc_productData').getById('1').value().isshow
  113. // if (!flag) {
  114. // db.read().get('sc_productData').updateById('1', { isshow: true }).write()
  115. // }
  116. // db.read().get('sc_productData').removeWhere({ isshow: false }).write()
  117. // let allnum = db.read().get('sc_exeData').size().value()
  118. // if (manualnum === 0 && !flag && allnum !== 0) {
  119. // db.read().get('sc_productData').updateById('1', { isshow: false }).write()
  120. // }
  121. // 对还是isshow:false的软件进行文件夹文件查询,如果还在则保留,不存在则删除
  122. if (num !== 0) {
  123. let deleteExeData = await db.read().get('sc_exeData').filter({ auto: true, isshow: false }).value()
  124. for (let exe in deleteExeData) {
  125. let exePath = path.join(exe.path, exe.exeName)
  126. let existExe = await db.read().get('sc_exeData').find({ path: exe.path, exeName: exe.exeName, isshow: true }).value()
  127. if (fse.pathExistsSync(exePath) && !existExe) {
  128. db.read().get('sc_exeData').updateById(exe.id, { isshow: true }).write()
  129. }
  130. }
  131. }
  132. db.read().get('sc_exeData').removeWhere({ auto: true, isshow: false }).write()
  133. return num
  134. }
  135. const sleep = (timeout = 2000) => new Promise(resolve => {
  136. setTimeout(resolve, timeout)
  137. })
  138. // 取文件名不带后缀
  139. function GetFileNameNoExt (filepath) {
  140. if (filepath !== '') {
  141. let names = filepath.split('\\')
  142. let pos = names[names.length - 1].lastIndexOf('.')
  143. return names[names.length - 1].substring(0, pos)
  144. }
  145. }
  146. // 产生随机数函数
  147. function RndNum (n) {
  148. let rnd = ''
  149. for (let i = 0; i < n; i++) {
  150. rnd += Math.floor(Math.random() * 10)
  151. }
  152. return rnd
  153. }
  154. /**
  155. * 判断文件名是否包含纵横软件exe的部分名称
  156. * @param item
  157. * @return {boolean}
  158. */
  159. function existSoftwareName (item) {
  160. // 纵横软件exe所带包含的文件名
  161. const smartcostSoftwareHeader = ['SmartCost', 'Measure', 'DrawingBuilder', 'BillsEditor']
  162. let flag = false
  163. for (let i = 0; i < smartcostSoftwareHeader.length; i++) {
  164. if (item.indexOf(smartcostSoftwareHeader[i]) !== -1) {
  165. flag = true
  166. break
  167. }
  168. }
  169. return flag
  170. }
  171. function inArray (val, arr) {
  172. for (let i in arr) {
  173. if (arr[i] === val) {
  174. return true
  175. }
  176. }
  177. return false
  178. }
  179. /**
  180. * 数据入库
  181. *
  182. */
  183. function insertData (exeData) {
  184. return new Promise(resolve => {
  185. let pathstr = path.join('data/fileInfo.dll')
  186. let libm = ffi.Library(pathstr, {
  187. 'GetFileInfo': ['string', ['string']]
  188. })
  189. let fileinfo = JSON.parse(libm.GetFileInfo(path.join(exeData.path, exeData.exeName)))
  190. exeData.fileVersion = fileinfo.FileVersion
  191. exeData.productName = fileinfo.ProductName
  192. exeData.productVersion = fileinfo.ProductVersion
  193. exeData.fileDescription = fileinfo.FileDescription
  194. let dbExeData = db.read().get('sc_exeData').find({ exeName: exeData.exeName, path: exeData.path, fileVersion: exeData.fileVersion }).value()
  195. if (dbExeData === undefined || dbExeData === null) {
  196. // 先判断是否存在该产品数据库(同时关联到sc_sofeware.json文件数据),再加入安装包数据库
  197. // 新方法,先关联注册表名查找数据,然后再关联产品数据库生成
  198. let softwarejson = path.join('data/sc_software.json')
  199. let downlist = fse.readJsonSync(softwarejson).sc_down
  200. let downinfo = downlist.find(function (item) {
  201. return inArray(exeData.regeditName, item.regedits)
  202. })
  203. // let ptitle = downinfo !== undefined ? downinfo.product_title : ''
  204. if (downinfo !== undefined) {
  205. exeData.simpleName = downinfo.product_title
  206. exeData.versionName = downinfo.title
  207. let productInfo = db.read().get('sc_productData').find({ product_id: downinfo.product_id }).value()
  208. if (productInfo === undefined || productInfo === null) {
  209. let scproductlist = fse.readJsonSync(softwarejson).sc_product
  210. let scproductInfo = scproductlist.find(function (item) {
  211. return item.product_id === downinfo.product_id
  212. })
  213. let productInfo2 = scproductInfo
  214. productInfo2.addtime = Date.parse(new Date()) / 1000
  215. productInfo2.isshow = true
  216. let insertproudct = db.read().get('sc_productData').insert(productInfo2).write()
  217. exeData.pid = insertproudct.id
  218. productInfo = insertproudct
  219. } else {
  220. exeData.pid = productInfo.id
  221. db.read().get('sc_productData').updateById(productInfo.id, { isshow: true }).write()
  222. }
  223. // 获取json文件中的锁号,更新到exe当中
  224. for (let j in downlist) {
  225. if (productInfo.product_id === downlist[j].product_id && exeData.versionName === downlist[j].title) {
  226. exeData.keyNumber = downlist[j].key_number
  227. exeData.keytype = downlist[j].keytype
  228. exeData.product_id = downlist[j].product_id
  229. exeData.down_id = downlist[j].down_id
  230. exeData.product_version = fileinfo.FileVersion
  231. exeData.show_tip = fileinfo.FileVesrion !== downlist[j].version && exeData.exeName !== 'BillsEditor.exe'
  232. exeData.show_updateVersion = downlist[j].version
  233. break
  234. }
  235. }
  236. } else {
  237. exeData.pid = '1'
  238. exeData.simpleName = ''
  239. exeData.versionName = ''
  240. exeData.keyNumber = ''
  241. exeData.keytype = ''
  242. exeData.product_id = ''
  243. exeData.down_id = ''
  244. exeData.product_version = ''
  245. exeData.show_tip = false
  246. exeData.show_updateVersion = ''
  247. db.read().get('sc_productData').updateById('1', { isshow: true }).write()
  248. }
  249. exeData.addtime = Date.parse(new Date()) / 1000
  250. exeData.isshow = true
  251. exeData.auto = true
  252. exeData.id = GetFileNameNoExt(exeData.exeName) + '-' + RndNum(10)
  253. ++globalNUM
  254. db.read().get('sc_exeData').insert(exeData).write()
  255. } else {
  256. db.read().get('sc_productData').updateById(dbExeData.pid, { isshow: true }).write()
  257. db.read().get('sc_exeData').updateById(dbExeData.id, { isshow: true }).write()
  258. }
  259. resolve(exeData)
  260. })
  261. }
  262. /**
  263. * node 循环和异步解决方案
  264. * @param Info
  265. */
  266. function getExeDataList (Info) {
  267. return new Promise(resolve => {
  268. // setTimeout(function () {
  269. regedit.list(regeditPath + '\\' + Info).on('data', async function (result) {
  270. let values = result.data.values
  271. let regeditData = {
  272. path: values['Inno Setup: App Path'].value,
  273. name: values['DisplayName'].value,
  274. regeditName: Info,
  275. fileName: values['Inno Setup: Icon Group'].value
  276. }
  277. let dirname = await fs.readdirSync(regeditData.path)
  278. for (let i in dirname) {
  279. if (path.extname(dirname[i]) === '.exe' && existSoftwareName(dirname[i])) {
  280. let exeData = regeditData
  281. // exeData.exeName = diraname[i]
  282. // 这里必须分离2个数组记录值并在外面合并,push才不会出错,否则会重复exeName名,未知bug,坑
  283. globalSoftware.push(exeData)
  284. globalExe.push(dirname[i])
  285. }
  286. }
  287. })
  288. resolve('ok')
  289. })
  290. }
  291. }
  292. /**
  293. * 判断系统位数
  294. * @return {boolean}
  295. */
  296. function isOSWin64 () {
  297. return process.arch === 'x64' || process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432')
  298. }
  299. export default updateInstall