mirror of
https://github.com/dergigi/boris.git
synced 2025-12-19 07:34:28 +01:00
refactor: use applesauce EventStore for offline event management
Major improvements: - Store highlights in EventStore immediately when created - Query EventStore instead of local relays for offline sync - Pass eventStore to highlight creation service and hooks - Simplified offline sync: no more relay queries, just EventStore lookups - More efficient and reliable offline event tracking - Better integration with applesauce architecture Benefits: - Faster sync (no relay queries needed) - More reliable (events always in EventStore) - Cleaner code (leveraging applesauce patterns) - Better separation of concerns
This commit is contained in:
@@ -59,6 +59,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
|||||||
useOfflineSync({
|
useOfflineSync({
|
||||||
relayPool,
|
relayPool,
|
||||||
account: activeAccount,
|
account: activeAccount,
|
||||||
|
eventStore,
|
||||||
relayStatuses,
|
relayStatuses,
|
||||||
enabled: true
|
enabled: true
|
||||||
})
|
})
|
||||||
@@ -129,6 +130,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
|||||||
} = useHighlightCreation({
|
} = useHighlightCreation({
|
||||||
activeAccount,
|
activeAccount,
|
||||||
relayPool,
|
relayPool,
|
||||||
|
eventStore,
|
||||||
currentArticle,
|
currentArticle,
|
||||||
selectedUrl,
|
selectedUrl,
|
||||||
readerContent,
|
readerContent,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useCallback, useRef } from 'react'
|
import { useCallback, useRef } from 'react'
|
||||||
import { RelayPool } from 'applesauce-relay'
|
import { RelayPool } from 'applesauce-relay'
|
||||||
import { NostrEvent } from 'nostr-tools'
|
import { NostrEvent } from 'nostr-tools'
|
||||||
|
import { IEventStore } from 'applesauce-core'
|
||||||
import { Highlight } from '../types/highlights'
|
import { Highlight } from '../types/highlights'
|
||||||
import { ReadableContent } from '../services/readerService'
|
import { ReadableContent } from '../services/readerService'
|
||||||
import { createHighlight } from '../services/highlightCreationService'
|
import { createHighlight } from '../services/highlightCreationService'
|
||||||
@@ -11,6 +12,7 @@ interface UseHighlightCreationParams {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
activeAccount: any
|
activeAccount: any
|
||||||
relayPool: RelayPool | null
|
relayPool: RelayPool | null
|
||||||
|
eventStore: IEventStore | null
|
||||||
currentArticle: NostrEvent | undefined
|
currentArticle: NostrEvent | undefined
|
||||||
selectedUrl: string | undefined
|
selectedUrl: string | undefined
|
||||||
readerContent: ReadableContent | undefined
|
readerContent: ReadableContent | undefined
|
||||||
@@ -21,6 +23,7 @@ interface UseHighlightCreationParams {
|
|||||||
export const useHighlightCreation = ({
|
export const useHighlightCreation = ({
|
||||||
activeAccount,
|
activeAccount,
|
||||||
relayPool,
|
relayPool,
|
||||||
|
eventStore,
|
||||||
currentArticle,
|
currentArticle,
|
||||||
selectedUrl,
|
selectedUrl,
|
||||||
readerContent,
|
readerContent,
|
||||||
@@ -38,7 +41,7 @@ export const useHighlightCreation = ({
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleCreateHighlight = useCallback(async (text: string) => {
|
const handleCreateHighlight = useCallback(async (text: string) => {
|
||||||
if (!activeAccount || !relayPool) {
|
if (!activeAccount || !relayPool || !eventStore) {
|
||||||
console.error('Missing requirements for highlight creation')
|
console.error('Missing requirements for highlight creation')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -61,6 +64,7 @@ export const useHighlightCreation = ({
|
|||||||
source,
|
source,
|
||||||
activeAccount,
|
activeAccount,
|
||||||
relayPool,
|
relayPool,
|
||||||
|
eventStore,
|
||||||
contentForContext,
|
contentForContext,
|
||||||
undefined,
|
undefined,
|
||||||
settings
|
settings
|
||||||
@@ -79,7 +83,7 @@ export const useHighlightCreation = ({
|
|||||||
// Re-throw to allow parent to handle
|
// Re-throw to allow parent to handle
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}, [activeAccount, relayPool, currentArticle, selectedUrl, readerContent, onHighlightCreated, settings])
|
}, [activeAccount, relayPool, eventStore, currentArticle, selectedUrl, readerContent, onHighlightCreated, settings])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
highlightButtonRef,
|
highlightButtonRef,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef } from 'react'
|
||||||
import { RelayPool } from 'applesauce-relay'
|
import { RelayPool } from 'applesauce-relay'
|
||||||
import { IAccount } from 'applesauce-core/helpers'
|
import { IAccount, IEventStore } from 'applesauce-core'
|
||||||
import { syncLocalEventsToRemote } from '../services/offlineSyncService'
|
import { syncLocalEventsToRemote } from '../services/offlineSyncService'
|
||||||
import { isLocalRelay } from '../utils/helpers'
|
import { isLocalRelay } from '../utils/helpers'
|
||||||
import { RelayStatus } from '../services/relayStatusService'
|
import { RelayStatus } from '../services/relayStatusService'
|
||||||
@@ -8,6 +8,7 @@ import { RelayStatus } from '../services/relayStatusService'
|
|||||||
interface UseOfflineSyncParams {
|
interface UseOfflineSyncParams {
|
||||||
relayPool: RelayPool | null
|
relayPool: RelayPool | null
|
||||||
account: IAccount | null
|
account: IAccount | null
|
||||||
|
eventStore: IEventStore | null
|
||||||
relayStatuses: RelayStatus[]
|
relayStatuses: RelayStatus[]
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
}
|
}
|
||||||
@@ -15,6 +16,7 @@ interface UseOfflineSyncParams {
|
|||||||
export function useOfflineSync({
|
export function useOfflineSync({
|
||||||
relayPool,
|
relayPool,
|
||||||
account,
|
account,
|
||||||
|
eventStore,
|
||||||
relayStatuses,
|
relayStatuses,
|
||||||
enabled = true
|
enabled = true
|
||||||
}: UseOfflineSyncParams) {
|
}: UseOfflineSyncParams) {
|
||||||
@@ -27,7 +29,7 @@ export function useOfflineSync({
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!enabled || !relayPool || !account) return
|
if (!enabled || !relayPool || !account || !eventStore) return
|
||||||
|
|
||||||
const connectedRelays = relayStatuses.filter(r => r.isInPool)
|
const connectedRelays = relayStatuses.filter(r => r.isInPool)
|
||||||
const hasRemoteRelays = connectedRelays.some(r => !isLocalRelay(r.url))
|
const hasRemoteRelays = connectedRelays.some(r => !isLocalRelay(r.url))
|
||||||
@@ -57,11 +59,11 @@ export function useOfflineSync({
|
|||||||
// Wait a moment for relays to fully establish connections
|
// Wait a moment for relays to fully establish connections
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log('🚀 Starting sync after delay...')
|
console.log('🚀 Starting sync after delay...')
|
||||||
syncLocalEventsToRemote(relayPool, account)
|
syncLocalEventsToRemote(relayPool, account, eventStore)
|
||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
previousStateRef.current.hasRemoteRelays = hasRemoteRelays
|
previousStateRef.current.hasRemoteRelays = hasRemoteRelays
|
||||||
}, [relayPool, account, relayStatuses, enabled])
|
}, [relayPool, account, eventStore, relayStatuses, enabled])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { RelayPool } from 'applesauce-relay'
|
|||||||
import { IAccount } from 'applesauce-accounts'
|
import { IAccount } from 'applesauce-accounts'
|
||||||
import { AddressPointer } from 'nostr-tools/nip19'
|
import { AddressPointer } from 'nostr-tools/nip19'
|
||||||
import { NostrEvent } from 'nostr-tools'
|
import { NostrEvent } from 'nostr-tools'
|
||||||
import { Helpers } from 'applesauce-core'
|
import { Helpers, IEventStore } from 'applesauce-core'
|
||||||
import { RELAYS } from '../config/relays'
|
import { RELAYS } from '../config/relays'
|
||||||
import { Highlight } from '../types/highlights'
|
import { Highlight } from '../types/highlights'
|
||||||
import { UserSettings } from './settingsService'
|
import { UserSettings } from './settingsService'
|
||||||
@@ -35,6 +35,7 @@ export async function createHighlight(
|
|||||||
source: NostrEvent | string,
|
source: NostrEvent | string,
|
||||||
account: IAccount,
|
account: IAccount,
|
||||||
relayPool: RelayPool,
|
relayPool: RelayPool,
|
||||||
|
eventStore: IEventStore,
|
||||||
contentForContext?: string,
|
contentForContext?: string,
|
||||||
comment?: string,
|
comment?: string,
|
||||||
settings?: UserSettings
|
settings?: UserSettings
|
||||||
@@ -143,6 +144,10 @@ export async function createHighlight(
|
|||||||
eventId: signedEvent.id
|
eventId: signedEvent.id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Store the event in the local EventStore immediately
|
||||||
|
eventStore.add(signedEvent)
|
||||||
|
console.log('💾 Stored highlight in EventStore:', signedEvent.id.slice(0, 8))
|
||||||
|
|
||||||
// If we're in local-only mode, mark this event for later sync
|
// If we're in local-only mode, mark this event for later sync
|
||||||
if (isLocalOnly) {
|
if (isLocalOnly) {
|
||||||
markEventAsOfflineCreated(signedEvent.id)
|
markEventAsOfflineCreated(signedEvent.id)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { RelayPool } from 'applesauce-relay'
|
import { RelayPool } from 'applesauce-relay'
|
||||||
import { NostrEvent } from 'nostr-tools'
|
import { NostrEvent } from 'nostr-tools'
|
||||||
import { IAccount } from 'applesauce-core/helpers'
|
import { IAccount, IEventStore } from 'applesauce-core'
|
||||||
import { RELAYS } from '../config/relays'
|
import { RELAYS } from '../config/relays'
|
||||||
import { isLocalRelay } from '../utils/helpers'
|
import { isLocalRelay } from '../utils/helpers'
|
||||||
|
|
||||||
@@ -19,10 +19,12 @@ export function markEventAsOfflineCreated(eventId: string): void {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Syncs local-only events to remote relays when coming back online
|
* Syncs local-only events to remote relays when coming back online
|
||||||
|
* Now uses applesauce EventStore instead of querying relays
|
||||||
*/
|
*/
|
||||||
export async function syncLocalEventsToRemote(
|
export async function syncLocalEventsToRemote(
|
||||||
relayPool: RelayPool,
|
relayPool: RelayPool,
|
||||||
account: IAccount
|
account: IAccount,
|
||||||
|
eventStore: IEventStore
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (isSyncing) {
|
if (isSyncing) {
|
||||||
console.log('⏳ Sync already in progress, skipping...')
|
console.log('⏳ Sync already in progress, skipping...')
|
||||||
@@ -34,16 +36,9 @@ export async function syncLocalEventsToRemote(
|
|||||||
isSyncing = true
|
isSyncing = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const localRelays = RELAYS.filter(isLocalRelay)
|
|
||||||
const remoteRelays = RELAYS.filter(url => !isLocalRelay(url))
|
const remoteRelays = RELAYS.filter(url => !isLocalRelay(url))
|
||||||
|
|
||||||
console.log(`📡 Local relays: ${localRelays.length}, Remote relays: ${remoteRelays.length}`)
|
console.log(`📡 Remote relays: ${remoteRelays.length}`)
|
||||||
|
|
||||||
if (localRelays.length === 0) {
|
|
||||||
console.log('⚠️ No local relays available for sync')
|
|
||||||
isSyncing = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remoteRelays.length === 0) {
|
if (remoteRelays.length === 0) {
|
||||||
console.log('⚠️ No remote relays available for sync')
|
console.log('⚠️ No remote relays available for sync')
|
||||||
@@ -51,49 +46,30 @@ export async function syncLocalEventsToRemote(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get events from local relays that were created in the last 24 hours
|
if (offlineCreatedEvents.size === 0) {
|
||||||
const since = Math.floor(Date.now() / 1000) - (24 * 60 * 60)
|
console.log('✅ No offline events to sync')
|
||||||
const eventsToSync: NostrEvent[] = []
|
isSyncing = false
|
||||||
|
return
|
||||||
console.log(`🔍 Querying local relays for events since ${new Date(since * 1000).toISOString()}...`)
|
|
||||||
|
|
||||||
// Query for user's events from local relays
|
|
||||||
const filters = [
|
|
||||||
{ kinds: [9802], authors: [account.pubkey], since }, // Highlights
|
|
||||||
{ kinds: [10003, 30003], authors: [account.pubkey], since }, // Bookmarks
|
|
||||||
]
|
|
||||||
|
|
||||||
for (const filter of filters) {
|
|
||||||
console.log(`🔎 Querying with filter:`, filter)
|
|
||||||
const events = await new Promise<NostrEvent[]>((resolve) => {
|
|
||||||
const collected: NostrEvent[] = []
|
|
||||||
const sub = relayPool.req(localRelays, filter, {
|
|
||||||
onevent: (event: NostrEvent) => {
|
|
||||||
console.log(`📥 Received event ${event.id.slice(0, 8)} (kind ${event.kind}) from local relay`)
|
|
||||||
collected.push(event)
|
|
||||||
},
|
|
||||||
oneose: () => {
|
|
||||||
console.log(`✅ EOSE received, collected ${collected.length} events`)
|
|
||||||
sub.close()
|
|
||||||
resolve(collected)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Timeout after 10 seconds (increased from 5)
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log(`⏱️ Query timeout, collected ${collected.length} events`)
|
|
||||||
sub.close()
|
|
||||||
resolve(collected)
|
|
||||||
}, 10000)
|
|
||||||
})
|
|
||||||
|
|
||||||
eventsToSync.push(...events)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`📊 Total events collected: ${eventsToSync.length}`)
|
// Get events from EventStore using the tracked IDs
|
||||||
|
const eventsToSync: NostrEvent[] = []
|
||||||
|
console.log(`🔍 Querying EventStore for ${offlineCreatedEvents.size} offline events...`)
|
||||||
|
|
||||||
|
for (const eventId of offlineCreatedEvents) {
|
||||||
|
const event = eventStore.getEvent(eventId)
|
||||||
|
if (event) {
|
||||||
|
console.log(`📥 Found event ${eventId.slice(0, 8)} (kind ${event.kind}) in EventStore`)
|
||||||
|
eventsToSync.push(event)
|
||||||
|
} else {
|
||||||
|
console.warn(`⚠️ Event ${eventId.slice(0, 8)} not found in EventStore`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`📊 Total events to sync: ${eventsToSync.length}`)
|
||||||
|
|
||||||
if (eventsToSync.length === 0) {
|
if (eventsToSync.length === 0) {
|
||||||
console.log('✅ No local events to sync')
|
console.log('✅ No events found in EventStore to sync')
|
||||||
isSyncing = false
|
isSyncing = false
|
||||||
offlineCreatedEvents.clear()
|
offlineCreatedEvents.clear()
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user