Add failure notification from relays

This commit is contained in:
SondreB 2023-04-07 21:36:41 +02:00
parent 981f22988a
commit 14ae68bb4d
No known key found for this signature in database
GPG Key ID: D6CC44C75005FDBF
5 changed files with 178 additions and 1 deletions

View File

@ -114,6 +114,13 @@ Thoughts and ideas:
- Validate the content of certain limit and don't render at all if content is too long, or at least cut the content and only render X length. Then allow users to manually retrieve
that exact event upon request.
Data Flow:
- Event received from relays... pushed into an event processor, which pushes events into individual services based upon the type.
- Individual services grabs existing event from StateService, if available, updates (if replaceable event or profile) or simply ignores. Maybe log "observed on relay".
- If not available, push into the StateService and schedule a database put.
- StateService should always keep some items in-memory: Profiles, Circles and more.
## Security
There are many ways a web app can be exploited when it allow user contributed content. Any and all measurements to avoid exploits should be done, like sanitizing the input.

View File

@ -435,3 +435,12 @@ export interface LNURLSuccessAction {
description?: string;
url?: string;
}
// export interface ProfileView {
// }
// export interface EventView {
// }

View File

@ -18,6 +18,8 @@ import { ArticleService } from './article';
import { LoggerService } from './logger';
import { BadgeService } from './badge';
import { ZapUiService } from './zap-ui';
import { StateService } from './state';
import { MatSnackBar } from '@angular/material/snack-bar';
@Injectable({
providedIn: 'root',
@ -57,7 +59,9 @@ export class RelayService {
private options: OptionsService,
private eventService: EventService,
private appState: ApplicationState,
private zapUi: ZapUiService
private zapUi: ZapUiService,
private stateService: StateService,
private snackBar: MatSnackBar
) {
// Whenever the visibility becomes visible, run connect to ensure we're connected to the relays.
this.appState.visibility$.subscribe((visible) => {
@ -417,6 +421,8 @@ export class RelayService {
this.logger.debug('SAVE EVENT?:', event);
this.stateService.addEvent(event);
if (event.kind == Kind.Zap) {
this.zapUi.addZap(event);
}
@ -656,6 +662,16 @@ export class RelayService {
const response = ev.data as RelayResponse;
switch (response.type) {
case 'failure':
this.logger.debug(`Relay ${url} failure: ${response.data}.`);
this.snackBar.open(`Failure: ${response.data}. (${url})`, 'Hide', {
duration: 3500,
horizontalPosition: 'center',
verticalPosition: 'bottom',
});
break;
case 'timeout':
this.logger.debug(`Relay ${url} timeout: ${response.data}.`);
this.setRelayTimeout(url, response.data);

144
src/app/services/state.ts Normal file
View File

@ -0,0 +1,144 @@
import { Injectable } from '@angular/core';
import { Kind } from 'nostr-tools';
import { Circle, NostrEvent, NostrProfileDocument } from './interfaces';
@Injectable({
providedIn: 'root',
})
export class StateService {
constructor(private state: State) {}
addEvent(event: NostrEvent) {
// TODO: Temporarily removed to avoid building massive in-memory state.
// switch (event.kind) {
// case Kind.Metadata:
// this.addIfNewer(event, this.state.events.shortTextNote);
// break;
// case Kind.Text:
// this.addIfMissing(event, this.state.events.shortTextNote);
// break;
// }
}
addIfMissing(event: NostrEvent, map: Map<string, NostrEvent>) {
if (map.has(event.id)) {
return;
}
map.set(event.id, event);
}
addIfNewer(event: NostrEvent, map: Map<string, NostrEvent>) {
if (!map.has(event.id)) {
map.set(event.id, event);
} else {
const existing = map.get(event.id);
if (existing!.created_at > event.created_at) {
return;
}
map.set(event.id, event);
}
}
}
@Injectable({
providedIn: 'root',
})
export class State {
profiles: NostrProfileDocument[] = [];
circles: Circle[] = [];
events: EventsState = {
metadata: new Map(),
shortTextNote: new Map(),
recommendRelay: new Map(),
contacts: new Map(),
encryptedDirectMessages: new Map(),
eventDeletion: new Map(),
reposts: new Map(),
reaction: new Map(),
badgeAward: new Map(),
channelCreation: new Map(),
channelMetadata: new Map(),
channelMessage: new Map(),
channelHideMessage: new Map(),
channelMuteUser: new Map(),
reporting: new Map(),
zapRequest: new Map(),
zap: new Map(),
muteList: new Map(),
relayListMetadata: new Map(),
clientAuthentication: new Map(),
nostrConnect: new Map(),
categorizedPeopleList: new Map(),
categorizedBookmarkList: new Map(),
profileBadges: new Map(),
badgeDefinition: new Map(),
longFormContent: new Map(),
applicationSpecificData: new Map(),
regularEvents: new Map(),
replaceableEvents: new Map(),
ephemeralEvents: new Map(),
parameterizedReplaceableEvents: new Map(),
};
relays: RelaysState = {
notice: new Map(),
auth: new Map(),
};
}
export interface EventsState {
metadata: Map<string, NostrEvent>; // 0
shortTextNote: Map<string, NostrEvent>; // 1
recommendRelay: Map<string, NostrEvent>; // 2
contacts: Map<string, NostrEvent>; // 3
encryptedDirectMessages: Map<string, NostrEvent>; // 4
eventDeletion: Map<string, NostrEvent>; // 5
reposts: Map<string, NostrEvent>; // 6
reaction: Map<string, NostrEvent>; // 7
badgeAward: Map<string, NostrEvent>; // 8
channelCreation: Map<string, NostrEvent>; // 40
channelMetadata: Map<string, NostrEvent>; // 41
channelMessage: Map<string, NostrEvent>; // 42
channelHideMessage: Map<string, NostrEvent>; // 43
channelMuteUser: Map<string, NostrEvent>; // 44
reporting: Map<string, NostrEvent>; // 1984
zapRequest: Map<string, NostrEvent>; // 9734
zap: Map<string, NostrEvent>; // 9735
muteList: Map<string, NostrEvent>; // 10000
relayListMetadata: Map<string, NostrEvent>; // 10002
clientAuthentication: Map<string, NostrEvent>; // 22242
nostrConnect: Map<string, NostrEvent>; // 24133
categorizedPeopleList: Map<string, NostrEvent>; // 30000
categorizedBookmarkList: Map<string, NostrEvent>; // 30001
profileBadges: Map<string, NostrEvent>; // 30008
badgeDefinition: Map<string, NostrEvent>; // 30009
longFormContent: Map<string, NostrEvent>; // 30023
applicationSpecificData: Map<string, NostrEvent>; // 30078
regularEvents: Map<string, NostrEvent>; // 1000-9999
replaceableEvents: Map<string, NostrEvent>; // 10000-19999
ephemeralEvents: Map<string, NostrEvent>; // 20000-29999
parameterizedReplaceableEvents: Map<string, NostrEvent>; // 30000-39999
}
export interface RelaysState {
notice: Map<string, NoticeItem>;
auth: Map<string, AuthItem>;
}
export interface NoticeItem {
relay: string;
notice: string;
timestamp: number;
}
// https://github.com/nostr-protocol/nips/blob/master/42.md
export interface AuthItem {
relay: string;
notice: string;
timestamp: number;
}

View File

@ -40,6 +40,7 @@ export class RelayWorker {
// });
pub.on('failed', (reason: any) => {
console.log(`failed to publish to ${this.relay.url}: ${reason}`);
postMessage({ type: 'failure', data: reason, url: this.relay.url } as RelayResponse);
});
}