import {boundedCall, fileAccess} from './sharing-runtime' const VERSION = 'v5' const MAX_AGE = 24 * 60 * 60 * 1000 const INDEX = 'fulian-sharing-cache-' + VERSION function digest(text) { let value = 2166136261 for (let i=0;i>> 0).toString(16) } function identity(id,kind) { if (!Number.isSafeInteger(Number(id)) || Number(id)<=0 || !['invite','personal'].includes(kind)) throw new Error('分享信息无效') return `${Number(id)}-${kind}` } export function sharingFingerprint(profile,kind) { const values = kind === 'invite' ? [profile.id,profile.nickname] : [profile.id,profile.nickname,profile.photo,profile.photos,profile.details,profile.introduction,profile.idealMate] return digest(JSON.stringify([VERSION,kind,values])) } function readIndex() { try { return wx.getStorageSync(INDEX) || {} } catch (_) { return {} } } function ownFile(value) { return typeof value === 'string' && value.startsWith(wx.env.USER_DATA_PATH+'/fulian-share-'+VERSION+'-') && !value.includes('..') } function removeFiles(record) { if (!record) return for(const key of ['poster','cover','qrcode']) if(ownFile(record[key])) wx.getFileSystemManager().unlink({filePath:record[key],fail(){}}) } export async function readSharingCache(id,kind,profile) { if (!wx.getStorageSync('token')) return null const index=readIndex(),key=identity(id,kind),record=index[key] if (!record || record.version!==VERSION || record.auth!==digest(String(wx.getStorageSync('token'))) || record.savedAt>Date.now() || Date.now()-record.savedAt>MAX_AGE) return null if (profile && record.fingerprint!==sharingFingerprint(profile,kind)) return null if (![record.poster,record.cover,record.qrcode].every(ownFile)) return null const present=await Promise.all([record.poster,record.cover,record.qrcode].map(fileAccess)) return present.every(Boolean) ? record : null } export async function writeSharingCache(profile,kind,assets) { const key=identity(profile.id,kind) const prefix=`${wx.env.USER_DATA_PATH}/fulian-share-${VERSION}-${key}-${Date.now()}-${Math.random().toString(16).slice(2,8)}` const paths={poster:prefix+'-poster.png',cover:prefix+'-cover.png',qrcode:prefix+'-qr.png'} try { for (const name of ['poster','cover','qrcode']) { await boundedCall((resolve,reject)=>wx.getFileSystemManager().copyFile({srcPath:assets[name],destPath:paths[name],success:resolve,fail:reject}), '图片缓存失败', 3000) } const index=readIndex(),previous=index[key] const record={...paths,selectedPhoto:profile.photo||'',version:VERSION,fingerprint:sharingFingerprint(profile,kind),auth:digest(String(wx.getStorageSync('token')||'')),savedAt:Date.now()} index[key]=record const expired=Object.keys(index).filter(k=>k!==key).sort((a,b)=>(index[b].savedAt||0)-(index[a].savedAt||0)).slice(3) const discarded=expired.map(k=>index[k]);expired.forEach(k=>delete index[k]) wx.setStorageSync(INDEX,index) removeFiles(previous);discarded.forEach(removeFiles) return record } catch(error) { removeFiles(paths); throw error } }