55 lines
3.1 KiB
JavaScript
55 lines
3.1 KiB
JavaScript
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<text.length;i++) { value ^= text.charCodeAt(i); value = Math.imul(value,16777619) }
|
|
return (value >>> 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 }
|
|
}
|