cache user's metdata in db

This commit is contained in:
Ren Amamiya 2023-07-05 17:19:49 +07:00
parent ec9b54cb82
commit c5ba98e37a
6 changed files with 59 additions and 49 deletions

View File

@ -48,3 +48,12 @@ CREATE TABLE
value TEXT NOT NULL, value TEXT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
); );
-- create metadata table
CREATE TABLE
metadata (
id TEXT NOT NULL PRIMARY KEY,
pubkey TEXT NOT NULL,
content TEXT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

View File

@ -8,7 +8,7 @@ VALUES
'["wss://relayable.org","wss://relay.damus.io","wss://relay.nostr.band/all","wss://relay.nostrgraph.net","wss://nostr.mutinywallet.com"]' '["wss://relayable.org","wss://relay.damus.io","wss://relay.nostr.band/all","wss://relay.nostrgraph.net","wss://nostr.mutinywallet.com"]'
), ),
("auto_start", "0"), ("auto_start", "0"),
("cache_time", "86400"), ("cache_time", "86400000"),
("compose_shortcut", "meta+n"), ("compose_shortcut", "meta+n"),
("add_imageblock_shortcut", "meta+i"), ("add_imageblock_shortcut", "meta+i"),
("add_feedblock_shortcut", "meta+f") ("add_feedblock_shortcut", "meta+f")

View File

