Improve data loading and subscriptions

This commit is contained in:
SondreB 2023-01-06 17:36:49 +01:00
parent 4cee396689
commit 0cb83fed07
No known key found for this signature in database
GPG Key ID: D6CC44C75005FDBF
11 changed files with 110 additions and 42 deletions

View File

@ -165,8 +165,10 @@ export class AppComponent {
await this.profileService.populate();
await this.relayStorage.initialize();
await this.relayService.initialize();
await this.relayService.connect();
this.relayService.connect();
await this.feedService.initialize();
// This service will perform data cleanup, etc.

View File

@ -136,7 +136,7 @@ export class HomeComponent {
async follow(profile: DefaultProfile) {
if (profile.checked) {
await this.profileService.follow(profile.pubkeyhex, undefined, profile as any);
await this.feedService.downloadRecent([profile.pubkeyhex]);
this.feedService.downloadRecent([profile.pubkeyhex]);
// Perform a detected changes now, since 'profileService.profiles.length' should be updated.
this.#defaultsChanged.next(this.defaults);
@ -164,7 +164,7 @@ export class HomeComponent {
// await this.profileService.follow(pubKeys[i].pubkeyhex, undefined, pubKeys[i] as any);
// }
// await this.feedService.downloadRecent(pubKeys.map((p) => p.pubkeyhex));
// this.feedService.downloadRecent(pubKeys.map((p) => p.pubkeyhex));
// // Perform a detected changes now, since 'profileService.profiles.length' should be updated.
// this.cd.detectChanges();

View File

@ -92,9 +92,9 @@
<span>
<div class="events-header">
<app-event-header [pubkey]="event.pubkey"
><span class="event-date clickable">{{ event.created_at | ago }}</span> <app-directory-icon [pubkey]="event.pubkey"></app-directory-icon
></app-event-header>
<app-event-actions [event]="event" [pubkey]="event.pubkey"></app-event-actions>
><span class="event-date clickable">{{ event.created_at | ago }}</span> <app-directory-icon [pubkey]="event.pubkey"></app-directory-icon
></app-event-header>
<app-event-actions [event]="event" [pubkey]="event.pubkey"></app-event-actions>
</div>
<app-content [event]="event"></app-content>
<!-- <div class="content">{{ event.content }}<span *ngIf="event.contentCut">... (message was truncated)</span></div> -->

View File

@ -128,7 +128,7 @@ export class PeopleComponent {
pubkey = this.utilities.ensureHexIdentifier(pubkey);
await this.profileService.follow(pubkey);
await this.feedService.downloadRecent([pubkey]);
this.feedService.downloadRecent([pubkey]);
}
createFollow(): void {

View File

@ -88,7 +88,6 @@ export class DataService {
downloadProfile(pubkey: string) {
if (!pubkey) {
debugger;
return;
}

View File

@ -492,14 +492,15 @@ export class FeedService {
// this.relayStorage.list();
}
async downloadRecent(pubkeys: string[]) {
/** Download the recent events by the specified pubkeys and then disconnects the subscription. */
downloadRecent(pubkeys: string[]) {
console.log('DOWNLOAD RECENT FOR:', pubkeys);
const relay = this.relayService.relays[0];
const backInTime = moment().subtract(12, 'hours').unix();
// const backInTime = moment().subtract(12, 'hours').unix();
// Start subscribing to our people feeds.
const sub = relay.sub([{ kinds: [1], since: backInTime, authors: pubkeys }], {}) as NostrSubscription;
// Start subscribing to our people feeds. // since: backInTime
const sub = relay.sub([{ kinds: [1], limit: 1000, authors: pubkeys }], {}) as NostrSubscription;
sub.loading = true;
@ -519,6 +520,7 @@ export class FeedService {
sub.on('eose', () => {
// console.log('Initial load of people feed completed.');
sub.loading = false;
sub.unsub();
});
}

View File

@ -97,7 +97,7 @@ export class ProfileService {
this.#profileRequested.next(pubkey);
}
async downloadRecent(pubkey: string) {
downloadRecent(pubkey: string) {
this.#profileRequested.next(pubkey);
}

View File

@ -19,11 +19,13 @@ import { ApplicationState } from './applicationstate.service';
export class RelayService {
/** Default relays that the app has for users without extension. This follows the document structure as extension data. */
defaultRelays: any = {
'wss://relay.nostr.info': { read: true, write: true },
// 'wss://relay.damus.io': { read: true, write: false },
'wss://nostr-pub.wellorder.net': { read: true, write: true },
// 'wss://relay.nostr.info': { read: true, write: true },
'wss://nostr.nordlysln.net': { read: true, write: true },
'wss://relay.damus.io': { read: true, write: false },
'wss://relay.nostr.ch': { read: true, write: true },
'wss://nostr.v0l.io': { read: true, write: true },
'wss://nostr-relay.wlvs.space': { read: true, write: true },
};
#table;
@ -47,6 +49,8 @@ export class RelayService {
sortOrder: 'asc' | 'desc' = 'asc';
subs: Sub[] = [];
/** These are relay instances that have connection over WebSocket and holds a reference to database metadata for the relay. */
relays: NostrRelay[] = [];
#relaysChanged: BehaviorSubject<NostrRelay[]> = new BehaviorSubject<NostrRelay[]>(this.relays);
@ -188,6 +192,24 @@ export class RelayService {
this.connect();
}
});
// Every time the list of profiles changes, we will re-sub to have a single subscription against all following:
this.profileService.profilesChanged$.subscribe(() => {
console.log('profilesChanged$!!!, SUBSCRIBE TO FOLLOWING!');
for (let i = 0; i < this.relays.length; i++) {
this.subscribeToFollowing(this.relays[i]);
}
});
}
getActiveRelay(url: string) {
const index = this.relays.findIndex((r) => r.url == url);
if (index == -1) {
return null;
} else {
return this.relays[index];
}
}
/** Add an in-memory instance of relay and get stored metadata for it. */
@ -340,7 +362,12 @@ export class RelayService {
await this.relayStorage.delete(url);
const relayIndex = this.relays.findIndex((r) => r.url == url);
this.relays.splice(relayIndex, 1);
let existingRelayInstance = this.relays.splice(relayIndex, 1);
// Disconnect from the relay when we delete it.
if (existingRelayInstance.length > 0) {
existingRelayInstance[0].close();
}
this.relaysUpdated();
}
@ -378,6 +405,13 @@ export class RelayService {
}
async #connectToRelay(server: NostrRelayDocument, onConnected: any) {
const existingActiveRelay = this.getActiveRelay(server.id);
// If the relay already exists, just return that and do nothing else.
if (existingActiveRelay) {
onConnected(existingActiveRelay);
}
// const relay = relayInit('wss://relay.nostr.info');
const relay = relayInit(server.id) as NostrRelay;
@ -395,11 +429,16 @@ export class RelayService {
console.log(`NOTICE FROM ${relay?.url}`);
});
relay.connect();
// Keep a reference of the metadata on the relay instance.
relay.metadata = server;
try {
await relay.connect();
} catch (err) {
console.log(err);
relay.metadata.error = 'Unable to connect.';
}
await this.addRelay(relay);
return relay;
@ -412,40 +451,66 @@ export class RelayService {
// When finished, trigger an observable that we are connected.
this.appState.connected(true);
const authors = this.profileService.profiles.map((p) => p.pubkey);
this.subscribeToFollowing(relay);
});
}
// Append ourself to the authors list so we receive everything we publish to any relay.
authors.push(this.appState.getPublicKey());
subscriptions: any = {};
const backInTime = moment().subtract(120, 'minutes').unix();
/** Subscribes to the following on the specific relay. */
subscribeToFollowing(relay: Relay) {
const authors = this.profileService.profiles.map((p) => p.pubkey);
// Start subscribing to our people feeds.
const sub = relay.sub([{ kinds: [1], since: backInTime, authors: authors }], {}) as NostrSubscription;
// Append ourself to the authors list so we receive everything we publish to any relay.
authors.push(this.appState.getPublicKey());
sub.loading = true;
// TODO: We must store last time user closed the application and use that as back in time value.
// const backInTime = moment().subtract(5, 'days').unix();
// Keep all subscriptions around so we can close them when needed.
this.subs.push(sub);
// Start subscribing to our people feeds. // since: backInTime,
// TODO: MAYBE WE SHOULD UNSUB AND SUB AGAIN, OR WILL THIS OVERRIDE EXISTING SUB?!
sub.on('event', (originalEvent: any) => {
const event = this.eventService.processEvent(originalEvent);
const filters = authors.map((a) => {
return { kinds: [1], limit: 500, authors: [a] };
});
if (!event) {
return;
}
const sub = relay.sub(filters, {}) as NostrSubscription;
this.#persist(event);
});
// If we are still waiting for "loading" after 30 seconds, retry the subscription.
setTimeout(() => {
console.log('Subscription Timeout Protection was triggered.', sub.loading);
sub.on('eose', () => {
// console.log('Initial load of people feed completed.');
sub.loading = false;
});
if (sub.loading) {
console.log('Unsubbing and restarting subscription.', relay);
sub.unsub();
this.subscribeToFollowing(relay);
}
}, 5 * 60 * 1000);
sub.loading = true;
// Keep all subscriptions around so we can close them when needed.
this.subs.push(sub);
sub.on('event', (originalEvent: any) => {
const event = this.eventService.processEvent(originalEvent);
if (!event) {
return;
}
this.#persist(event);
});
sub.on('eose', () => {
console.log('Initial load of people feed completed.');
sub.loading = false;
});
}
async initialize() {
if (this.relays.length === 0) {
// If there are no relay metatadata in database, get it from extension or default
if (this.relayStorage.items.length === 0) {
let relays;
try {

View File

@ -56,7 +56,7 @@ export class EventActionsComponent {
// If not already following, add a full follow and download recent:
if (!this.profile.follow) {
await this.profileService.follow(this.profile.pubkey, circle);
await this.feedService.downloadRecent([this.profile.pubkey]);
this.feedService.downloadRecent([this.profile.pubkey]);
} else {
// If we already follow but just change the circle, do a smaller operation.
await this.profileService.setCircle(this.profile.pubkey, circle);

View File

@ -56,7 +56,7 @@ export class ProfileActionsComponent {
// If not already following, add a full follow and download recent:
if (!this.profile.follow) {
await this.profileService.follow(this.profile.pubkey, circle);
await this.feedService.downloadRecent([this.profile.pubkey]);
this.feedService.downloadRecent([this.profile.pubkey]);
} else {
// If we already follow but just change the circle, do a smaller operation.
await this.profileService.setCircle(this.profile.pubkey, circle);

View File

@ -126,7 +126,7 @@ export class UserComponent {
async follow() {
this.profile!.follow = true;
await this.profiles.follow(this.pubkey!);
await this.feedService.downloadRecent([this.pubkey!]);
this.feedService.downloadRecent([this.pubkey!]);
}
tabIndex?: number;