From ab5be712ed1f08bbc381454cf01114406897f43c Mon Sep 17 00:00:00 2001 From: A Hannigan Date: Mon, 8 May 2023 12:33:40 +0100 Subject: [PATCH] Show warning if no relays readable. Relay connection indicator in status bar. Note times are no longer static. --- app.go | 48 ++++++++++++++++++++++++++---- frontend/package-lock.json | 6 ++++ frontend/package.json | 1 + frontend/package.json.md5 | 2 +- frontend/src/App.svelte | 48 +++++++++++++++++++++--------- frontend/src/EventDialog.svelte | 3 +- frontend/src/EventInfo.svelte | 4 ++- frontend/src/EventPost.svelte | 17 +++++++++-- frontend/src/FindContact.svelte | 3 +- frontend/src/FindEvent.svelte | 3 +- frontend/src/Follow.svelte | 2 +- frontend/src/GenKeys.svelte | 3 +- frontend/src/Login.svelte | 3 +- frontend/src/MessageDialog.svelte | 3 +- frontend/src/PinDialog.svelte | 5 ++-- frontend/src/Post.svelte | 4 +-- frontend/src/ProfileCard.svelte | 8 ++--- frontend/src/Relays.svelte | 6 +++- frontend/src/Reply.svelte | 4 +-- frontend/src/StatusBar.svelte | 34 +++++++++++++++++++++ frontend/src/SuggestFollows.svelte | 3 +- frontend/wailsjs/go/main/App.d.ts | 6 ++++ frontend/wailsjs/go/main/App.js | 12 ++++++++ go.mod | 1 - go.sum | 2 -- relay.go | 12 ++++++++ relaypool.go | 17 +++-------- 27 files changed, 200 insertions(+), 60 deletions(-) create mode 100644 frontend/src/StatusBar.svelte diff --git a/app.go b/app.go index f1e00c8..fb37d02 100644 --- a/app.go +++ b/app.go @@ -6,7 +6,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/dustin/go-humanize" "github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr/nip19" "github.com/rs/zerolog" @@ -64,6 +63,16 @@ func (a *App) startup(ctx context.Context) { } } } + + // Maintenance loop + go func() { + for { + a.CheckRelays() + a.PingTimer() + time.Sleep(time.Second * 10) + } + }() + log.Info().Msg("...start up done") } @@ -128,6 +137,7 @@ func (a *App) OnDomReady(ctx context.Context) { }() } } + a.CheckRelays() } func (a *App) BeginSubscriptions() { @@ -348,10 +358,20 @@ func (a *App) GetContactProfile(pk string) *Profile { } } +func (a *App) GetReadableRelays() []*string { + rs := []*string{} + for _, r := range a.relayPool.pool { + if r.Enabled && r.Read && (r.conn.ConnectionError == nil) { + rs = append(rs, &r.Url) + } + } + return rs +} + func (a *App) GetWritableRelays() []*string { rs := []*string{} for _, r := range a.relayPool.pool { - if r.Enabled && r.Write { + if r.Enabled && r.Write && (r.conn.ConnectionError == nil) { rs = append(rs, &r.Url) } } @@ -389,7 +409,6 @@ func (a *App) GetTextNotesForPubkeys(pks []string, postEvent string, repost bool ch := make(chan *nostr.Event) go func() { for ev := range ch { - ev.SetExtra("when", humanize.Time(ev.CreatedAt.Time())) existingEvent := db.GetEvent(ev.ID) db.AddEvent(ev.ID, ev) if existingEvent == nil || repost { @@ -415,7 +434,6 @@ func (a *App) SubscribeToFeedForPubkeys(pks []string, repost bool) { ch1 := make(chan *nostr.Event) go func() { for ev := range ch { - ev.SetExtra("when", humanize.Time(ev.CreatedAt.Time())) existingEvent := db.GetEvent(ev.ID) db.AddEvent(ev.ID, ev) if existingEvent == nil || repost { @@ -425,7 +443,6 @@ func (a *App) SubscribeToFeedForPubkeys(pks []string, repost bool) { }() go func() { for ev := range ch1 { - ev.SetExtra("when", humanize.Time(ev.CreatedAt.Time())) existingEvent := db.GetEvent(ev.ID) db.AddEvent(ev.ID, ev) if existingEvent == nil || repost { @@ -456,7 +473,6 @@ func (a *App) GetTextNotesByEventIds(ids []string) []*nostr.Event { ch := make(chan *nostr.Event) go func() { for ev := range ch { - ev.SetExtra("when", humanize.Time(ev.CreatedAt.Time())) db.AddEvent(ev.ID, ev) events = append(events, ev) } @@ -790,3 +806,23 @@ func (a *App) SaveProfile(metadata ProfileMetadata) error { a.PostEvent(nostr.KindSetMetadata, nostr.Tags{}, string(content)) return nil } + +func (a *App) CheckRelays() { + readable := a.GetReadableRelays() + writable := a.GetWritableRelays() + numSubs := 0 + for _, url := range readable { + relay := a.relayPool.GetRelayByUrl(*url) + numSubs += len(relay.subs) + } + + opts := make(map[string]int) + opts["readable"] = len(readable) + opts["writable"] = len(writable) + opts["subs"] = numSubs + runtime.EventsEmit(a.ctx, "evRelayStatus", opts) +} + +func (a *App) PingTimer() { + runtime.EventsEmit(a.ctx, "evTimer", time.Now().UnixMilli()) +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4029345..564bece 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "frontend", "version": "0.0.0", "dependencies": { + "humanize-duration": "^3.28.0", "lodash": "^4.17.21" }, "devDependencies": { @@ -484,6 +485,11 @@ "node": ">= 0.4.0" } }, + "node_modules/humanize-duration": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.28.0.tgz", + "integrity": "sha512-jMAxraOOmHuPbffLVDKkEKi/NeG8dMqP8lGRd6Tbf7JgAeG33jjgPWDbXXU7ypCI0o+oNKJFgbSB9FKVdWNI2A==" + }, "node_modules/is-core-module": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 0c54bf0..e916a12 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "vite": "^3.0.0" }, "dependencies": { + "humanize-duration": "^3.28.0", "lodash": "^4.17.21" } } diff --git a/frontend/package.json.md5 b/frontend/package.json.md5 index 6b72465..44201da 100755 --- a/frontend/package.json.md5 +++ b/frontend/package.json.md5 @@ -1 +1 @@ -85d34d58ecc427335e7de2b1f57c5e5b \ No newline at end of file +ce91643ecdbb4e57cab88302cac35cc1 \ No newline at end of file diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 15dc632..59708ce 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -5,6 +5,7 @@ * caught, the user icon set, contacts refreshed and the feed loaded. */ + import {EventsOn} from "../wailsjs/runtime/runtime.js"; import Follow from "./Follow.svelte"; import EventPost from "./EventPost.svelte"; import { @@ -17,7 +18,8 @@ GetContactProfile, SaveContacts, RestoreContacts, - BeginSubscriptions + BeginSubscriptions, + GetReadableRelays } from '../wailsjs/go/main/App.js' import { contactStore } from './ContactStore.js' import { eventStore, sortedEvents } from "./EventStore.js"; @@ -25,6 +27,7 @@ import loadingGif from "./assets/images/loading.gif"; import Dialogs from "./Dialogs.svelte"; import {EventsEmit} from "../wailsjs/runtime/runtime.js"; + import StatusBar from "./StatusBar.svelte"; let pendingNotes = []; let myPk = false; @@ -35,13 +38,28 @@ let autoRefresh = false; const onPkChange = (pk) => { + GetReadableRelays().then((relays)=>{ + if(relays.length === 0) { + EventsEmit("evMessageDialog", { + title: "No Available Relays", + message: "No relays able to read from the network. Click OK to configure, or cancel", + iconClass: "bi-exclamation-circle", + cancelable: true, + callback: ()=>{ + console.log("Callback..."); + EventsEmit("evRelayDialog"); + } + }); + } + }); + myPk = pk; GetContactProfile(pk).then((p)=>{ myProfile = p; BeginSubscriptions(); }); } - window.runtime.EventsOn('evPkChange', onPkChange); + EventsOn('evPkChange', onPkChange); const onRefreshNote = (event) => { if(autoRefresh) { @@ -51,12 +69,12 @@ pendingNotes = pendingNotes; } } - window.runtime.EventsOn('evRefreshNote', onRefreshNote); + EventsOn('evRefreshNote', onRefreshNote); const onFollowEventNote = (event) => { addOrUpdateEvent(event); } - window.runtime.EventsOn('evFollowEventNote', onFollowEventNote); + EventsOn('evFollowEventNote', onFollowEventNote); const addOrUpdateEvent = (event) => { let ev = getEventIndex(event); @@ -71,11 +89,9 @@ for(let a = 0; a < $sortedEvents.length; a++) { let c = $sortedEvents[a]; if(c.id === event.id) { - console.log("Got event index " + a); return a; } } - console.log("Got event index -1"); return -1 } @@ -105,7 +121,7 @@ $contactStore.push(profile); } } - window.runtime.EventsOn('evMetadata', onMetadata); + EventsOn('evMetadata', onMetadata); const refreshFeed = () => { if(pendingNotes.length > 0 && !filtering) { @@ -124,16 +140,16 @@ $contactStore = []; RefreshContactProfiles(); } - window.runtime.EventsOn('evRefreshContacts', onRefreshContacts); + EventsOn('evRefreshContacts', onRefreshContacts); const launchPostDialog = () => { - window.runtime.EventsEmit("evPostDialog"); + EventsEmit("evPostDialog"); } const launchRelayDialog = () => { - window.runtime.EventsEmit("evRelayDialog"); + EventsEmit("evRelayDialog"); } const launchSearchContact = () => { - window.runtime.EventsEmit("evFindContactDialog"); + EventsEmit("evFindContactDialog"); } const actionQuit = (e) => { @@ -143,7 +159,7 @@ const launchProfileCard = () => { GetMyPubkey().then((pk)=>{ GetContactProfile(pk).then((p)=>{ - window.runtime.EventsEmit("evProfileCard", p); + EventsEmit("evProfileCard", p); }); }); } @@ -164,7 +180,7 @@ eventStore.deleteAll(); GetTextNotesForPubkeys([profile.pk], "evFollowEventNote", true); } - window.runtime.EventsOn('evFilterByProfile', onFilterByProfile); + EventsOn('evFilterByProfile', onFilterByProfile); const resetFilterAndRefresh = () => { filtering = false; @@ -356,7 +372,11 @@ -
+
+ +
+ +
diff --git a/frontend/src/EventDialog.svelte b/frontend/src/EventDialog.svelte index b9354b7..93e7b26 100644 --- a/frontend/src/EventDialog.svelte +++ b/frontend/src/EventDialog.svelte @@ -5,6 +5,7 @@ */ import {GetMyPubkey, GetTextNotesByEventIds, Nip19Decode} from "../wailsjs/go/main/App.js"; + import {EventsOn} from "../wailsjs/runtime/runtime.js"; import EventPost from "./EventPost.svelte"; let myPk; @@ -35,7 +36,7 @@ }); } - window.runtime.EventsOn('evEventDialog', onEventDialog); + EventsOn('evEventDialog', onEventDialog); diff --git a/frontend/src/EventInfo.svelte b/frontend/src/EventInfo.svelte index 9b29c1c..bc284dc 100644 --- a/frontend/src/EventInfo.svelte +++ b/frontend/src/EventInfo.svelte @@ -1,4 +1,6 @@ diff --git a/frontend/src/EventPost.svelte b/frontend/src/EventPost.svelte index e6a3cef..78c57b1 100644 --- a/frontend/src/EventPost.svelte +++ b/frontend/src/EventPost.svelte @@ -6,7 +6,7 @@ * The note text is parsed for links, images and nostr: links. */ - import {EventsEmit} from "../wailsjs/runtime/runtime.js"; + import {EventsEmit, EventsOn} from "../wailsjs/runtime/runtime.js"; import { GetTaggedProfiles, GetTaggedEvents, @@ -18,6 +18,7 @@ import LookupPk from "./LookupPk.svelte"; import LookupEvent from "./LookupEvent.svelte"; import loadingGif from "./assets/images/loading.gif" + import humanizeDuration from "humanize-duration" export let event; @@ -27,6 +28,16 @@ let showWaiting = false; let notFound = false; + const getWhen = (millis) => { + return humanizeDuration(Math.floor(millis - event.created_at*1000), { round: true, units: ["y", "mo", "d", "h", "m"] }); + } + let when = getWhen(Date.now()); + + const updateWhen = (now) => { + when = getWhen(now) + } + EventsOn("evTimer", updateWhen); + const parseContent = (txt) => { return imageParse(newlineParse(httpLinkParse(nostrNpubLinkParse(nostrEventLinkParse(txt))))); } @@ -147,7 +158,7 @@ } const openReplyDialog = (ev) => { - window.runtime.EventsEmit("evReplyDialog", ev); + EventsEmit("evReplyDialog", ev); } @@ -161,7 +172,7 @@
{getDisplayName(p)} - {event.when} + {when} ago
profileCard(p)}> diff --git a/frontend/src/FindContact.svelte b/frontend/src/FindContact.svelte index 38f0b72..091147e 100644 --- a/frontend/src/FindContact.svelte +++ b/frontend/src/FindContact.svelte @@ -6,6 +6,7 @@ import { Nip19Decode, GetContactProfile } from "../wailsjs/go/main/App.js"; import { EventsEmit } from "../wailsjs/runtime/runtime.js"; + import {EventsOn} from "../wailsjs/runtime/runtime.js"; let input; @@ -16,7 +17,7 @@ document.getElementById('searchContact').focus(); }, 500); } - window.runtime.EventsOn('evFindContactDialog', onFindContactDialog); + EventsOn('evFindContactDialog', onFindContactDialog); async function getProfile(pk) { return await GetContactProfile(pk); diff --git a/frontend/src/FindEvent.svelte b/frontend/src/FindEvent.svelte index a83c9fc..7d3d28a 100644 --- a/frontend/src/FindEvent.svelte +++ b/frontend/src/FindEvent.svelte @@ -6,6 +6,7 @@ import { Nip19Decode } from "../wailsjs/go/main/App.js"; import { EventsEmit } from "../wailsjs/runtime/runtime.js"; + import {EventsOn} from "../wailsjs/runtime/runtime.js"; const onFindEventDialog = () => { document.getElementById('launchFindEventDialog').click(); @@ -13,7 +14,7 @@ document.getElementById('findEvent').focus(); }, 500); } - window.runtime.EventsOn('evFindEventDialog', onFindEventDialog); + EventsOn('evFindEventDialog', onFindEventDialog); const showError = (msg) => { diff --git a/frontend/src/Follow.svelte b/frontend/src/Follow.svelte index d8770eb..1bce923 100644 --- a/frontend/src/Follow.svelte +++ b/frontend/src/Follow.svelte @@ -18,7 +18,7 @@ } const filter = () => { - window.runtime.EventsEmit("evFilterByProfile", profile); + EventsEmit("evFilterByProfile", profile); } const copyPubkey = () => { diff --git a/frontend/src/GenKeys.svelte b/frontend/src/GenKeys.svelte index dbec090..4821599 100644 --- a/frontend/src/GenKeys.svelte +++ b/frontend/src/GenKeys.svelte @@ -6,13 +6,14 @@ import {GenerateKeys, SaveNewKeys } from "../wailsjs/go/main/App.js"; import {EventsEmit} from "../wailsjs/runtime/runtime.js"; + import {EventsOn} from "../wailsjs/runtime/runtime.js"; let enableSave = true; const onGenkeysDialog = () => { document.getElementById('launchGenKeysDialog').click(); } - window.runtime.EventsOn('evGenkeysDialog', onGenkeysDialog); + EventsOn('evGenkeysDialog', onGenkeysDialog); const showError = (msg) => { let d = document.getElementById("getKeysErrorMessage"); diff --git a/frontend/src/Login.svelte b/frontend/src/Login.svelte index 240ba57..4afb55c 100644 --- a/frontend/src/Login.svelte +++ b/frontend/src/Login.svelte @@ -7,11 +7,12 @@ import {Nip19Decode, SetLoginWithPrivKey} from "../wailsjs/go/main/App.js"; import {EventsEmit} from "../wailsjs/runtime/runtime.js"; + import {EventsOn} from "../wailsjs/runtime/runtime.js"; const onLoginDialog = () => { document.getElementById('launchLoginDialog').click(); } - window.runtime.EventsOn('evLoginDialog', onLoginDialog); + EventsOn('evLoginDialog', onLoginDialog); const showError = (msg) => { let d = document.getElementById("loginErrorMessage"); diff --git a/frontend/src/MessageDialog.svelte b/frontend/src/MessageDialog.svelte index 5387d33..2e275eb 100644 --- a/frontend/src/MessageDialog.svelte +++ b/frontend/src/MessageDialog.svelte @@ -2,6 +2,7 @@ /** * A helper modal dialog for displaying error/info messages and getting confirmation. */ + import {EventsOn} from "../wailsjs/runtime/runtime.js"; let title = ""; let message = ""; @@ -20,7 +21,7 @@ document.getElementById('launchMessageDialog').click(); } - window.runtime.EventsOn('evMessageDialog', onMessageDialog); + EventsOn('evMessageDialog', onMessageDialog); const confirmed = () => { if(callback && typeof(callback) === "function" ) { diff --git a/frontend/src/PinDialog.svelte b/frontend/src/PinDialog.svelte index 28611a9..3cc6f50 100644 --- a/frontend/src/PinDialog.svelte +++ b/frontend/src/PinDialog.svelte @@ -5,6 +5,7 @@ */ import {LoginWithPin} from "../wailsjs/go/main/App.js"; + import {EventsOn} from "../wailsjs/runtime/runtime.js"; const onPinDialog = () => { document.getElementById('launchPinDialog').click(); @@ -13,7 +14,7 @@ document.getElementById('pin').focus(); }, 500); } - window.runtime.EventsOn('evPinDialog', onPinDialog); + EventsOn('evPinDialog', onPinDialog); const showError = (msg) => { let d = document.getElementById("pinDialogErrorMessage"); @@ -40,7 +41,7 @@ } const resetAccount = () => { - window.runtime.EventsEmit("evLoginDialog"); + EventsEmit("evLoginDialog"); } diff --git a/frontend/src/Post.svelte b/frontend/src/Post.svelte index 274471a..3659490 100644 --- a/frontend/src/Post.svelte +++ b/frontend/src/Post.svelte @@ -13,7 +13,7 @@ PublishContentToSelectedRelays, GetContactProfile } from "../wailsjs/go/main/App.js"; - import {EventsEmit} from "../wailsjs/runtime/runtime.js"; + import {EventsEmit, EventsOn} from "../wailsjs/runtime/runtime.js"; import {contactStore} from "./ContactStore"; let promise; @@ -23,7 +23,7 @@ promise = GetWritableRelays(); document.getElementById('postForm').focus(); } - window.runtime.EventsOn('evPostDialog', onPostDialog); + EventsOn('evPostDialog', onPostDialog); const showError = (msg) => { let d = document.getElementById("postErrorMessage"); diff --git a/frontend/src/ProfileCard.svelte b/frontend/src/ProfileCard.svelte index 3006b86..c8b19ca 100644 --- a/frontend/src/ProfileCard.svelte +++ b/frontend/src/ProfileCard.svelte @@ -6,7 +6,7 @@ */ import {FollowContact, UnfollowContact, GetContactProfile, GetMyPubkey, SaveProfile} from "../wailsjs/go/main/App.js"; - import {EventsEmit} from "../wailsjs/runtime/runtime.js"; + import {EventsEmit, EventsOn} from "../wailsjs/runtime/runtime.js"; let id = ""; let npub = ""; @@ -48,14 +48,14 @@ banner = profile.meta.banner || ""; following = profile.following; } - window.runtime.EventsOn('evProfileCard', onProfileCard); + EventsOn('evProfileCard', onProfileCard); const onProfilePk = (pk) => { GetContactProfile(pk).then((p)=>{ EventsEmit("evProfileCard", p); }) } - window.runtime.EventsOn('evProfileCardPk', onProfilePk); + EventsOn('evProfileCardPk', onProfilePk); const followContact = (pk) => { FollowContact([pk]).then((err) => { @@ -70,7 +70,7 @@ } const filter = () => { - window.runtime.EventsEmit("evFilterByProfile", prof); + EventsEmit("evFilterByProfile", prof); } const changeCheck = (e) => { diff --git a/frontend/src/Relays.svelte b/frontend/src/Relays.svelte index a9bcee8..ee07271 100644 --- a/frontend/src/Relays.svelte +++ b/frontend/src/Relays.svelte @@ -8,14 +8,17 @@ import {GetRelays, SetRelays} from "../wailsjs/go/main/App.js"; + import {EventsOn} from "../wailsjs/runtime/runtime.js"; + let relays = []; const onRelayDialog = () => { GetRelays().then((r) => { relays = r; }); + document.getElementById('launchRelayDialog').click(); } - window.runtime.EventsOn('evRelayDialog', onRelayDialog); + EventsOn('evRelayDialog', onRelayDialog); const showError = (msg) => { let d = document.getElementById("relayErrorMessage"); @@ -83,6 +86,7 @@ +