@ -1,5 +1,4 @@
import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk'; import { NDKFilter } from '@nostr-dev-kit/ndk';
import { useQueryClient } from '@tanstack/react-query';
import { useContext, useEffect, useRef } from 'react'; import { useContext, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -8,7 +7,6 @@ import {
countTotalNotes, countTotalNotes,
createChat, createChat,
createNote, createNote,
getAllPubkeys,
getLastLogin, getLastLogin,
updateLastLogin, updateLastLogin,
} from '@libs/storage'; } from '@libs/storage';
@ -21,12 +19,10 @@ import { useAccount } from '@utils/hooks/useAccount';
const totalNotes = await countTotalNotes(); const totalNotes = await countTotalNotes();
const lastLogin = await getLastLogin(); const lastLogin = await getLastLogin();
const users = await getAllPubkeys();
export function Root() { export function Root() {
const ndk = useContext(RelayContext); const ndk = useContext(RelayContext);
const now = useRef(new Date()); const now = useRef(new Date());
const queryClient = useQueryClient();
const navigate = useNavigate(); const navigate = useNavigate();
const { status, account } = useAccount(); const { status, account } = useAccount();
@ -49,8 +45,8 @@ export function Root() {
}; };
const events = await prefetchEvents(ndk, filter); const events = await prefetchEvents(ndk, filter);
events.forEach((event) => { for (const event of events) {
createNote( await createNote(
event.id, event.id,
event.pubkey, event.pubkey,
event.kind, event.kind,
@ -58,7 +54,7 @@ export function Root() {
event.content, event.content,
event.created_at event.created_at
); );
}); }
return true; return true;
} catch (e) { } catch (e) {
@ -66,33 +62,6 @@ export function Root() {
} }
} }
async function fetchUsersProfile() {
const authors = [];
users.forEach((user) => {
if (user.sender_pubkey) {
authors.push(user.sender_pubkey);
} else {
authors.push(user.pubkey);
}
});
const filter: NDKFilter = {
authors: authors,
kinds: [0],
};
const events = await ndk.fetchEvents(filter);
events.forEach((event: NDKEvent) => {
const profile = JSON.parse(event.content);
profile['image'] = profile.picture;
queryClient.setQueryData(['user', event.pubkey], profile);
});
return true;
}
async function fetchChats() { async function fetchChats() {
try { try {
const sendFilter: NDKFilter = { const sendFilter: NDKFilter = {
@ -108,11 +77,11 @@ export function Root() {
const sendMessages = await prefetchEvents(ndk, sendFilter); const sendMessages = await prefetchEvents(ndk, sendFilter);
const receiveMessages = await prefetchEvents(ndk, receiveFilter); const receiveMessages = await prefetchEvents(ndk, receiveFilter);
const events = [...sendMessages, ...receiveMessages];
events.forEach((event) => { const events = [...sendMessages, ...receiveMessages];
for (const event of events) {
const receiverPubkey = event.tags.find((t) => t[0] === 'p')[1] || account.pubkey; const receiverPubkey = event.tags.find((t) => t[0] === 'p')[1] || account.pubkey;
createChat( await createChat(
event.id, event.id,
receiverPubkey, receiverPubkey,
event.pubkey, event.pubkey,
@ -120,7 +89,7 @@ export function Root() {
event.tags, event.tags,
event.created_at event.created_at
); );
}); }
return true; return true;
} catch (e) { } catch (e) {
@ -172,8 +141,7 @@ export function Root() {
async function prefetch() { async function prefetch() {
const notes = await fetchNotes(); const notes = await fetchNotes();
const chats = await fetchChats(); const chats = await fetchChats();
const users = await fetchUsersProfile(); if (notes && chats) {
if (notes && users && chats) {
const now = Math.floor(Date.now() / 1000); const now = Math.floor(Date.now() / 1000);
await updateLastLogin(now); await updateLastLogin(now);
navigate('/app/space', { replace: true }); navigate('/app/space', { replace: true });

View File

@ -17,7 +17,9 @@ export function CacheTimeSetting() {
return ( return (
<div className="inline-flex items-center justify-between px-5 py-4"> <div className="inline-flex items-center justify-between px-5 py-4">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
<span className="font-medium leading-none text-zinc-200">Cache time</span> <span className="font-medium leading-none text-zinc-200">
Cache time (milliseconds)
</span>
<span className="text-sm leading-none text-zinc-400"> <span className="text-sm leading-none text-zinc-400">
The length of time before inactive data gets removed from the cache The length of time before inactive data gets removed from the cache
</span> </span>

View File

@ -1,3 +1,4 @@
import { NDKUserProfile } from '@nostr-dev-kit/ndk';
import Database from 'tauri-plugin-sql-api'; import Database from 'tauri-plugin-sql-api';
import { getParentID } from '@utils/transform'; import { getParentID } from '@utils/transform';
@ -426,3 +427,24 @@ export async function removeAll() {
await db.execute('DELETE FROM accounts;'); await db.execute('DELETE FROM accounts;');
return true; return true;
} }
// create metadata
export async function createMetadata(id: string, pubkey: string, content: string) {
const db = await connect();
const now = Math.floor(Date.now() / 1000);
return await db.execute(
'INSERT OR REPLACE INTO metadata (id, pubkey, content, created_at) VALUES (?, ?, ?, ?);',
[id, pubkey, content, now]
);
}
// get metadata
export async function getUserMetadata(pubkey: string) {
const db = await connect();
const result = await db.select(`SELECT content FROM metadata WHERE id = "${pubkey}";`);
if (result[0]) {
return JSON.parse(result[0].content);
} else {
return null;
}
}

View File

@ -1,6 +1,8 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useContext } from 'react'; import { useContext } from 'react';
import { createMetadata, getUserMetadata } from '@libs/storage';
import { RelayContext } from '@shared/relayProvider'; import { RelayContext } from '@shared/relayProvider';
export function useProfile(pubkey: string, fallback?: string) { export function useProfile(pubkey: string, fallback?: string) {
@ -13,15 +15,22 @@ export function useProfile(pubkey: string, fallback?: string) {
} = useQuery( } = useQuery(
['user', pubkey], ['user', pubkey],
async () => { async () => {
if (fallback) { if (!fallback) {
const profile = JSON.parse(fallback); const current = Math.floor(Date.now() / 1000);
return profile; const cache = await getUserMetadata(pubkey);
if (cache && parseInt(cache.created_at) + 86400 >= current) {
console.log('use cache', cache);
return cache;
} else { } else {
const user = ndk.getUser({ hexpubkey: pubkey }); const user = ndk.getUser({ hexpubkey: pubkey });
await user.fetchProfile(); await user.fetchProfile();
await createMetadata(pubkey, pubkey, JSON.stringify(user.profile));
return user.profile; return user.profile;
} }
} else {
const profile = JSON.parse(fallback);
return profile;
}
}, },
{ {
refetchOnWindowFocus: false, refetchOnWindowFocus: false,