forked from cybrespace/pinafore
208 lines
6.0 KiB
JavaScript
208 lines
6.0 KiB
JavaScript
import {
|
|
toReversePaddedBigInt
|
|
} from './utils'
|
|
import {
|
|
getDatabase,
|
|
dbPromise,
|
|
deleteDatabase,
|
|
} from './databaseLifecycle'
|
|
|
|
import {
|
|
META_STORE,
|
|
STATUS_TIMELINES_STORE,
|
|
STATUSES_STORE,
|
|
ACCOUNTS_STORE,
|
|
RELATIONSHIPS_STORE,
|
|
NOTIFICATIONS_STORE,
|
|
NOTIFICATION_TIMELINES_STORE
|
|
} from './constants'
|
|
|
|
import {
|
|
statusesCache,
|
|
relationshipsCache,
|
|
accountsCache,
|
|
metaCache,
|
|
notificationsCache,
|
|
clearCache,
|
|
getInCache,
|
|
hasInCache,
|
|
setInCache
|
|
} from './cache'
|
|
|
|
//
|
|
// helpers
|
|
//
|
|
|
|
async function getGenericEntityWithId(store, cache, instanceName, id) {
|
|
if (hasInCache(cache, instanceName, id)) {
|
|
return getInCache(cache, instanceName, id)
|
|
}
|
|
const db = await getDatabase(instanceName)
|
|
let result = await dbPromise(db, store, 'readonly', (store, callback) => {
|
|
store.get(id).onsuccess = (e) => callback(e.target.result)
|
|
})
|
|
setInCache(cache, instanceName, id, result)
|
|
return result
|
|
}
|
|
|
|
async function setGenericEntityWithId(store, cache, instanceName, entity) {
|
|
setInCache(cache, instanceName, entity.id, entity)
|
|
const db = await getDatabase(instanceName)
|
|
return await dbPromise(db, store, 'readwrite', (store) => {
|
|
store.put(entity)
|
|
})
|
|
}
|
|
|
|
//
|
|
// timelines/statuses/notifications
|
|
//
|
|
|
|
function getTimelineVariables(timeline) {
|
|
if (timeline === 'notifications') {
|
|
return {
|
|
stores: [NOTIFICATION_TIMELINES_STORE, NOTIFICATIONS_STORE, ACCOUNTS_STORE],
|
|
remoteId: 'notificationId',
|
|
itemsCache: notificationsCache
|
|
}
|
|
}
|
|
return {
|
|
stores: [STATUS_TIMELINES_STORE, STATUSES_STORE, ACCOUNTS_STORE],
|
|
remoteId: 'statusId',
|
|
itemsCache: statusesCache
|
|
}
|
|
}
|
|
|
|
export async function getTimeline(instanceName, timeline, maxId = null, limit = 20) {
|
|
let { stores, remoteId } = getTimelineVariables(timeline)
|
|
const db = await getDatabase(instanceName)
|
|
return await dbPromise(db, stores, 'readonly', (stores, callback) => {
|
|
let [ timelineStore, itemsStore ] = stores
|
|
|
|
let negBigInt = maxId && toReversePaddedBigInt(maxId)
|
|
let start = negBigInt ? (timeline + '\u0000' + negBigInt) : (timeline + '\u0000')
|
|
let end = timeline + '\u0000\uffff'
|
|
let query = IDBKeyRange.bound(start, end, false, false)
|
|
|
|
timelineStore.getAll(query, limit).onsuccess = e => {
|
|
let timelineResults = e.target.result
|
|
let res = new Array(timelineResults.length)
|
|
timelineResults.forEach((timelineResult, i) => {
|
|
itemsStore.get(timelineResult[remoteId]).onsuccess = e => {
|
|
res[i] = e.target.result
|
|
}
|
|
})
|
|
callback(res)
|
|
}
|
|
})
|
|
}
|
|
|
|
export async function insertTimelineItems(instanceName, timeline, timelineItems) {
|
|
let { stores, remoteId, itemsCache } = getTimelineVariables(timeline)
|
|
for (let timelineItem of timelineItems) {
|
|
setInCache(itemsCache, instanceName, timelineItem.id, timelineItem)
|
|
setInCache(accountsCache, instanceName, timelineItem.account.id, timelineItem.account)
|
|
if (timelineItem.reblog) {
|
|
setInCache(accountsCache, instanceName, timelineItem.reblog.account.id, timelineItem.reblog.account)
|
|
}
|
|
}
|
|
const db = await getDatabase(instanceName)
|
|
await dbPromise(db, stores, 'readwrite', (stores) => {
|
|
let [ timelineStore, itemsStore, accountsStore ] = stores
|
|
for (let item of timelineItems) {
|
|
itemsStore.put(item)
|
|
// reverse chronological order, prefixed by timeline
|
|
timelineStore.put({
|
|
id: (timeline + '\u0000' + toReversePaddedBigInt(item.id)),
|
|
[remoteId]: item.id
|
|
})
|
|
accountsStore.put(item.account)
|
|
if (item.reblog) {
|
|
accountsStore.put(item.reblog.account)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
export async function getStatus(instanceName, statusId) {
|
|
return await getGenericEntityWithId(STATUSES_STORE, statusesCache, instanceName, statusId)
|
|
}
|
|
|
|
export async function getNotification(instanceName, notificationId) {
|
|
return await getGenericEntityWithId(NOTIFICATIONS_STORE, notificationsCache, instanceName, notificationId)
|
|
}
|
|
|
|
//
|
|
// meta
|
|
//
|
|
|
|
async function getMetaProperty(instanceName, key) {
|
|
if (hasInCache(metaCache, instanceName, key)) {
|
|
return getInCache(metaCache, instanceName, key)
|
|
}
|
|
const db = await getDatabase(instanceName)
|
|
let result = await dbPromise(db, META_STORE, 'readonly', (store, callback) => {
|
|
store.get(key).onsuccess = (e) => {
|
|
callback(e.target.result && e.target.result.value)
|
|
}
|
|
})
|
|
setInCache(metaCache, instanceName, key, result)
|
|
return result
|
|
}
|
|
|
|
async function setMetaProperty(instanceName, key, value) {
|
|
setInCache(metaCache, instanceName, key, value)
|
|
const db = await getDatabase(instanceName)
|
|
return await dbPromise(db, META_STORE, 'readwrite', (store) => {
|
|
store.put({
|
|
key: key,
|
|
value: value
|
|
})
|
|
})
|
|
}
|
|
|
|
export async function getInstanceVerifyCredentials(instanceName) {
|
|
return await getMetaProperty(instanceName, 'verifyCredentials')
|
|
}
|
|
|
|
export async function setInstanceVerifyCredentials(instanceName, value) {
|
|
return await setMetaProperty(instanceName, 'verifyCredentials', value)
|
|
}
|
|
|
|
export async function getInstanceInfo(instanceName) {
|
|
return await getMetaProperty(instanceName, 'instance')
|
|
}
|
|
|
|
export async function setInstanceInfo(instanceName, value) {
|
|
return await setMetaProperty(instanceName, 'instance', value)
|
|
}
|
|
|
|
//
|
|
// accounts/relationships
|
|
//
|
|
|
|
export async function getAccount(instanceName, accountId) {
|
|
return await getGenericEntityWithId(ACCOUNTS_STORE, accountsCache, instanceName, accountId)
|
|
}
|
|
|
|
export async function setAccount(instanceName, account) {
|
|
return await setGenericEntityWithId(ACCOUNTS_STORE, accountsCache, instanceName, account)
|
|
}
|
|
|
|
export async function getRelationship(instanceName, accountId) {
|
|
return await getGenericEntityWithId(RELATIONSHIPS_STORE, relationshipsCache, instanceName, accountId)
|
|
}
|
|
|
|
export async function setRelationship(instanceName, relationship) {
|
|
return await setGenericEntityWithId(RELATIONSHIPS_STORE, relationshipsCache, instanceName, relationship)
|
|
}
|
|
|
|
//
|
|
// lifecycle
|
|
//
|
|
|
|
export async function clearDatabaseForInstance(instanceName) {
|
|
clearCache(statusesCache, instanceName)
|
|
clearCache(accountsCache, instanceName)
|
|
clearCache(metaCache, instanceName)
|
|
await deleteDatabase(instanceName)
|
|
} |