// import { app } from 'electron' import axios from 'axios' import fs from 'fs' import path from 'path' import { TypeAnswerItem } from '../types/typesMsg' const { execSync } = require('child_process') import hookRequest from '../api/hookRequest' import envConfig from '../config/envConfig' export const delay = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms)) // 通用重试函数 async function withRetry( fn: () => Promise, fnName = '', retries = 1, delay = 5000 ): Promise { for (let i = 0; i <= retries; i++) { try { return await fn() } catch (error) { if (i === retries) throw error console.log(`${fnName} 第${i + 1}次尝试失败,${delay}ms后进行重试:`) await new Promise((resolve) => setTimeout(resolve, delay)) } } throw new Error('重试失败') } // 使用 async function 定义异步函数 export async function downloadImage(url, filename): Promise { try { const res = await axios({ method: 'GET', url: url, responseType: 'stream' }) const tempImgPath = await getTempImgPath() // 使用path.join来拼接文件夹路径 const filePath = path.join(tempImgPath, filename) // 使用path.join来拼接文件路径 console.log('downloadImage-filePath', filePath) // 检查文件是否已经存在 if (fs.existsSync(filePath)) { // 将 Promise 包裹在新的函数体中 return new Promise((resolve) => { resolve(filePath) }) } // 将文件内容写入到文件中 const writer = fs.createWriteStream(filePath) return new Promise((resolve, reject) => { let finished = false const cleanup = (): void => { res.data.off('error', onError) writer.off('error', onError) writer.off('finish', onFinish) } const onError = (err): void => { if (!finished) { finished = true cleanup() reject(err) } } const onFinish = (): void => { if (!finished) { finished = true cleanup() resolve(filePath) } } res.data.pipe(writer) // 读端错误 res.data.on('error', onError) // 写端错误 writer.on('error', onError) writer.on('finish', onFinish) setTimeout(() => { if (!finished) { finished = true cleanup() reject(new Error('downloadImage timeout')) } }, 15000) }) } catch (error) { console.log('Error downloading the image:', error) throw error // 抛出异常,以便调用者可以处理 } } // 封装一个函数,进行JSON.format字符串,有些字符串被JSON.stringify过可能不止一层,需要递归处理,注意错误处理 export function formatJSONString(jsonString): T | null { try { const formattedJSON = JSON.parse(jsonString, (_key, value) => { if (typeof value === 'string') { try { return JSON.parse(value) } catch (error) { return value } } return value }) console.log('formattedJSON', formattedJSON) return formattedJSON } catch (error) { console.log('Error formatting JSON string:', error) return null } } // @ts-ignore: allow-with-description export function getRandomGroupData(answerList): TypeAnswerItem[] { // 将answerList按groupKey进行分组 const groupedAnswers = {} answerList.forEach((answer) => { if (!groupedAnswers[answer.groupKey]) { groupedAnswers[answer.groupKey] = [] } groupedAnswers[answer.groupKey].push(answer) }) // 生成随机数来选择一个组数据 const groupKeys = Object.keys(groupedAnswers) const randomGroupKey = groupKeys[Math.floor(Math.random() * groupKeys.length)] // 获取随机选择的组数据 const randomGroupData = groupedAnswers[randomGroupKey] return randomGroupData } // cdn图片下载,小程序图片 export async function cdnDownloadImg(_msgData): Promise { try { let save_path = '' const tempImgPath = await getTempImgPath() // 使用path.join来拼接文件夹路径 if (_msgData.thumbfileid && _msgData.thumbaeskey) { save_path = path.join(tempImgPath, _msgData.thumbaeskey + '.png') // 使用path.join来拼接文件路径 const data = { cdn_key: _msgData.thumbfileid, aes_key: _msgData.thumbaeskey, size: Number(_msgData.size || 0), img_type: 2, save_path: save_path } await hookRequest.fetchCdnDownloadImg(data) await delay(2000) } else { console.log('cdnDownloadImg: 缺少必要参数') } // 判断save_path是否cdn下载成功(本地是否有该文件) if (!save_path || !fs.existsSync(save_path)) { const root_path = await getRootPath() console.log('文件不存在:', tempImgPath, save_path) const folderPath = path.join(root_path, 'resources') // 使用path.join来拼接文件夹路径 save_path = path.join(folderPath, 'baseCover2.png') } return save_path || '' } catch (error) { console.log('cdnDownloadImg', error) return '' } } // cdn图片下载, oss图片 export async function cdnDownloadImg2(url): Promise { return withRetry(() => _cdnDownloadImg2Internal(url), 'cdnDownloadImg2') } async function _cdnDownloadImg2Internal(url): Promise { // envConfig.urlENV.OSS_BASE // 判断url是否需要osshost,还是一个完整的路径 const _url = url.startsWith('http://') || url.startsWith('https://') ? url : envConfig.urlENV.OSS_BASE + url const res = await axios({ method: 'GET', url: _url, responseType: 'stream' }) const fileName = url.split('/').pop() const tempImgPath = await getTempImgPath() // 使用path.join来拼接文件夹路径 const filePath = path.join(tempImgPath, fileName) const writer = fs.createWriteStream(filePath) // 创建文件写入流 return new Promise((resolve, reject) => { let finished = false const cleanup = (): void => { res.data.off('error', onError) writer.off('error', onError) writer.off('finish', onFinish) } const onError = (err): void => { console.log('cdnDownloadImg2-error:', JSON.stringify(err)) if (!finished) { finished = true cleanup() reject(err) } } const onFinish = (): void => { if (!finished) { finished = true cleanup() resolve(filePath) } } res.data.pipe(writer) // 读端错误 res.data.on('error', onError) // 写端错误 writer.on('error', onError) writer.on('finish', onFinish) setTimeout(() => { if (!finished) { finished = true cleanup() reject(new Error('cdnDownloadImg2 timeout')) } }, 15000) }) } // cdn图片下载,消息图片(个微) export async function cdnDownloadImg3(imgData): Promise { try { let save_path = '' const tempImgPath = await getTempImgPath() // 使用path.join来拼接文件夹路径 if (imgData.auth_key && imgData.aes_key) { save_path = path.join(tempImgPath, imgData.aes_key + '.png') // 使用path.join来拼接文件路径 const data = { url: imgData.url, auth_key: imgData.auth_key, aes_key: imgData.aes_key, size: Number(imgData.size || 0), save_path: save_path } await hookRequest.fetchCdnDownloadWxImg(data) await delay(2000) } else { console.log('cdnDownloadImg3: 缺少必要参数') } // 判断save_path是否cdn下载成功(本地是否有该文件) if (!save_path || !fs.existsSync(save_path)) { const root_path = await getRootPath() console.log('文件不存在:', tempImgPath, save_path) const folderPath = path.join(root_path, 'resources') // 使用path.join来拼接文件夹路径 save_path = path.join(folderPath, 'baseCover2.png') } return save_path || '' } catch (error) { console.log('cdnDownloadImg', error) return '' } } // 获取项目根目录 export async function getRootPath(): Promise { let root_path = '' if (envConfig.env == 'production') { try { // __dirname: __dirname 获取当前文件所在目录的绝对路径 const asarPath = path.join(__dirname, '..', '..') root_path = path.join(__dirname, '..', '..', '..', 'unpacked') if (!fs.existsSync(root_path)) { // asar.extractAll(asarPath, root_path) await execSync(`asar extract ${asarPath} ${root_path}`) console.log('--解压成功--execSync') } } catch (err) { console.log('err', err) } } else { // path.resolve 将相对路径解析为绝对路径 root_path = path.resolve('.') } return root_path } export async function getTempImgPath(): Promise { const root_path = await getRootPath() const localFolderPath = path.join(root_path, 'tempImg') // 使用path.join来拼接文件夹路径 // 确保文件夹存在,如果不存在则创建 if (!fs.existsSync(localFolderPath)) { fs.mkdirSync(localFolderPath, { recursive: true }) // 使用fs.mkdirSync来创建文件夹,{ recursive: true }表示如果父文件夹不存在也会被创建 } return localFolderPath }