fix(observers): refactor instance observers, minor optimizations (#730)

try to defer more work, split everything up into more functional code for easier reading
This commit is contained in:
Nolan Lawson 2018-12-05 00:21:54 -08:00 committed by GitHub
parent ef32bfb278
commit f7164dd4c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 97 additions and 72 deletions

View File

@ -3,16 +3,17 @@ import { getLists } from '../_api/lists'
import { cacheFirstUpdateAfter } from '../_utils/sync' import { cacheFirstUpdateAfter } from '../_utils/sync'
import { database } from '../_database/database' import { database } from '../_database/database'
export async function updateLists () { export async function updateListsForInstance (instanceName) {
let { currentInstance, accessToken } = store.get() let { loggedInInstances } = store.get()
let accessToken = loggedInInstances[instanceName].access_token
await cacheFirstUpdateAfter( await cacheFirstUpdateAfter(
() => getLists(currentInstance, accessToken), () => getLists(instanceName, accessToken),
() => database.getLists(currentInstance), () => database.getLists(instanceName),
lists => database.setLists(currentInstance, lists), lists => database.setLists(instanceName, lists),
lists => { lists => {
let { instanceLists } = store.get() let { instanceLists } = store.get()
instanceLists[currentInstance] = lists instanceLists[instanceName] = lists
store.set({ instanceLists: instanceLists }) store.set({ instanceLists: instanceLists })
} }
) )

View File

@ -92,13 +92,13 @@
import HiddenFromSSR from '../../_components/HiddenFromSSR' import HiddenFromSSR from '../../_components/HiddenFromSSR'
import PageList from '../../_components/community/PageList.html' import PageList from '../../_components/community/PageList.html'
import PageListItem from '../../_components/community/PageListItem.html' import PageListItem from '../../_components/community/PageListItem.html'
import { updateLists } from '../../_actions/lists' import { updateListsForInstance } from '../../_actions/lists'
export default { export default {
async oncreate () { async oncreate () {
let { currentInstance } = this.store.get() let { currentInstance } = this.store.get()
if (currentInstance) { if (currentInstance) {
await updateLists() await updateListsForInstance(currentInstance)
} }
}, },
store: () => store, store: () => store,

View File

@ -1,16 +1,98 @@
import { updateInstanceInfo, updateVerifyCredentialsForInstance } from '../../_actions/instances' import { updateInstanceInfo, updateVerifyCredentialsForInstance } from '../../_actions/instances'
import { updateLists } from '../../_actions/lists' import { updateListsForInstance } from '../../_actions/lists'
import { createStream } from '../../_actions/streaming' import { createStream } from '../../_actions/streaming'
import { updatePushSubscriptionForInstance } from '../../_actions/pushSubscription' import { updatePushSubscriptionForInstance } from '../../_actions/pushSubscription'
import { updateCustomEmojiForInstance } from '../../_actions/emoji' import { updateCustomEmojiForInstance } from '../../_actions/emoji'
import { addStatusesOrNotifications } from '../../_actions/addStatusOrNotification' import { addStatusesOrNotifications } from '../../_actions/addStatusOrNotification'
import { getTimeline } from '../../_api/timelines' import { getTimeline } from '../../_api/timelines'
import { TIMELINE_BATCH_SIZE } from '../../_static/timelines' import { TIMELINE_BATCH_SIZE } from '../../_static/timelines'
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask'
import { mark, stop } from '../../_utils/marks'
export function instanceObservers (store) {
// stream to watch for home timeline updates and notifications // stream to watch for home timeline updates and notifications
let currentInstanceStream let currentInstanceStream
async function refreshInstanceDataAndStream (store, instanceName) {
mark(`refreshInstanceDataAndStream-${instanceName}`)
await doRefreshInstanceDataAndStream(store, instanceName)
stop(`refreshInstanceDataAndStream-${instanceName}`)
}
function currentInstanceChanged (store, instanceName) {
return store.get().currentInstance !== instanceName
}
async function doRefreshInstanceDataAndStream (store, instanceName) {
if (currentInstanceChanged(store, instanceName)) {
return
}
await refreshInstanceData(instanceName)
if (currentInstanceChanged(store, instanceName)) {
return
}
let { currentInstanceInfo } = store.get()
if (!currentInstanceInfo) {
return
}
stream(store, instanceName, currentInstanceInfo)
}
async function refreshInstanceData (instanceName) {
// these are all low-priority
scheduleIdleTask(() => updateVerifyCredentialsForInstance(instanceName))
scheduleIdleTask(() => updateCustomEmojiForInstance(instanceName))
scheduleIdleTask(() => updateListsForInstance(instanceName))
scheduleIdleTask(() => updatePushSubscriptionForInstance(instanceName))
// this is the only critical one
await updateInstanceInfo(instanceName)
}
function stream (store, instanceName, currentInstanceInfo) {
let homeTimelineItemIds = store.getForTimeline(instanceName,
'home', 'timelineItemIds')
let firstHomeTimelineItemId = homeTimelineItemIds && homeTimelineItemIds[0]
let notificationItemIds = store.getForTimeline(instanceName,
'notifications', 'timelineItemIds')
let firstNotificationTimelineItemId = notificationItemIds && notificationItemIds[0]
let { accessToken } = store.get()
let streamingApi = currentInstanceInfo.urls.streaming_api
function onOpenStream () {
if (currentInstanceChanged(store, instanceName)) {
return
}
/* no await */ fillGap(instanceName, accessToken, 'home', firstHomeTimelineItemId)
/* no await */ fillGap(instanceName, accessToken, 'notifications', firstNotificationTimelineItemId)
}
currentInstanceStream = createStream(streamingApi, instanceName, accessToken, 'home', onOpenStream)
if (process.env.NODE_ENV !== 'production') {
window.currentInstanceStream = currentInstanceStream
}
}
// fill in the "streaming gap" i.e. fetch the most recent 20 items so that there isn't
// a big gap in the timeline if you haven't looked at it in awhile
async function fillGap (instanceName, accessToken, timelineName, firstTimelineItemId) {
if (!firstTimelineItemId) {
return
}
let newTimelineItems = await getTimeline(instanceName, accessToken,
timelineName, null, firstTimelineItemId, TIMELINE_BATCH_SIZE)
if (newTimelineItems.length) {
addStatusesOrNotifications(instanceName, timelineName, newTimelineItems)
}
}
export function instanceObservers (store) {
store.observe('currentInstance', async (currentInstance) => { store.observe('currentInstance', async (currentInstance) => {
if (!process.browser) { if (!process.browser) {
return return
@ -26,64 +108,6 @@ export function instanceObservers (store) {
return return
} }
/* no await */ updateVerifyCredentialsForInstance(currentInstance) scheduleIdleTask(() => refreshInstanceDataAndStream(store, currentInstance))
/* no await */ updateCustomEmojiForInstance(currentInstance)
/* no await */ updateLists()
/* no await */ updatePushSubscriptionForInstance(currentInstance)
await updateInstanceInfo(currentInstance)
let currentInstanceIsUnchanged = () => {
let { currentInstance: newCurrentInstance } = store.get()
return newCurrentInstance === currentInstance
}
if (!currentInstanceIsUnchanged()) {
return
}
let { currentInstanceInfo } = store.get()
if (!currentInstanceInfo) {
return
}
let homeTimelineItemIds = store.getForTimeline(currentInstance,
'home', 'timelineItemIds')
let firstHomeTimelineItemId = homeTimelineItemIds && homeTimelineItemIds[0]
let notificationItemIds = store.getForTimeline(currentInstance,
'notifications', 'timelineItemIds')
let firstNotificationTimelineItemId = notificationItemIds && notificationItemIds[0]
let onOpenStream = async () => {
if (!currentInstanceIsUnchanged()) {
return
}
// fill in the "streaming gap" i.e. fetch the most recent 20 items so that there isn't
// a big gap in the timeline if you haven't looked at it in awhile
async function fillGap (timelineName, firstTimelineItemId) {
if (!firstTimelineItemId) {
return
}
let newTimelineItems = await getTimeline(currentInstance, accessToken,
timelineName, null, firstTimelineItemId, TIMELINE_BATCH_SIZE)
if (newTimelineItems.length) {
addStatusesOrNotifications(currentInstance, timelineName, newTimelineItems)
}
}
await Promise.all([
fillGap('home', firstHomeTimelineItemId),
fillGap('notifications', firstNotificationTimelineItemId)
])
}
let { accessToken } = store.get()
let streamingApi = currentInstanceInfo.urls.streaming_api
currentInstanceStream = createStream(streamingApi,
currentInstance, accessToken, 'home', onOpenStream)
if (process.env.NODE_ENV !== 'production') {
window.currentInstanceStream = currentInstanceStream
}
}) })
} }