From fd3f8ec4f6f3cafb3cfb6ff94462e267f5b4ade2 Mon Sep 17 00:00:00 2001 From: Jonathan Staab Date: Fri, 23 Dec 2022 16:02:01 -0800 Subject: [PATCH] Fix alerts --- README.md | 27 ++++++---------------- src/App.svelte | 45 ++++++++++++++++++------------------- src/partials/Note.svelte | 5 +++-- src/relay/db.js | 8 +++---- src/routes/Alerts.svelte | 7 +++--- src/routes/RelayList.svelte | 23 +++++++------------ src/util/misc.js | 2 +- 7 files changed, 49 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index c4063f2c..0f520393 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # What is this? -Coracle is a web client for the Nostr protocol. While Nostr is useful for many things, Coracle focuses on providing a high-quality user experience. Check it out at [coracle.social](https://coracle.social). +Coracle is a web client for the Nostr protocol. While Nostr is useful for many things, Coracle focuses on providing a high-quality social media experience. Check it out at [coracle.social](https://coracle.social). [Dufflepud](https://github.com/staab/dufflepud) is a companion server which you can self-host. It helps Coracle with things like link previews and image uploads. Coracle is currently in _alpha_ - expect bugs, slow loading times, and rough edges. +If you like Coracle and want to support its development, you can donate sats via [Geyser](https://geyser.fund/project/coracle). + # Features - [x] Chat @@ -24,7 +26,6 @@ Coracle is currently in _alpha_ - expect bugs, slow loading times, and rough edg # Bugs -- [ ] Use https://nostr.watch/relays.json to populate relays - [ ] Add alerts for replies to posts the user liked - [ ] With link/image previews, remove the url from the note body if it's on a separate last line - [ ] Stack views so scroll position isn't lost on navigation @@ -32,23 +33,9 @@ Coracle is currently in _alpha_ - expect bugs, slow loading times, and rough edg - [ ] Wait for 60% or so of relays to eose to balance completeness with speed - [ ] Add a CSP, check for XSS in image urls -# Current update +# Changelog -- [ ] Write blog post -- [x] Sync user -- [x] Based on petnames, sync network to 2 or 3 degrees of separation - - When a user is added/removed, sync them and add to or remove from network -- [x] Add cursor object to handle since/until/last sync -- [x] Separate fetching and loading from the db - - Each route should have a fetcher and loader. - - The fetcher should keep track of the range of notes it has already gotten - - Separate helper functions into loaders and fetchers -- [x] Main fetch requests: - - Fetch feed by name, since last sync - - Fetch person, including feed - - Fetch note, including context - - This is based on detail pages. Each request should check local db and fall back to network, all within an await. +## 0.2.0 -# Problems to solve - -- [ ] How will newcomers get followed? +- [x] Completely re-worked data synchronization layer, moving from naive just-in-time requests to background listeners and a local copy stored in dexie. Events and tags, but not people are deleted from the database on logout, and old events are periodically purged. +- [x] diff --git a/src/App.svelte b/src/App.svelte index ea2f807e..6b82b1cc 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -10,9 +10,9 @@ import {Router, Route, links, navigate} from "svelte-routing" import {globalHistory} from "svelte-routing/src/history" import {hasParent} from 'src/util/html' - import {timedelta, now} from 'src/util/misc' + import {timedelta, getLastSync, now} from 'src/util/misc' import {store as toast} from "src/state/toast" - import {modal, alerts, settings} from "src/state/app" + import {modal, settings, alerts} from "src/state/app" import relay, {user, connections} from 'src/relay' import Anchor from 'src/partials/Anchor.svelte' import NoteDetail from "src/views/NoteDetail.svelte" @@ -43,31 +43,24 @@ let menuIcon let scrollY let suspendedSubs = [] - let mostRecentAlert = relay.lq(async () => { - const [e] = await relay.filterAlerts($user, 1) + let mostRecentAlert = $alerts.since - return e?.created_at - }) + const logout = async () => { + const $connections = get(connections) + const $settings = get(settings) - const logout = () => { - // Give any animations a moment to finish - setTimeout(() => { - const $connections = get(connections) - const $settings = get(settings) + localStorage.clear() - localStorage.clear() + // Keep relays around + await relay.db.events.clear() + await relay.db.tags.clear() - // Keep relays around - relay.db.events.clear() - relay.db.tags.clear() + // Remember the user's relay selection and settings + connections.set($connections) + settings.set($settings) - // Remember the user's relay selection and settings - connections.set($connections) - settings.set($settings) - - // Do a hard refresh so everything gets totally cleared - window.location = '/login' - }, 200) + // do a hard refresh so everything gets totally cleared + window.location = '/login' } onMount(() => { @@ -83,7 +76,13 @@ const unsubUser = user.subscribe($user => { if ($user && $user.pubkey !== prevPubkey) { relay.pool.syncNetwork() - relay.pool.listenForEvents('App/alerts', {'#p': [$user.pubkey], since: now()}) + relay.pool.listenForEvents( + 'App/alerts', + [{kinds: [1, 7], '#p': [$user.pubkey], since: mostRecentAlert}], + e => { + mostRecentAlert = Math.max(e.created_at, mostRecentAlert) + } + ) } prevPubkey = $user?.pubkey diff --git a/src/partials/Note.svelte b/src/partials/Note.svelte index 4491b16e..9c5d2175 100644 --- a/src/partials/Note.svelte +++ b/src/partials/Note.svelte @@ -16,6 +16,7 @@ export let note export let depth = 0 export let anchorId = null + export let showParent = true export let invertColors = false let reply = null @@ -117,7 +118,7 @@

