Add FeedService and integrate into NostrFeed module

- Introduced FeedService to manage feed functionality, including subscription and deduplication of posts.
- Updated NostrFeed module to register FeedService in the DI container and initialize it during installation.
- Refactored useFeed composable to utilize FeedService for managing feed state and loading posts.
- Enhanced NostrFeed component to display posts and handle loading states more effectively.
- Changed Home.vue to use the 'all' feed type for broader content display.

These changes improve the modularity and functionality of the feed system, providing a more robust user experience.
This commit is contained in:
padreug 2025-09-16 21:43:23 +02:00
parent 2e12315a35
commit 6217e3b70a
6 changed files with 408 additions and 270 deletions

View file

@ -1,97 +1,55 @@
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { computed, ref, onMounted, onUnmounted } from 'vue'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import { eventBus } from '@/core/event-bus'
import type { Event as NostrEvent, Filter } from 'nostr-tools'
import type { FeedService, FeedConfig } from '../services/FeedService'
export interface FeedConfig {
feedType: 'announcements' | 'general' | 'mentions'
export interface UseFeedConfig {
feedType: 'announcements' | 'general' | 'mentions' | 'events' | 'all'
maxPosts?: number
refreshInterval?: number
adminPubkeys?: string[]
}
export function useFeed(config: FeedConfig) {
const relayHub = injectService<any>(SERVICE_TOKENS.RELAY_HUB)
const posts = ref<NostrEvent[]>([])
const isLoading = ref(false)
const error = ref<string | null>(null)
export function useFeed(config: UseFeedConfig) {
const feedService = injectService<FeedService>(SERVICE_TOKENS.FEED_SERVICE)
console.log('useFeed: FeedService injected:', !!feedService)
if (!feedService) {
console.error('useFeed: FeedService not available from DI container')
}
let refreshTimer: number | null = null
let unsubscribe: (() => void) | null = null
// Convert to FeedService config
const feedConfig: FeedConfig = {
feedType: config.feedType,
maxPosts: config.maxPosts,
adminPubkeys: config.adminPubkeys
}
const filteredPosts = computed(() => {
let filtered = posts.value
// Filter by feed type
if (config.feedType === 'announcements' && config.adminPubkeys) {
filtered = filtered.filter(post => config.adminPubkeys!.includes(post.pubkey))
}
// Sort by created timestamp (newest first)
filtered = filtered.sort((a, b) => b.created_at - a.created_at)
// Limit posts
if (config.maxPosts) {
filtered = filtered.slice(0, config.maxPosts)
}
return filtered
if (!feedService) return []
return feedService.getFilteredPosts(feedConfig)
})
const loadFeed = async () => {
if (!relayHub) {
error.value = 'RelayHub not available'
console.log('useFeed: loadFeed called, feedService available:', !!feedService)
if (!feedService) {
console.error('FeedService not available')
return
}
isLoading.value = true
error.value = null
console.log('useFeed: calling feedService.subscribeFeed with config:', feedConfig)
try {
// Create filter based on feed type
const filter: Filter = {
kinds: [1], // Text notes
limit: config.maxPosts || 50
}
if (config.feedType === 'announcements' && config.adminPubkeys) {
filter.authors = config.adminPubkeys
}
// Subscribe to events
await relayHub.subscribe('feed-subscription', [filter], {
onEvent: (event: NostrEvent) => {
// Add new event if not already present
if (!posts.value.some(p => p.id === event.id)) {
posts.value = [event, ...posts.value]
// Emit event for other modules
eventBus.emit('nostr-feed:new-post', { event, feedType: config.feedType }, 'nostr-feed')
}
},
onEose: () => {
console.log('Feed subscription end of stored events')
isLoading.value = false
},
onClose: () => {
console.log('Feed subscription closed')
}
})
unsubscribe = () => {
relayHub.unsubscribe('feed-subscription')
}
await feedService.subscribeFeed(feedConfig)
console.log('useFeed: subscribeFeed completed')
} catch (err) {
console.error('Failed to load feed:', err)
error.value = err instanceof Error ? err.message : 'Failed to load feed'
isLoading.value = false
}
}
const refreshFeed = () => {
posts.value = []
loadFeed()
const refreshFeed = async () => {
if (!feedService) return
await feedService.refreshFeed()
}
const startAutoRefresh = () => {
@ -109,21 +67,19 @@ export function useFeed(config: FeedConfig) {
// Lifecycle
onMounted(() => {
console.log('useFeed: onMounted called')
loadFeed()
startAutoRefresh()
})
onUnmounted(() => {
stopAutoRefresh()
if (unsubscribe) {
unsubscribe()
}
})
return {
posts: filteredPosts,
isLoading,
error,
isLoading: feedService?.isLoading ?? ref(false),
error: feedService?.error ?? ref(null),
refreshFeed,
loadFeed
}