mirror of
https://github.com/DocNR/POWR.git
synced 2025-06-06 18:31:03 +00:00
Add contact cache schema and service integration
- Add contact_cache table schema and migration - Update useContactList hook with caching support - Enhance RelayInitializer with cache initialization - Update SocialFeedService to work with caching system
This commit is contained in:
parent
b5bf32d10f
commit
f17f0c4ff4
@ -2,7 +2,7 @@
|
|||||||
import { SQLiteDatabase } from 'expo-sqlite';
|
import { SQLiteDatabase } from 'expo-sqlite';
|
||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
|
|
||||||
export const SCHEMA_VERSION = 11;
|
export const SCHEMA_VERSION = 12;
|
||||||
|
|
||||||
class Schema {
|
class Schema {
|
||||||
private async getCurrentVersion(db: SQLiteDatabase): Promise<number> {
|
private async getCurrentVersion(db: SQLiteDatabase): Promise<number> {
|
||||||
@ -146,6 +146,54 @@ class Schema {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async migrate_v12(db: SQLiteDatabase): Promise<void> {
|
||||||
|
try {
|
||||||
|
console.log('[Schema] Running migration v12 - Adding Contact Cache table');
|
||||||
|
|
||||||
|
// Create contact_cache table if it doesn't exist
|
||||||
|
await db.execAsync(`
|
||||||
|
CREATE TABLE IF NOT EXISTS contact_cache (
|
||||||
|
owner_pubkey TEXT NOT NULL,
|
||||||
|
contact_pubkey TEXT NOT NULL,
|
||||||
|
cached_at INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (owner_pubkey, contact_pubkey)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_contact_cache_owner
|
||||||
|
ON contact_cache (owner_pubkey);
|
||||||
|
`);
|
||||||
|
|
||||||
|
console.log('[Schema] Migration v12 completed successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Schema] Error in migration v12:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async addContactCacheTable(db: SQLiteDatabase): Promise<void> {
|
||||||
|
try {
|
||||||
|
console.log('[Schema] Running migration v12 - Adding Contact Cache table');
|
||||||
|
|
||||||
|
// Create contact_cache table if it doesn't exist
|
||||||
|
await db.execAsync(`
|
||||||
|
CREATE TABLE IF NOT EXISTS contact_cache (
|
||||||
|
owner_pubkey TEXT NOT NULL,
|
||||||
|
contact_pubkey TEXT NOT NULL,
|
||||||
|
cached_at INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (owner_pubkey, contact_pubkey)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_contact_cache_owner
|
||||||
|
ON contact_cache (owner_pubkey);
|
||||||
|
`);
|
||||||
|
|
||||||
|
console.log('[Schema] Migration v12 completed successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Schema] Error in migration v12:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async createTables(db: SQLiteDatabase): Promise<void> {
|
async createTables(db: SQLiteDatabase): Promise<void> {
|
||||||
try {
|
try {
|
||||||
console.log(`[Schema] Initializing database on ${Platform.OS}`);
|
console.log(`[Schema] Initializing database on ${Platform.OS}`);
|
||||||
@ -207,6 +255,11 @@ class Schema {
|
|||||||
await this.migrate_v11(db);
|
await this.migrate_v11(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentVersion < 12) {
|
||||||
|
console.log(`[Schema] Running migration from version ${currentVersion} to 12`);
|
||||||
|
await this.migrate_v12(db);
|
||||||
|
}
|
||||||
|
|
||||||
// Update schema version at the end of the transaction
|
// Update schema version at the end of the transaction
|
||||||
await this.updateSchemaVersion(db);
|
await this.updateSchemaVersion(db);
|
||||||
});
|
});
|
||||||
@ -245,6 +298,11 @@ class Schema {
|
|||||||
await this.migrate_v11(db);
|
await this.migrate_v11(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentVersion < 12) {
|
||||||
|
console.log(`[Schema] Running migration from version ${currentVersion} to 12`);
|
||||||
|
await this.migrate_v12(db);
|
||||||
|
}
|
||||||
|
|
||||||
// Update schema version
|
// Update schema version
|
||||||
await this.updateSchemaVersion(db);
|
await this.updateSchemaVersion(db);
|
||||||
|
|
||||||
|
@ -1,20 +1,64 @@
|
|||||||
// lib/hooks/useContactList.ts
|
// lib/hooks/useContactList.ts
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import { NDKEvent, NDKUser, NDKKind, NDKSubscriptionCacheUsage } from '@nostr-dev-kit/ndk-mobile';
|
import { NDKEvent, NDKUser, NDKKind, NDKSubscriptionCacheUsage } from '@nostr-dev-kit/ndk-mobile';
|
||||||
import { useNDK } from '@/lib/hooks/useNDK';
|
import { useNDK } from '@/lib/hooks/useNDK';
|
||||||
import { POWR_PUBKEY_HEX } from '@/lib/hooks/useFeedHooks';
|
import { POWR_PUBKEY_HEX } from '@/lib/hooks/useFeedHooks';
|
||||||
|
import { useDatabase } from '@/components/DatabaseProvider';
|
||||||
|
import { getContactCacheService } from '@/lib/db/services/ContactCacheService';
|
||||||
|
|
||||||
export function useContactList(pubkey: string | undefined) {
|
export function useContactList(pubkey: string | undefined) {
|
||||||
const { ndk } = useNDK();
|
const { ndk } = useNDK();
|
||||||
|
const db = useDatabase();
|
||||||
const [contacts, setContacts] = useState<string[]>([]);
|
const [contacts, setContacts] = useState<string[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<Error | null>(null);
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
const [isInitialLoad, setIsInitialLoad] = useState(true);
|
||||||
|
|
||||||
|
// Use a ref to track if we've loaded from cache
|
||||||
|
const loadedFromCacheRef = useRef(false);
|
||||||
|
|
||||||
|
// Load contacts from cache first
|
||||||
|
useEffect(() => {
|
||||||
|
if (!pubkey || !db || loadedFromCacheRef.current) return;
|
||||||
|
|
||||||
|
const loadCachedContacts = async () => {
|
||||||
|
try {
|
||||||
|
const contactCache = getContactCacheService(db);
|
||||||
|
const cachedContacts = await contactCache.getCachedContacts(pubkey);
|
||||||
|
|
||||||
|
if (cachedContacts.length > 0) {
|
||||||
|
console.log(`[useContactList] Loaded ${cachedContacts.length} contacts from cache`);
|
||||||
|
|
||||||
|
// Add self and POWR account to contacts
|
||||||
|
const contactSet = new Set(cachedContacts);
|
||||||
|
contactSet.add(pubkey);
|
||||||
|
if (POWR_PUBKEY_HEX) {
|
||||||
|
contactSet.add(POWR_PUBKEY_HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set contacts state with cached contacts
|
||||||
|
setContacts(Array.from(contactSet));
|
||||||
|
setIsInitialLoad(false);
|
||||||
|
loadedFromCacheRef.current = true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[useContactList] Error loading cached contacts:', error);
|
||||||
|
// Don't set error state here - we'll still try to fetch from network
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadCachedContacts();
|
||||||
|
}, [pubkey, db]);
|
||||||
|
|
||||||
|
// Fetch contact list from NDK
|
||||||
const fetchContactList = useCallback(async () => {
|
const fetchContactList = useCallback(async () => {
|
||||||
if (!ndk || !pubkey) return;
|
if (!ndk || !pubkey) return;
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError(null);
|
if (!loadedFromCacheRef.current) {
|
||||||
|
// Only reset error if this is not a background refresh after cache load
|
||||||
|
setError(null);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try multiple approaches to ensure reliability
|
// Try multiple approaches to ensure reliability
|
||||||
@ -92,13 +136,26 @@ export function useContactList(pubkey: string | undefined) {
|
|||||||
// Convert to array and update state
|
// Convert to array and update state
|
||||||
const contactArray = Array.from(contactSet);
|
const contactArray = Array.from(contactSet);
|
||||||
setContacts(contactArray);
|
setContacts(contactArray);
|
||||||
|
setIsInitialLoad(false);
|
||||||
|
|
||||||
|
// Cache contacts if we have a database connection
|
||||||
|
if (db && contactArray.length > 0) {
|
||||||
|
try {
|
||||||
|
const contactCache = getContactCacheService(db);
|
||||||
|
await contactCache.cacheContacts(pubkey, contactArray);
|
||||||
|
console.log(`[useContactList] Cached ${contactArray.length} contacts for ${pubkey}`);
|
||||||
|
} catch (cacheError) {
|
||||||
|
console.error('[useContactList] Error caching contacts:', cacheError);
|
||||||
|
// Non-fatal, we can continue even if caching fails
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error fetching contact list:', err);
|
console.error('Error fetching contact list:', err);
|
||||||
setError(err instanceof Error ? err : new Error('Failed to fetch contacts'));
|
setError(err instanceof Error ? err : new Error('Failed to fetch contacts'));
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [ndk, pubkey]);
|
}, [ndk, pubkey, db]);
|
||||||
|
|
||||||
// Fetch on mount and when dependencies change
|
// Fetch on mount and when dependencies change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -112,6 +169,7 @@ export function useContactList(pubkey: string | undefined) {
|
|||||||
isLoading,
|
isLoading,
|
||||||
error,
|
error,
|
||||||
refetch: fetchContactList,
|
refetch: fetchContactList,
|
||||||
hasContacts: contacts.length > 0
|
hasContacts: contacts.length > 0,
|
||||||
|
isInitialLoad
|
||||||
};
|
};
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user