{formatTimestamp(note.created_at)}

- {#if findReply(note)} + {#if findReply(note) && showParent} Reply to {findReply(note).slice(0, 8)} @@ -184,7 +185,7 @@ {#if depth > 0} {#each note.replies as r (r.id)}
- +
{/each} {/if} diff --git a/src/relay/db.js b/src/relay/db.js index 1f2e5a11..1b2f1e74 100644 --- a/src/relay/db.js +++ b/src/relay/db.js @@ -39,7 +39,7 @@ db.events.process = async events => { // Persist notes and reactions if (notesAndReactions.length > 0) { const persistentEvents = notesAndReactions - .map(e => ({...e, root: findRoot(e), reply: findReply(e), created_at: now()})) + .map(e => ({...e, root: findRoot(e), reply: findReply(e), loaded_at: now()})) db.events.bulkPut(persistentEvents) @@ -54,7 +54,7 @@ db.events.process = async events => { value: tag[1], relay: tag[2], mark: tag[3], - created_at: e.created_at, + loaded_at: now(), }) ) ) @@ -107,5 +107,5 @@ db.events.process = async events => { // On initial load, delete old event data const threshold = now() - timedelta(30, 'days') -db.events.where('created_at').below(threshold).delete() -db.tags.where('created_at').below(threshold).delete() +db.events.where('loaded_at').below(threshold).delete() +db.tags.where('loaded_at').below(threshold).delete() diff --git a/src/routes/Alerts.svelte b/src/routes/Alerts.svelte index 4e2383f9..fd9f8ded 100644 --- a/src/routes/Alerts.svelte +++ b/src/routes/Alerts.svelte @@ -2,9 +2,9 @@ import {propEq, uniqBy, prop, sortBy} from 'ramda' import {onMount, onDestroy} from 'svelte' import {fly} from 'svelte/transition' + import {alerts} from 'src/state/app' import {findReply} from 'src/util/nostr' import relay, {people, user} from 'src/relay' - import {alerts} from 'src/state/app' import {now, timedelta, createScroller, Cursor, getLastSync} from 'src/util/misc' import Spinner from "src/partials/Spinner.svelte" import Note from 'src/partials/Note.svelte' @@ -23,7 +23,7 @@ onMount(async () => { sub = await relay.pool.listenForEvents( 'routes/Alerts', - [{kinds: [1, 7], '#p': [$user.pubkey], since: cursor.since}], + [{kinds: [1, 5, 7], '#p': [$user.pubkey], since: cursor.since}], onEvent ) @@ -51,6 +51,8 @@ relay.getOrLoadNote(replyId) } } + + alerts.set({since: now()}) } const loadNotes = async limit => { @@ -94,7 +96,6 @@ ) } - // Clear notification badge alerts.set({since: now()}) diff --git a/src/routes/RelayList.svelte b/src/routes/RelayList.svelte index fbd4e87f..2d7b79f0 100644 --- a/src/routes/RelayList.svelte +++ b/src/routes/RelayList.svelte @@ -3,25 +3,17 @@ import {fuzzy} from "src/util/misc" import Input from "src/partials/Input.svelte" import Anchor from "src/partials/Anchor.svelte" - import {modal} from "src/state/app" + import {modal, settings} from "src/state/app" import relay, {connections} from 'src/relay' let q = "" let search - const defaultRelays = [ - "wss://nostr.zebedee.cloud", - "wss://nostr-pub.wellorder.net", - "wss://relay.damus.io", - "wss://relay.grunch.dev", - "wss://nostr.sandwich.farm", - "wss://relay.nostr.ch", - "wss://nostr-relay.wlvs.space", - ] - - for (const url of defaultRelays) { - relay.db.relays.put({url}) - } + fetch($settings.dufflepudUrl + '/relay').then(r => r.json()).then(({relays}) => { + for (const url of relays) { + relay.db.relays.put({url}) + } + }) const knownRelays = relay.lq(() => relay.db.relays.toArray()) @@ -72,7 +64,7 @@
{/if} - {#each (search(q) || []).slice(0, 10) as r} + {#each (search(q) || []).slice(0, 50) as r} {#if !$connections.includes(r.url)}
@@ -85,6 +77,7 @@
{/if} {/each} + Found {($knownRelays || []).length} known relays
diff --git a/src/util/misc.js b/src/util/misc.js index bc420cf4..f014f2c1 100644 --- a/src/util/misc.js +++ b/src/util/misc.js @@ -89,7 +89,7 @@ export const createScroller = loadMore => { export const randomChoice = xs => xs[Math.floor(Math.random() * xs.length)] -export const getLastSync = (k, fallback) => { +export const getLastSync = (k, fallback = 0) => { const key = `${k}/lastSync` const lastSync = getLocalJson(key) || fallback