mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-18 11:13:30 +00:00
add ndk cache tauri
This commit is contained in:
parent
ace58ecdd5
commit
0b25a4a04b
27
src-tauri/migrations/20231028083224_add_ndk_cache_table.sql
Normal file
27
src-tauri/migrations/20231028083224_add_ndk_cache_table.sql
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
-- Add migration script here
|
||||||
|
CREATE TABLE
|
||||||
|
ndk_users (
|
||||||
|
pubkey TEXT NOT NULL PRIMARY KEY,
|
||||||
|
profile TEXT,
|
||||||
|
createdAt NUMBER
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE
|
||||||
|
ndk_events (
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
pubkey TEXT,
|
||||||
|
content TEXT,
|
||||||
|
kind NUMBER,
|
||||||
|
createdAt NUMBER,
|
||||||
|
relay TEXT,
|
||||||
|
event TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE
|
||||||
|
ndk_eventtags (
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
eventId TEXT,
|
||||||
|
tag TEXT,
|
||||||
|
value TEXT,
|
||||||
|
tagValue TEXT
|
||||||
|
);
|
@ -128,12 +128,20 @@ fn main() {
|
|||||||
tauri_plugin_sql::Builder::default()
|
tauri_plugin_sql::Builder::default()
|
||||||
.add_migrations(
|
.add_migrations(
|
||||||
"sqlite:lume_v2.db",
|
"sqlite:lume_v2.db",
|
||||||
vec![Migration {
|
vec![
|
||||||
|
Migration {
|
||||||
version: 20230418013219,
|
version: 20230418013219,
|
||||||
description: "initial data",
|
description: "initial data",
|
||||||
sql: include_str!("../migrations/20230418013219_initial_data.sql"),
|
sql: include_str!("../migrations/20230418013219_initial_data.sql"),
|
||||||
kind: MigrationKind::Up,
|
kind: MigrationKind::Up,
|
||||||
}],
|
},
|
||||||
|
Migration {
|
||||||
|
version: 20231028083224,
|
||||||
|
description: "add ndk cache table",
|
||||||
|
sql: include_str!("../migrations/20231028083224_add_ndk_cache_table.sql"),
|
||||||
|
kind: MigrationKind::Up,
|
||||||
|
},
|
||||||
|
],
|
||||||
)
|
)
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
|
@ -5,61 +5,31 @@ import type {
|
|||||||
NDKFilter,
|
NDKFilter,
|
||||||
NDKSubscription,
|
NDKSubscription,
|
||||||
NDKUserProfile,
|
NDKUserProfile,
|
||||||
|
NostrEvent,
|
||||||
} from '@nostr-dev-kit/ndk';
|
} from '@nostr-dev-kit/ndk';
|
||||||
import _debug from 'debug';
|
import { LRUCache } from 'lru-cache';
|
||||||
import { matchFilter } from 'nostr-tools';
|
import { matchFilter } from 'nostr-tools';
|
||||||
import { LRUCache } from 'typescript-lru-cache';
|
|
||||||
|
|
||||||
import { createDatabase, db } from './db';
|
import { LumeStorage } from '@libs/storage/instance';
|
||||||
|
|
||||||
export { db } from './db';
|
export default class NDKCacheAdapterTauri implements NDKCacheAdapter {
|
||||||
|
public db: LumeStorage;
|
||||||
interface NDKCacheAdapterDexieOptions {
|
|
||||||
/**
|
|
||||||
* The name of the database to use
|
|
||||||
*/
|
|
||||||
dbName?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debug instance to use for logging
|
|
||||||
*/
|
|
||||||
debug?: debug.IDebugger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of seconds to store events in Dexie (IndexedDB) before they expire
|
|
||||||
* Defaults to 3600 seconds (1 hour)
|
|
||||||
*/
|
|
||||||
expirationTime?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of profiles to keep in an LRU cache
|
|
||||||
*/
|
|
||||||
profileCacheSize?: number | 'disabled';
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|
||||||
public debug: debug.Debugger;
|
|
||||||
private expirationTime;
|
|
||||||
readonly locking;
|
|
||||||
public profiles?: LRUCache<Hexpubkey, NDKUserProfile>;
|
public profiles?: LRUCache<Hexpubkey, NDKUserProfile>;
|
||||||
private dirtyProfiles: Set<Hexpubkey> = new Set();
|
private dirtyProfiles: Set<Hexpubkey> = new Set();
|
||||||
|
readonly locking: boolean;
|
||||||
|
|
||||||
constructor(opts: NDKCacheAdapterDexieOptions = {}) {
|
constructor(db: LumeStorage) {
|
||||||
createDatabase(opts.dbName || 'ndk');
|
this.db = db;
|
||||||
this.debug = opts.debug || _debug('ndk:dexie-adapter');
|
|
||||||
this.locking = true;
|
this.locking = true;
|
||||||
this.expirationTime = opts.expirationTime || 3600;
|
|
||||||
|
|
||||||
if (opts.profileCacheSize !== 'disabled') {
|
|
||||||
this.profiles = new LRUCache({
|
this.profiles = new LRUCache({
|
||||||
maxSize: opts.profileCacheSize || 100000,
|
max: 100000,
|
||||||
});
|
});
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
this.dumpProfiles();
|
this.dumpProfiles();
|
||||||
}, 1000 * 10);
|
}, 1000 * 10);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async query(subscription: NDKSubscription): Promise<void> {
|
public async query(subscription: NDKSubscription): Promise<void> {
|
||||||
Promise.allSettled(
|
Promise.allSettled(
|
||||||
@ -73,9 +43,9 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
let profile = this.profiles.get(pubkey);
|
let profile = this.profiles.get(pubkey);
|
||||||
|
|
||||||
if (!profile) {
|
if (!profile) {
|
||||||
const user = await db.users.get({ pubkey });
|
const user = await this.db.getCacheUser(pubkey);
|
||||||
if (user) {
|
if (user) {
|
||||||
profile = user.profile;
|
profile = user.profile as NDKUserProfile;
|
||||||
this.profiles.set(pubkey, profile);
|
this.profiles.set(pubkey, profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,7 +96,7 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
|
|
||||||
if (event.isParamReplaceable()) {
|
if (event.isParamReplaceable()) {
|
||||||
const replaceableId = `${event.kind}:${event.pubkey}:${event.tagId()}`;
|
const replaceableId = `${event.kind}:${event.pubkey}:${event.tagId()}`;
|
||||||
const existingEvent = await db.events.where({ id: replaceableId }).first();
|
const existingEvent = await this.db.getCacheEvent(replaceableId);
|
||||||
if (
|
if (
|
||||||
existingEvent &&
|
existingEvent &&
|
||||||
event.created_at &&
|
event.created_at &&
|
||||||
@ -137,7 +107,7 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (addEvent) {
|
if (addEvent) {
|
||||||
db.events.put({
|
this.db.setCacheEvent({
|
||||||
id: event.tagId(),
|
id: event.tagId(),
|
||||||
pubkey: event.pubkey,
|
pubkey: event.pubkey,
|
||||||
content: event.content,
|
content: event.content,
|
||||||
@ -153,7 +123,7 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
event.tags.forEach((tag) => {
|
event.tags.forEach((tag) => {
|
||||||
if (tag[0].length !== 1) return;
|
if (tag[0].length !== 1) return;
|
||||||
|
|
||||||
db.eventTags.put({
|
this.db.setCacheEventTag({
|
||||||
id: `${event.id}:${tag[0]}:${tag[1]}`,
|
id: `${event.id}:${tag[0]}:${tag[1]}`,
|
||||||
eventId: event.id,
|
eventId: event.id,
|
||||||
tag: tag[0],
|
tag: tag[0],
|
||||||
@ -182,9 +152,9 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
|
|
||||||
if (hasAllKeys && filter.authors) {
|
if (hasAllKeys && filter.authors) {
|
||||||
for (const pubkey of filter.authors) {
|
for (const pubkey of filter.authors) {
|
||||||
const events = await db.events.where({ pubkey }).toArray();
|
const events = await this.db.getCacheEventsByPubkey(pubkey);
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
let rawEvent;
|
let rawEvent: NostrEvent;
|
||||||
try {
|
try {
|
||||||
rawEvent = JSON.parse(event.event);
|
rawEvent = JSON.parse(event.event);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -218,9 +188,9 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
|
|
||||||
if (hasAllKeys && filter.kinds) {
|
if (hasAllKeys && filter.kinds) {
|
||||||
for (const kind of filter.kinds) {
|
for (const kind of filter.kinds) {
|
||||||
const events = await db.events.where({ kind }).toArray();
|
const events = await this.db.getCacheEventsByKind(kind);
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
let rawEvent;
|
let rawEvent: NostrEvent;
|
||||||
try {
|
try {
|
||||||
rawEvent = JSON.parse(event.event);
|
rawEvent = JSON.parse(event.event);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -252,10 +222,10 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
|
|
||||||
if (hasAllKeys && filter.ids) {
|
if (hasAllKeys && filter.ids) {
|
||||||
for (const id of filter.ids) {
|
for (const id of filter.ids) {
|
||||||
const event = await db.events.where({ id }).first();
|
const event = await this.db.getCacheEvent(id);
|
||||||
if (!event) continue;
|
if (!event) continue;
|
||||||
|
|
||||||
let rawEvent;
|
let rawEvent: NostrEvent;
|
||||||
try {
|
try {
|
||||||
rawEvent = JSON.parse(event.event);
|
rawEvent = JSON.parse(event.event);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -295,10 +265,10 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
for (const author of filter.authors) {
|
for (const author of filter.authors) {
|
||||||
for (const dTag of filter['#d']) {
|
for (const dTag of filter['#d']) {
|
||||||
const replaceableId = `${kind}:${author}:${dTag}`;
|
const replaceableId = `${kind}:${author}:${dTag}`;
|
||||||
const event = await db.events.where({ id: replaceableId }).first();
|
const event = await this.db.getCacheEvent(replaceableId);
|
||||||
if (!event) continue;
|
if (!event) continue;
|
||||||
|
|
||||||
let rawEvent;
|
let rawEvent: NostrEvent;
|
||||||
try {
|
try {
|
||||||
rawEvent = JSON.parse(event.event);
|
rawEvent = JSON.parse(event.event);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -335,10 +305,10 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
if (filter.kinds && filter.authors) {
|
if (filter.kinds && filter.authors) {
|
||||||
for (const kind of filter.kinds) {
|
for (const kind of filter.kinds) {
|
||||||
for (const author of filter.authors) {
|
for (const author of filter.authors) {
|
||||||
const events = await db.events.where({ kind, pubkey: author }).toArray();
|
const events = await this.db.getCacheEventsByKindAndAuthor(kind, author);
|
||||||
|
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
let rawEvent;
|
let rawEvent: NostrEvent;
|
||||||
try {
|
try {
|
||||||
rawEvent = JSON.parse(event.event);
|
rawEvent = JSON.parse(event.event);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -400,12 +370,12 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const value of values) {
|
for (const value of values) {
|
||||||
const eventTags = await db.eventTags.where({ tagValue: tag + value }).toArray();
|
const eventTags = await this.db.getCacheEventTagsByTagValue(tag + value);
|
||||||
if (!eventTags.length) continue;
|
if (!eventTags.length) continue;
|
||||||
|
|
||||||
const eventIds = eventTags.map((t) => t.eventId);
|
const eventIds = eventTags.map((t) => t.eventId);
|
||||||
|
|
||||||
const events = await db.events.where('id').anyOf(eventIds).toArray();
|
const events = await this.db.getCacheEvents(eventIds);
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
let rawEvent;
|
let rawEvent;
|
||||||
try {
|
try {
|
||||||
@ -441,13 +411,13 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
|
|||||||
|
|
||||||
profiles.push({
|
profiles.push({
|
||||||
pubkey,
|
pubkey,
|
||||||
profile,
|
profile: JSON.stringify(profile),
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profiles.length) {
|
if (profiles.length) {
|
||||||
await db.users.bulkPut(profiles);
|
await this.db.setCacheProfiles(profiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dirtyProfiles.clear();
|
this.dirtyProfiles.clear();
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import NDK, { NDKNip46Signer, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
import NDK, { NDKNip46Signer, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
||||||
import NDKCacheAdapterDexie from '@nostr-dev-kit/ndk-cache-dexie';
|
|
||||||
import { ndkAdapter } from '@nostr-fetch/adapter-ndk';
|
import { ndkAdapter } from '@nostr-fetch/adapter-ndk';
|
||||||
import { message } from '@tauri-apps/plugin-dialog';
|
import { message } from '@tauri-apps/plugin-dialog';
|
||||||
import { fetch } from '@tauri-apps/plugin-http';
|
import { fetch } from '@tauri-apps/plugin-http';
|
||||||
import { NostrFetcher } from 'nostr-fetch';
|
import { NostrFetcher } from 'nostr-fetch';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import NDKCacheAdapterTauri from '@libs/ndk/cache';
|
||||||
import { useStorage } from '@libs/storage/provider';
|
import { useStorage } from '@libs/storage/provider';
|
||||||
|
|
||||||
export const NDKInstance = () => {
|
export const NDKInstance = () => {
|
||||||
@ -77,7 +77,7 @@ export const NDKInstance = () => {
|
|||||||
const outboxSetting = await db.getSettingValue('outbox');
|
const outboxSetting = await db.getSettingValue('outbox');
|
||||||
const explicitRelayUrls = await getExplicitRelays();
|
const explicitRelayUrls = await getExplicitRelays();
|
||||||
|
|
||||||
const dexieAdapter = new NDKCacheAdapterDexie({ dbName: 'lume_ndkcache' });
|
const dexieAdapter = new NDKCacheAdapterTauri(db);
|
||||||
const instance = new NDK({
|
const instance = new NDK({
|
||||||
explicitRelayUrls,
|
explicitRelayUrls,
|
||||||
cacheAdapter: dexieAdapter,
|
cacheAdapter: dexieAdapter,
|
||||||
|
@ -6,7 +6,15 @@ import Database from '@tauri-apps/plugin-sql';
|
|||||||
import { FULL_RELAYS } from '@stores/constants';
|
import { FULL_RELAYS } from '@stores/constants';
|
||||||
|
|
||||||
import { rawEvent } from '@utils/transform';
|
import { rawEvent } from '@utils/transform';
|
||||||
import { Account, DBEvent, Relays, Widget } from '@utils/types';
|
import type {
|
||||||
|
Account,
|
||||||
|
DBEvent,
|
||||||
|
NDKCacheEvent,
|
||||||
|
NDKCacheEventTag,
|
||||||
|
NDKCacheUser,
|
||||||
|
Relays,
|
||||||
|
Widget,
|
||||||
|
} from '@utils/types';
|
||||||
|
|
||||||
export class LumeStorage {
|
export class LumeStorage {
|
||||||
public db: Database;
|
public db: Database;
|
||||||
@ -37,6 +45,115 @@ export class LumeStorage {
|
|||||||
return await invoke('secure_remove', { key });
|
return await invoke('secure_remove', { key });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getCacheUser(pubkey: string) {
|
||||||
|
const results: Array<NDKCacheUser> = await this.db.select(
|
||||||
|
'SELECT * FROM ndk_users WHERE pubkey = $1 ORDER BY pubkey DESC LIMIT 1;',
|
||||||
|
[pubkey]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.length < 1) return null;
|
||||||
|
|
||||||
|
if (typeof results[0].profile === 'string')
|
||||||
|
results[0].profile = JSON.parse(results[0].profile);
|
||||||
|
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCacheEvent(id: string) {
|
||||||
|
const results: Array<NDKCacheEvent> = await this.db.select(
|
||||||
|
'SELECT * FROM ndk_events WHERE id = $1 ORDER BY id DESC LIMIT 1;',
|
||||||
|
[id]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.length < 1) return null;
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCacheEvents(ids: string[]) {
|
||||||
|
const idsArr = `'${ids.join("','")}'`;
|
||||||
|
|
||||||
|
const results: Array<NDKCacheEvent> = await this.db.select(
|
||||||
|
`SELECT * FROM ndk_events WHERE id IN (${idsArr}) ORDER BY id;`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.length < 1) return [];
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCacheEventsByPubkey(pubkey: string) {
|
||||||
|
const results: Array<NDKCacheEvent> = await this.db.select(
|
||||||
|
'SELECT * FROM ndk_events WHERE pubkey = $1 ORDER BY id;',
|
||||||
|
[pubkey]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.length < 1) return [];
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCacheEventsByKind(kind: number) {
|
||||||
|
const results: Array<NDKCacheEvent> = await this.db.select(
|
||||||
|
'SELECT * FROM ndk_events WHERE kind = $1 ORDER BY id;',
|
||||||
|
[kind]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.length < 1) return [];
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCacheEventsByKindAndAuthor(kind: number, pubkey: string) {
|
||||||
|
const results: Array<NDKCacheEvent> = await this.db.select(
|
||||||
|
'SELECT * FROM ndk_events WHERE kind = $1 AND pubkey = $2 ORDER BY id;',
|
||||||
|
[kind, pubkey]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.length < 1) return [];
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCacheEventTagsByTagValue(tagValue: string) {
|
||||||
|
const results: Array<NDKCacheEventTag> = await this.db.select(
|
||||||
|
'SELECT * FROM ndk_eventtags WHERE tagValue = $1 ORDER BY id;',
|
||||||
|
[tagValue]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.length < 1) return [];
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setCacheEvent({
|
||||||
|
id,
|
||||||
|
pubkey,
|
||||||
|
content,
|
||||||
|
kind,
|
||||||
|
createdAt,
|
||||||
|
relay,
|
||||||
|
event,
|
||||||
|
}: NDKCacheEvent) {
|
||||||
|
return await this.db.execute(
|
||||||
|
'INSERT OR IGNORE INTO ndk_events (id, pubkey, content, kind, createdAt, relay, event) VALUES ($1, $2, $3, $4, $5, $6, $7);',
|
||||||
|
[id, pubkey, content, kind, createdAt, relay, event]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setCacheEventTag({ id, eventId, tag, value, tagValue }: NDKCacheEventTag) {
|
||||||
|
return await this.db.execute(
|
||||||
|
'INSERT OR IGNORE INTO ndk_eventtags (id, eventId, tag, value, tagValue) VALUES ($1, $2, $3, $4, $5);',
|
||||||
|
[id, eventId, tag, value, tagValue]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setCacheProfiles(profiles: Array<NDKCacheUser>) {
|
||||||
|
return await Promise.all(
|
||||||
|
profiles.map(
|
||||||
|
async (profile) =>
|
||||||
|
await this.db.execute(
|
||||||
|
'INSERT OR IGNORE INTO ndk_users (pubkey, profile, createdAt) VALUES ($1, $2, $3);',
|
||||||
|
[profile.pubkey, profile.profile, profile.createdAt]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public async checkAccount() {
|
public async checkAccount() {
|
||||||
const result: Array<{ total: string }> = await this.db.select(
|
const result: Array<{ total: string }> = await this.db.select(
|
||||||
'SELECT COUNT(*) AS "total" FROM accounts;'
|
'SELECT COUNT(*) AS "total" FROM accounts;'
|
||||||
|
@ -189,7 +189,7 @@ export const User = memo(function User({
|
|||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2.5">
|
<div className="flex items-center gap-2.5">
|
||||||
<div className="h-11 w-11 shrink-0 animate-pulse rounded-lg bg-neutral-300 dark:bg-neutral-700" />
|
<div className="h-11 w-11 shrink-0 animate-pulse rounded-lg bg-neutral-300 dark:bg-neutral-700" />
|
||||||
<div className="flex w-full flex-col items-start">
|
<div className="flex w-full flex-col items-start gap-1">
|
||||||
<div className="h-4 w-36 animate-pulse rounded bg-neutral-300 dark:bg-neutral-700" />
|
<div className="h-4 w-36 animate-pulse rounded bg-neutral-300 dark:bg-neutral-700" />
|
||||||
<div className="h-4 w-24 animate-pulse rounded bg-neutral-300 dark:bg-neutral-700" />
|
<div className="h-4 w-24 animate-pulse rounded bg-neutral-300 dark:bg-neutral-700" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,19 +19,18 @@ export function EventLoader({ firstTime }: { firstTime: boolean }) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getEvents() {
|
async function getEvents() {
|
||||||
const events = await getAllEventsSinceLastLogin();
|
const events = await getAllEventsSinceLastLogin();
|
||||||
console.log('total new events has found: ', events.data.length);
|
console.log('total new events has found: ', events.length);
|
||||||
|
|
||||||
const promises = await Promise.all(
|
if (events) {
|
||||||
events.data.map(async (event) => await db.createEvent(event))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (promises) {
|
|
||||||
setProgress(100);
|
setProgress(100);
|
||||||
setIsFetched();
|
setIsFetched();
|
||||||
|
|
||||||
// invalidate queries
|
// invalidate queries
|
||||||
queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: ['local-network-widget']
|
queryKey: ['local-network-widget'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// update last login time, use for next fetch
|
||||||
await db.updateLastLogin();
|
await db.updateLastLogin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import { TitleBar } from '@shared/titleBar';
|
|||||||
import { WidgetWrapper } from '@shared/widgets';
|
import { WidgetWrapper } from '@shared/widgets';
|
||||||
|
|
||||||
import { useActivities } from '@stores/activities';
|
import { useActivities } from '@stores/activities';
|
||||||
|
import { useWidgets } from '@stores/widgets';
|
||||||
|
|
||||||
import { useNostr } from '@utils/hooks/useNostr';
|
import { useNostr } from '@utils/hooks/useNostr';
|
||||||
import { Widget } from '@utils/types';
|
import { Widget } from '@utils/types';
|
||||||
@ -23,6 +24,8 @@ export function LocalNotificationWidget({ params }: { params: Widget }) {
|
|||||||
state.setActivities,
|
state.setActivities,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const isFetched = useWidgets((state) => state.isFetched);
|
||||||
|
|
||||||
const renderEvent = useCallback(
|
const renderEvent = useCallback(
|
||||||
(event: NDKEvent) => {
|
(event: NDKEvent) => {
|
||||||
if (event.pubkey === db.account.pubkey) return null;
|
if (event.pubkey === db.account.pubkey) return null;
|
||||||
@ -37,8 +40,8 @@ export function LocalNotificationWidget({ params }: { params: Widget }) {
|
|||||||
setActivities(events);
|
setActivities(events);
|
||||||
}
|
}
|
||||||
|
|
||||||
getActivities();
|
if (isFetched) getActivities();
|
||||||
}, []);
|
}, [isFetched]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WidgetWrapper>
|
<WidgetWrapper>
|
||||||
|
@ -3,14 +3,12 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { AddressPointer } from 'nostr-tools/lib/types/nip19';
|
import { AddressPointer } from 'nostr-tools/lib/types/nip19';
|
||||||
|
|
||||||
import { useNDK } from '@libs/ndk/provider';
|
import { useNDK } from '@libs/ndk/provider';
|
||||||
import { useStorage } from '@libs/storage/provider';
|
|
||||||
|
|
||||||
export function useEvent(
|
export function useEvent(
|
||||||
id: undefined | string,
|
id: undefined | string,
|
||||||
naddr?: undefined | AddressPointer,
|
naddr?: undefined | AddressPointer,
|
||||||
embed?: undefined | string
|
embed?: undefined | string
|
||||||
) {
|
) {
|
||||||
const { db } = useStorage();
|
|
||||||
const { ndk } = useNDK();
|
const { ndk } = useNDK();
|
||||||
const { status, data } = useQuery({
|
const { status, data } = useQuery({
|
||||||
queryKey: ['event', id],
|
queryKey: ['event', id],
|
||||||
@ -33,20 +31,16 @@ export function useEvent(
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get event from db
|
// get event from relay
|
||||||
const dbEvent = await db.getEventByID(id);
|
|
||||||
if (dbEvent) return dbEvent;
|
|
||||||
|
|
||||||
// get event from relay if event in db not present
|
|
||||||
const event = await ndk.fetchEvent(id);
|
const event = await ndk.fetchEvent(id);
|
||||||
if (!event) return Promise.reject(new Error('event not found'));
|
if (!event) return Promise.reject(new Error('event not found'));
|
||||||
|
|
||||||
await db.createEvent(event);
|
|
||||||
|
|
||||||
return event;
|
return event;
|
||||||
},
|
},
|
||||||
enabled: !!ndk,
|
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
|
refetchOnMount: false,
|
||||||
|
refetchOnReconnect: false,
|
||||||
|
staleTime: Infinity,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { status, data };
|
return { status, data };
|
||||||
|
@ -186,10 +186,9 @@ export function useNostr() {
|
|||||||
{ since: since }
|
{ since: since }
|
||||||
)) as unknown as NDKEvent[];
|
)) as unknown as NDKEvent[];
|
||||||
|
|
||||||
return { status: 'ok', message: 'fetch completed', data: events };
|
return events;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('prefetch events failed, error: ', e);
|
console.error('prefetch events failed, error: ', e);
|
||||||
return { status: 'failed', message: e };
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,12 +22,10 @@ export function useProfile(pubkey: string, embed?: string) {
|
|||||||
|
|
||||||
return await user.fetchProfile();
|
return await user.fetchProfile();
|
||||||
},
|
},
|
||||||
enabled: !!ndk,
|
|
||||||
staleTime: Infinity,
|
staleTime: Infinity,
|
||||||
refetchOnMount: false,
|
refetchOnMount: false,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
refetchOnReconnect: false,
|
refetchOnReconnect: false,
|
||||||
retry: 2,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return { status, user, error };
|
return { status, user, error };
|
||||||
|
24
src/utils/types.d.ts
vendored
24
src/utils/types.d.ts
vendored
@ -115,3 +115,27 @@ export interface Resources {
|
|||||||
title: string;
|
title: string;
|
||||||
data: Array<Resource>;
|
data: Array<Resource>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface NDKCacheUser {
|
||||||
|
pubkey: string;
|
||||||
|
profile: string | NDKUserProfile;
|
||||||
|
createdAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NDKCacheEvent {
|
||||||
|
id: string;
|
||||||
|
pubkey: string;
|
||||||
|
content: string;
|
||||||
|
kind: number;
|
||||||
|
createdAt: number;
|
||||||
|
relay: string;
|
||||||
|
event: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NDKCacheEventTag {
|
||||||
|
id: string;
|
||||||
|
eventId: string;
|
||||||
|
tag: string;
|
||||||
|
value: string;
|
||||||
|
tagValue: string;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user