bug: improve relay handeling

This commit is contained in:
2023-01-26 10:48:21 +00:00
parent bb8f6bd070
commit 64b28263d6
8 changed files with 39 additions and 17 deletions

View File

@ -19,9 +19,7 @@ export const ProfileCacheExpire = (1_000 * 60 * 5);
* Default bootstrap relays * Default bootstrap relays
*/ */
export const DefaultRelays = new Map<string, RelaySettings>([ export const DefaultRelays = new Map<string, RelaySettings>([
["wss://relay.snort.social", { read: true, write: true }], ["wss://relay.snort.social", { read: true, write: true }]
["wss://relay.damus.io", { read: true, write: true }],
["wss://nostr-pub.wellorder.net", { read: true, write: true }],
]); ]);
/** /**

View File

@ -63,7 +63,7 @@ export default function Relay(props: RelayProps) {
<FontAwesomeIcon icon={faPlugCircleXmark} /> {state?.disconnects} <FontAwesomeIcon icon={faPlugCircleXmark} /> {state?.disconnects}
</div> </div>
<div> <div>
<span className="icon-btn" onClick={() => navigate(name)}> <span className="icon-btn" onClick={() => navigate(state!.id)}>
<FontAwesomeIcon icon={faGear} /> <FontAwesomeIcon icon={faGear} />
</span> </span>
</div> </div>

View File

@ -13,7 +13,7 @@ declare global {
nostr: { nostr: {
getPublicKey: () => Promise<HexKey>, getPublicKey: () => Promise<HexKey>,
signEvent: (event: RawEvent) => Promise<RawEvent>, signEvent: (event: RawEvent) => Promise<RawEvent>,
getRelays: () => Promise<[[string, { read: boolean, write: boolean }]]>, getRelays: () => Promise<Record<string, { read: boolean, write: boolean }>>,
nip04: { nip04: {
encrypt: (pubkey: HexKey, content: string) => Promise<string>, encrypt: (pubkey: HexKey, content: string) => Promise<string>,
decrypt: (pubkey: HexKey, content: string) => Promise<string> decrypt: (pubkey: HexKey, content: string) => Promise<string>

View File

@ -29,10 +29,12 @@ export type StateSnapshot = {
received: number, received: number,
send: number send: number
}, },
info?: RelayInfo info?: RelayInfo,
id: string
}; };
export default class Connection { export default class Connection {
Id: string;
Address: string; Address: string;
Socket: WebSocket | null; Socket: WebSocket | null;
Pending: Subscriptions[]; Pending: Subscriptions[];
@ -50,6 +52,7 @@ export default class Connection {
EventsCallback: Map<u256, () => void>; EventsCallback: Map<u256, () => void>;
constructor(addr: string, options: RelaySettings) { constructor(addr: string, options: RelaySettings) {
this.Id = uuid();
this.Address = addr; this.Address = addr;
this.Socket = null; this.Socket = null;
this.Pending = []; this.Pending = [];
@ -285,6 +288,7 @@ export default class Connection {
this.CurrentState.avgLatency = this.Stats.Latency.length > 0 ? (this.Stats.Latency.reduce((acc, v) => acc + v, 0) / this.Stats.Latency.length) : 0; this.CurrentState.avgLatency = this.Stats.Latency.length > 0 ? (this.Stats.Latency.reduce((acc, v) => acc + v, 0) / this.Stats.Latency.length) : 0;
this.CurrentState.disconnects = this.Stats.Disconnects; this.CurrentState.disconnects = this.Stats.Disconnects;
this.CurrentState.info = this.Info; this.CurrentState.info = this.Info;
this.CurrentState.id = this.Id;
this.Stats.Latency = this.Stats.Latency.slice(-20); // trim this.Stats.Latency = this.Stats.Latency.slice(-20); // trim
this.HasStateChange = true; this.HasStateChange = true;
this._NotifyState(); this._NotifyState();

View File

@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom";
import * as secp from '@noble/secp256k1'; import * as secp from '@noble/secp256k1';
import { RootState } from "State/Store"; import { RootState } from "State/Store";
import { setPrivateKey, setPublicKey } from "State/Login"; import { setPrivateKey, setPublicKey, setRelays } from "State/Login";
import { EmailRegex } from "Const"; import { EmailRegex } from "Const";
import { bech32ToHex } from "Util"; import { bech32ToHex } from "Util";
import { HexKey } from "Nostr"; import { HexKey } from "Nostr";
@ -72,7 +72,12 @@ export default function LoginPage() {
async function doNip07Login() { async function doNip07Login() {
let pubKey = await window.nostr.getPublicKey(); let pubKey = await window.nostr.getPublicKey();
let relays = await window.nostr.getRelays();
dispatch(setPublicKey(pubKey)); dispatch(setPublicKey(pubKey));
dispatch(setRelays({
relays: relays,
createdAt: 1
}));
} }
function altLogins() { function altLogins() {

View File

@ -30,7 +30,7 @@ export const SettingsRoutes: RouteObject[] = [
element: <Relay />, element: <Relay />,
}, },
{ {
path: "relays/:addr", path: "relays/:id",
element: <RelayInfo /> element: <RelayInfo />
}, },
{ {

View File

@ -10,16 +10,16 @@ const RelayInfo = () => {
const params = useParams(); const params = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
const addr: string = `wss://${params.addr}`;
const con = System.Sockets.get(addr) ?? System.Sockets.get(`${addr}/`); const conn = Array.from(System.Sockets.values()).find(a => a.Id === params.id);
const stats = useRelayState(con?.Address ?? addr); console.debug(conn);
const stats = useRelayState(conn?.Address ?? "");
return ( return (
<> <>
<h3 className="pointer" onClick={() => navigate("/settings/relays")}>Relays</h3> <h3 className="pointer" onClick={() => navigate("/settings/relays")}>Relays</h3>
<div className="card"> <div className="card">
<h3>{stats?.info?.name ?? addr}</h3> <h3>{stats?.info?.name}</h3>
<p>{stats?.info?.description}</p> <p>{stats?.info?.description}</p>
{stats?.info?.pubkey && (<> {stats?.info?.pubkey && (<>
@ -45,7 +45,7 @@ const RelayInfo = () => {
</>)} </>)}
<div className="flex mt10 f-end"> <div className="flex mt10 f-end">
<div className="btn error" onClick={() => { <div className="btn error" onClick={() => {
dispatch(removeRelay(con!.Address)); dispatch(removeRelay(conn!.Address));
navigate("/settings/relays") navigate("/settings/relays")
}}>Remove</div> }}>Remove</div>
</div> </div>

View File

@ -8,6 +8,8 @@ const PrivateKeyItem = "secret";
const PublicKeyItem = "pubkey"; const PublicKeyItem = "pubkey";
const NotificationsReadItem = "notifications-read"; const NotificationsReadItem = "notifications-read";
const UserPreferencesKey = "preferences"; const UserPreferencesKey = "preferences";
const RelayListKey = "last-relays";
const FollowList = "last-follows";
export interface UserPreferences { export interface UserPreferences {
/** /**
@ -138,8 +140,6 @@ const LoginSlice = createSlice({
state.loggedOut = true; state.loggedOut = true;
} }
state.relays = Object.fromEntries(DefaultRelays.entries());
// check pub key only // check pub key only
let pubKey = window.localStorage.getItem(PublicKeyItem); let pubKey = window.localStorage.getItem(PublicKeyItem);
if (pubKey && !state.privateKey) { if (pubKey && !state.privateKey) {
@ -147,6 +147,18 @@ const LoginSlice = createSlice({
state.loggedOut = false; state.loggedOut = false;
} }
let lastRelayList = window.localStorage.getItem(RelayListKey);
if (lastRelayList) {
state.relays = JSON.parse(lastRelayList);
} else if (state.loggedOut === true) {
state.relays = Object.fromEntries(DefaultRelays.entries());
}
let lastFollows = window.localStorage.getItem(FollowList);
if (lastFollows) {
state.follows = JSON.parse(lastFollows);
}
// notifications // notifications
let readNotif = parseInt(window.localStorage.getItem(NotificationsReadItem) ?? "0"); let readNotif = parseInt(window.localStorage.getItem(NotificationsReadItem) ?? "0");
if (!isNaN(readNotif)) { if (!isNaN(readNotif)) {
@ -187,10 +199,12 @@ const LoginSlice = createSlice({
state.relays = Object.fromEntries(filtered.entries()); state.relays = Object.fromEntries(filtered.entries());
state.latestRelays = createdAt; state.latestRelays = createdAt;
window.localStorage.setItem(RelayListKey, JSON.stringify(state.relays));
}, },
removeRelay: (state, action: PayloadAction<string>) => { removeRelay: (state, action: PayloadAction<string>) => {
delete state.relays[action.payload]; delete state.relays[action.payload];
state.relays = { ...state.relays }; state.relays = { ...state.relays };
window.localStorage.setItem(RelayListKey, JSON.stringify(state.relays));
}, },
setFollows: (state, action: PayloadAction<string | string[]>) => { setFollows: (state, action: PayloadAction<string | string[]>) => {
let existing = new Set(state.follows); let existing = new Set(state.follows);
@ -205,6 +219,7 @@ const LoginSlice = createSlice({
} }
if (changes) { if (changes) {
state.follows = Array.from(existing); state.follows = Array.from(existing);
window.localStorage.setItem(FollowList, JSON.stringify(state.follows));
} }
}, },
addNotifications: (state, action: PayloadAction<TaggedRawEvent | TaggedRawEvent[]>) => { addNotifications: (state, action: PayloadAction<TaggedRawEvent | TaggedRawEvent[]>) => {
@ -249,10 +264,10 @@ const LoginSlice = createSlice({
state.dmInteraction += 1; state.dmInteraction += 1;
}, },
logout: (state) => { logout: (state) => {
window.localStorage.clear();
Object.assign(state, InitState); Object.assign(state, InitState);
state.loggedOut = true; state.loggedOut = true;
state.relays = Object.fromEntries(DefaultRelays.entries()); state.relays = Object.fromEntries(DefaultRelays.entries());
window.localStorage.clear();
}, },
markNotificationsRead: (state) => { markNotificationsRead: (state) => {
state.readNotifications = new Date().getTime(); state.readNotifications = new Date().getTime();