Pinafore-Web-Client-Frontend/src/routes/_actions/createMakeProps.js

91 lines
2.7 KiB
JavaScript
Raw Normal View History

2018-08-30 07:03:29 +02:00
import { database } from '../_database/database'
import { decode as decodeBlurhash, init as initBlurhash } from '../_utils/blurhash'
import { mark, stop } from '../_utils/marks'
import { get } from '../_utils/lodash-lite'
2018-08-30 07:03:29 +02:00
async function getNotification (instanceName, timelineType, timelineValue, itemId) {
return {
timelineType,
timelineValue,
notification: await database.getNotification(instanceName, itemId)
}
}
async function getStatus (instanceName, timelineType, timelineValue, itemId) {
return {
timelineType,
timelineValue,
status: await database.getStatus(instanceName, itemId)
}
}
function tryInitBlurhash () {
try {
initBlurhash()
} catch (err) {
console.error('could not start blurhash worker', err)
}
}
async function decodeAllBlurhashes (statusOrNotification) {
const status = statusOrNotification.status || statusOrNotification.notification.status
const mediaWithBlurhashes = get(status, ['media_attachments'], [])
.concat(get(status, ['reblog', 'media_attachments'], []))
.filter(_ => _.blurhash)
if (mediaWithBlurhashes.length) {
mark(`decodeBlurhash-${status.id}`)
await Promise.all(mediaWithBlurhashes.map(async media => {
try {
media.decodedBlurhash = await decodeBlurhash(media.blurhash)
} catch (err) {
console.warn('Could not decode blurhash, ignoring', err)
}
}))
stop(`decodeBlurhash-${status.id}`)
}
return statusOrNotification
}
2018-08-30 07:03:29 +02:00
export function createMakeProps (instanceName, timelineType, timelineValue) {
let taskCount = 0
let pending = []
tryInitBlurhash() // start the blurhash worker a bit early to save time
2018-08-30 07:03:29 +02:00
// The worker-powered indexeddb promises can resolve in arbitrary order,
// causing the timeline to load in a jerky way. With this function, we
// wait for all promises to resolve before resolving them all in one go.
function awaitAllTasksComplete () {
return new Promise(resolve => {
taskCount--
pending.push(resolve)
if (taskCount === 0) {
pending.forEach(_ => _())
pending = []
}
})
}
async function fetchFromIndexedDB (itemId) {
mark(`fetchFromIndexedDB-${itemId}`)
try {
const res = await (timelineType === 'notifications'
? getNotification(instanceName, timelineType, timelineValue, itemId)
: getStatus(instanceName, timelineType, timelineValue, itemId))
return res
} finally {
stop(`fetchFromIndexedDB-${itemId}`)
}
}
2018-08-30 07:03:29 +02:00
return (itemId) => {
taskCount++
return fetchFromIndexedDB(itemId)
.then(decodeAllBlurhashes)
.then(statusOrNotification => {
return awaitAllTasksComplete().then(() => statusOrNotification)
})
2018-08-30 07:03:29 +02:00
}
}