Use MATH to figure out cursor window

This commit is contained in:
Jonathan Staab 2023-02-24 10:37:05 -06:00
parent 7c9223a37f
commit 4034eb3862
5 changed files with 27 additions and 17 deletions

View File

@ -1,9 +1,5 @@
# Current
- [ ] Fix pagination
# Next
- [ ] Relay detail page, with more information about the relay + tabbed feeds (notes, more?)
- [ ] Add customize icon and route with editable custom view cards using "lists" nip
- nevent1qqspjcqw2hu5gfcpkrjhs0aqvxuzjgtp50l375mcqjfpmk48cg5hevgpr3mhxue69uhkummnw3ez6un9d3shjtnhd3m8xtnnwpskxegpzamhxue69uhkummnw3ezuendwsh8w6t69e3xj7spramhxue69uhkummnw3ez6un9d3shjtnwdahxxefwv93kzer9d4usz9rhwden5te0wfjkccte9ejxzmt4wvhxjmcpr9mhxue69uhkummnw3ezuer9d3hjuum0ve68wctjv5n8hwfg

View File

@ -72,12 +72,11 @@
const scroller = createScroller(
async () => {
await loadMessages(cursor, newMessages => {
cursor.onChunk(newMessages)
stickToBottom('auto', () => {
loading = sleep(30_000)
messages = sortBy(e => -e.created_at, newMessages.concat(messages))
network.loadPeople(pluck('pubkey', newMessages))
cursor.update(messages)
})
})
},

View File

@ -1,5 +1,5 @@
import {debounce, throttle} from 'throttle-debounce'
import {path as getPath, allPass, pipe, isNil, complement, equals, is, pluck, sum, identity, sortBy} from "ramda"
import {aperture, path as getPath, allPass, pipe, isNil, complement, equals, is, pluck, sum, identity, sortBy} from "ramda"
import Fuse from "fuse.js/dist/fuse.min.js"
import {writable} from 'svelte/store'
import {isObject} from 'hurdak/lib/hurdak'
@ -152,14 +152,19 @@ export class Cursor {
this.until = now()
this.limit = limit
}
onChunk(events) {
const minDelta = timedelta(1, 'minutes')
const maxDelta = timedelta(1, 'hours')
const delta = pluck('created_at', events).reduce(Math.min, 0) || 0
update(events) {
// update takes all events in a feed and figures out the best place to set `until`
// in order to find older events without re-fetching events that we've already seen.
// There are various edge cases:
// - When we have zero events, there's nothing we can do, presumably we have everything.
// - Sometimes relays send us extremely old events. Use median to avoid too-large gaps
if (events.length > 1) {
const timestamps = sortBy(identity, pluck('created_at', events))
const gaps = aperture(2, timestamps).map(([a, b]) => b - a)
const gap = quantile(gaps, 0.5)
// If the delta is very large, size it down. Relays with sparse data
// can slide the window very quickly, skipping a lot of events on more dense relays
this.until -= Math.max(minDelta, Math.min(maxDelta, delta))
this.until -= Math.round(gap * events.length)
}
}
}
@ -262,3 +267,14 @@ export const union = (...sets) =>
export const difference = (a, b) =>
new Set(Array.from(a).filter(x => !b.has(x)))
export const quantile = (a, q) => {
const sorted = sortBy(identity, a)
const pos = (sorted.length - 1) * q
const base = Math.floor(pos)
const rest = pos - base
return isNil(sorted[base + 1])
? sorted[base]
: sorted[base] + rest * (sorted[base + 1] - sorted[base])
}

View File

@ -12,7 +12,7 @@
transition:fly={{y: -50, duration: 300}}>
<div
class={cx(
"rounded shadow-xl mx-24 sm:mx-32 mt-2 p-3 text-center border pointer-events-auto",
"rounded shadow-xl m-2 ml-16 sm:ml-2 p-3 text-center border pointer-events-auto",
"max-w-xl flex-grow transition-all",
{
'bg-dark border-medium text-white': $toast.type === 'info',

View File

@ -68,8 +68,7 @@
notes = uniqBy(prop('id'), notes.concat(bottom))
notesBuffer = top.concat(notesBuffer).slice(0, maxNotes)
// Check all notes every time to stay very conservative with moving the window
cursor.onChunk(notes)
cursor.update(notes)
}
onMount(() => {