fix: connection props
This commit is contained in:
@ -40,7 +40,7 @@ export default function Relay(props: RelayProps) {
|
|||||||
<div>
|
<div>
|
||||||
<b>{name}</b>
|
<b>{name}</b>
|
||||||
</div>
|
</div>
|
||||||
{!connection?.Ephemeral && (
|
{!connection?.ephemeral && (
|
||||||
<div className="flex g8">
|
<div className="flex g8">
|
||||||
<AsyncIcon
|
<AsyncIcon
|
||||||
iconName="write"
|
iconName="write"
|
||||||
@ -74,7 +74,7 @@ export default function Relay(props: RelayProps) {
|
|||||||
iconName="gear"
|
iconName="gear"
|
||||||
iconSize={16}
|
iconSize={16}
|
||||||
className="button-icon-sm transparent"
|
className="button-icon-sm transparent"
|
||||||
onClick={() => navigate(connection?.Id ?? "")}
|
onClick={() => navigate(connection?.id ?? "")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -24,7 +24,7 @@ export async function updateRelayConnections(system: SystemInterface, relays: Re
|
|||||||
system.ConnectToRelay(k, v);
|
system.ConnectToRelay(k, v);
|
||||||
}
|
}
|
||||||
for (const [k, v] of system.pool) {
|
for (const [k, v] of system.pool) {
|
||||||
if (!relays[k] && !v.Ephemeral) {
|
if (!relays[k] && !v.ephemeral) {
|
||||||
system.DisconnectRelay(k);
|
system.DisconnectRelay(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
import { unixNow } from "@snort/shared";
|
|
||||||
import { SnortContext } from "@snort/system-react";
|
|
||||||
import { useContext, useEffect, useMemo, useState } from "react";
|
|
||||||
import { FormattedMessage } from "react-intl";
|
|
||||||
|
|
||||||
import Timeline from "@/Components/Feed/Timeline";
|
|
||||||
import useHistoryState from "@/Hooks/useHistoryState";
|
|
||||||
import useLogin from "@/Hooks/useLogin";
|
|
||||||
import { debounce, getRelayName, sha256 } from "@/Utils";
|
|
||||||
|
|
||||||
interface RelayOption {
|
|
||||||
url: string;
|
|
||||||
paid: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GlobalTab = () => {
|
|
||||||
const { relays } = useLogin();
|
|
||||||
const [relay, setRelay] = useHistoryState(undefined, "global-relay");
|
|
||||||
const [allRelays, setAllRelays] = useHistoryState(undefined, "global-relay-options");
|
|
||||||
const [now] = useState(unixNow());
|
|
||||||
const system = useContext(SnortContext);
|
|
||||||
|
|
||||||
function globalRelaySelector() {
|
|
||||||
if (!allRelays || allRelays.length === 0) return null;
|
|
||||||
|
|
||||||
const paidRelays = allRelays.filter(a => a.paid);
|
|
||||||
const publicRelays = allRelays.filter(a => !a.paid);
|
|
||||||
return (
|
|
||||||
<div className="flex items-center g8 justify-end nowrap">
|
|
||||||
<h3>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Relay"
|
|
||||||
id="KHK8B9"
|
|
||||||
description="Label for reading global feed from specific relays"
|
|
||||||
/>
|
|
||||||
</h3>
|
|
||||||
<select
|
|
||||||
className="f-ellipsis"
|
|
||||||
onChange={e => setRelay(allRelays.find(a => a.url === e.target.value))}
|
|
||||||
value={relay?.url}>
|
|
||||||
{paidRelays.length > 0 && (
|
|
||||||
<optgroup label="Paid Relays">
|
|
||||||
{paidRelays.map(a => (
|
|
||||||
<option key={a.url} value={a.url}>
|
|
||||||
{getRelayName(a.url)}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</optgroup>
|
|
||||||
)}
|
|
||||||
<optgroup label="Public Relays">
|
|
||||||
{publicRelays.map(a => (
|
|
||||||
<option key={a.url} value={a.url}>
|
|
||||||
{getRelayName(a.url)}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return debounce(500, () => {
|
|
||||||
const ret: RelayOption[] = [];
|
|
||||||
[...system.pool].forEach(([, v]) => {
|
|
||||||
if (!v.IsClosed) {
|
|
||||||
ret.push({
|
|
||||||
url: v.Address,
|
|
||||||
paid: v.Info?.limitation?.payment_required ?? false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ret.sort(a => (a.paid ? -1 : 1));
|
|
||||||
|
|
||||||
if (ret.length > 0 && !relay) {
|
|
||||||
setRelay(ret[0]);
|
|
||||||
}
|
|
||||||
setAllRelays(ret);
|
|
||||||
});
|
|
||||||
}, [relays, relay]);
|
|
||||||
|
|
||||||
const subject = useMemo(
|
|
||||||
() => ({
|
|
||||||
type: "global",
|
|
||||||
items: [],
|
|
||||||
relay: [relay?.url],
|
|
||||||
discriminator: `all-${sha256(relay?.url ?? "")}`,
|
|
||||||
}),
|
|
||||||
[relay?.url],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{globalRelaySelector()}
|
|
||||||
{relay && <Timeline subject={subject} postsOnly={false} method={"TIME_RANGE"} window={600} now={now} />}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
@ -7,7 +7,6 @@ import { ConversationsTab } from "@/Pages/Root/ConversationsTab";
|
|||||||
import { DefaultTab } from "@/Pages/Root/DefaultTab";
|
import { DefaultTab } from "@/Pages/Root/DefaultTab";
|
||||||
import { FollowedByFriendsTab } from "@/Pages/Root/FollowedByFriendsTab";
|
import { FollowedByFriendsTab } from "@/Pages/Root/FollowedByFriendsTab";
|
||||||
import { ForYouTab } from "@/Pages/Root/ForYouTab";
|
import { ForYouTab } from "@/Pages/Root/ForYouTab";
|
||||||
import { GlobalTab } from "@/Pages/Root/GlobalTab";
|
|
||||||
import { NotesTab } from "@/Pages/Root/NotesTab";
|
import { NotesTab } from "@/Pages/Root/NotesTab";
|
||||||
import { TagsTab } from "@/Pages/Root/TagsTab";
|
import { TagsTab } from "@/Pages/Root/TagsTab";
|
||||||
import { TopicsPage } from "@/Pages/TopicsPage";
|
import { TopicsPage } from "@/Pages/TopicsPage";
|
||||||
@ -15,7 +14,6 @@ import { TopicsPage } from "@/Pages/TopicsPage";
|
|||||||
export type RootTabRoutePath =
|
export type RootTabRoutePath =
|
||||||
| ""
|
| ""
|
||||||
| "for-you"
|
| "for-you"
|
||||||
| "global"
|
|
||||||
| "following"
|
| "following"
|
||||||
| "followed-by-friends"
|
| "followed-by-friends"
|
||||||
| "conversations"
|
| "conversations"
|
||||||
@ -41,10 +39,6 @@ export const RootTabRoutes: RootTabRoute[] = [
|
|||||||
path: "for-you",
|
path: "for-you",
|
||||||
element: <ForYouTab />,
|
element: <ForYouTab />,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "global",
|
|
||||||
element: <GlobalTab />,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "following",
|
path: "following",
|
||||||
element: <NotesTab />,
|
element: <NotesTab />,
|
||||||
|
@ -30,10 +30,10 @@ export function ZapPoolPageInner() {
|
|||||||
const relayConnections = useMemo(() => {
|
const relayConnections = useMemo(() => {
|
||||||
return [...system.pool]
|
return [...system.pool]
|
||||||
.map(([, a]) => {
|
.map(([, a]) => {
|
||||||
if (a.Info?.pubkey && !a.Ephemeral) {
|
if (a.info?.pubkey && !a.ephemeral) {
|
||||||
return {
|
return {
|
||||||
address: a.Address,
|
address: a.address,
|
||||||
pubkey: a.Info.pubkey,
|
pubkey: a.info.pubkey,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Connection } from "@snort/system";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
|
||||||
@ -16,66 +17,66 @@ const RelayInfo = () => {
|
|||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const { system } = useEventPublisher();
|
const { system } = useEventPublisher();
|
||||||
|
|
||||||
const conn = [...system.pool].find(([, a]) => a.Id === params.id)?.[1];
|
const conn = [...system.pool].find(([, a]) => a.id === params.id)?.[1];
|
||||||
|
|
||||||
const stats = useRelayState(conn?.Address ?? "");
|
const stats = useRelayState(conn?.address ?? "");
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h3 className="pointer" onClick={() => navigate("/settings/relays")}>
|
<h3 className="pointer" onClick={() => navigate("/settings/relays")}>
|
||||||
<FormattedMessage {...messages.Relays} />
|
<FormattedMessage {...messages.Relays} />
|
||||||
</h3>
|
</h3>
|
||||||
<div>
|
<div>
|
||||||
<h3>{stats?.Info?.name}</h3>
|
<h3>{stats?.info?.name}</h3>
|
||||||
<p>{stats?.Info?.description}</p>
|
<p>{stats?.info?.description}</p>
|
||||||
|
|
||||||
{stats?.Info?.pubkey && (
|
{stats?.info?.pubkey && (
|
||||||
<>
|
<>
|
||||||
<h4>
|
<h4>
|
||||||
<FormattedMessage {...messages.Owner} />
|
<FormattedMessage {...messages.Owner} />
|
||||||
</h4>
|
</h4>
|
||||||
<ProfilePreview pubkey={parseId(stats.Info.pubkey)} />
|
<ProfilePreview pubkey={parseId(stats.info.pubkey)} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{stats?.Info?.software && (
|
{stats?.info?.software && (
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<h4 className="grow">
|
<h4 className="grow">
|
||||||
<FormattedMessage {...messages.Software} />
|
<FormattedMessage {...messages.Software} />
|
||||||
</h4>
|
</h4>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
{stats.Info.software.startsWith("http") ? (
|
{stats.info.software.startsWith("http") ? (
|
||||||
<a href={stats.Info.software} target="_blank" rel="noreferrer">
|
<a href={stats.info.software} target="_blank" rel="noreferrer">
|
||||||
{stats.Info.software}
|
{stats.info.software}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
<>{stats.Info.software}</>
|
<>{stats.info.software}</>
|
||||||
)}
|
)}
|
||||||
<small>
|
<small>
|
||||||
{!stats.Info.version?.startsWith("v") && "v"}
|
{!stats.info.version?.startsWith("v") && "v"}
|
||||||
{stats.Info.version}
|
{stats.info.version}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{stats?.Info?.contact && (
|
{stats?.info?.contact && (
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<h4 className="grow">
|
<h4 className="grow">
|
||||||
<FormattedMessage {...messages.Contact} />
|
<FormattedMessage {...messages.Contact} />
|
||||||
</h4>
|
</h4>
|
||||||
<a
|
<a
|
||||||
href={`${stats.Info.contact.startsWith("mailto:") ? "" : "mailto:"}${stats.Info.contact}`}
|
href={`${stats.info.contact.startsWith("mailto:") ? "" : "mailto:"}${stats.info.contact}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer">
|
rel="noreferrer">
|
||||||
{stats.Info.contact}
|
{stats.info.contact}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{stats?.Info?.supported_nips && (
|
{stats?.info?.supported_nips && (
|
||||||
<>
|
<>
|
||||||
<h4>
|
<h4>
|
||||||
<FormattedMessage {...messages.Supports} />
|
<FormattedMessage {...messages.Supports} />
|
||||||
</h4>
|
</h4>
|
||||||
<div className="grow">
|
<div className="grow">
|
||||||
{stats.Info?.supported_nips?.map(a => (
|
{stats.info?.supported_nips?.map(a => (
|
||||||
<a key={a} target="_blank" rel="noreferrer" href={`https://nips.be/${a}`} className="pill">
|
<a key={a} target="_blank" rel="noreferrer" href={`https://nips.be/${a}`} className="pill">
|
||||||
NIP-{a.toString().padStart(2, "0")}
|
NIP-{a.toString().padStart(2, "0")}
|
||||||
</a>
|
</a>
|
||||||
@ -83,30 +84,38 @@ const RelayInfo = () => {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<h4>
|
{conn instanceof Connection && (
|
||||||
<FormattedMessage defaultMessage="Active Subscriptions" id="p85Uwy" />
|
<>
|
||||||
</h4>
|
<h4>
|
||||||
<div className="grow">
|
<FormattedMessage defaultMessage="Active Subscriptions" id="p85Uwy" />
|
||||||
{[...(stats?.ActiveRequests ?? [])].map(a => (
|
</h4>
|
||||||
<span className="pill" key={a}>
|
<div className="grow">
|
||||||
{a}
|
{conn.ActiveRequests.map(a => (
|
||||||
</span>
|
<span className="pill" key={a}>
|
||||||
))}
|
{a}
|
||||||
</div>
|
</span>
|
||||||
<h4>
|
))}
|
||||||
<FormattedMessage defaultMessage="Pending Subscriptions" id="UDYlxu" />
|
</div>
|
||||||
</h4>
|
</>
|
||||||
<div className="grow">
|
)}
|
||||||
{stats?.PendingRequests?.map(a => (
|
{conn instanceof Connection && (
|
||||||
<span className="pill" key={a.obj[1]}>
|
<>
|
||||||
{a.obj[1]}
|
<h4>
|
||||||
</span>
|
<FormattedMessage defaultMessage="Pending Subscriptions" id="UDYlxu" />
|
||||||
))}
|
</h4>
|
||||||
</div>
|
<div className="grow">
|
||||||
|
{conn.PendingRequests.map(a => (
|
||||||
|
<span className="pill" key={a.obj[1]}>
|
||||||
|
{a.obj[1]}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="flex mt10 justify-end">
|
<div className="flex mt10 justify-end">
|
||||||
<AsyncButton
|
<AsyncButton
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await login.state.removeRelay(unwrap(conn).Address, true);
|
await login.state.removeRelay(unwrap(conn).address, true);
|
||||||
navigate("/settings/relays");
|
navigate("/settings/relays");
|
||||||
}}>
|
}}>
|
||||||
<FormattedMessage {...messages.Remove} />
|
<FormattedMessage {...messages.Remove} />
|
||||||
|
@ -78,7 +78,7 @@ const RelaySettingsPage = () => {
|
|||||||
</h3>
|
</h3>
|
||||||
<div className="flex flex-col g8">
|
<div className="flex flex-col g8">
|
||||||
{otherConnections.map(a => (
|
{otherConnections.map(a => (
|
||||||
<Relay addr={a.Address} key={a.Id} />
|
<Relay addr={a.address} key={a.id} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,7 +104,7 @@ export class Zapper {
|
|||||||
if (!svc) {
|
if (!svc) {
|
||||||
throw new Error(`Failed to get invoice from ${t.value}`);
|
throw new Error(`Failed to get invoice from ${t.value}`);
|
||||||
}
|
}
|
||||||
const relays = [...this.system.pool].filter(([, v]) => !v.Ephemeral).map(([k]) => k);
|
const relays = [...this.system.pool].filter(([, v]) => !v.ephemeral).map(([k]) => k);
|
||||||
const pub = t.zap?.anon ?? false ? EventPublisher.privateKey(generateRandomKey().privateKey) : this.publisher;
|
const pub = t.zap?.anon ?? false ? EventPublisher.privateKey(generateRandomKey().privateKey) : this.publisher;
|
||||||
const zap =
|
const zap =
|
||||||
t.zap && svc.canZap
|
t.zap && svc.canZap
|
||||||
|
@ -31,6 +31,7 @@ export type ConnectionType = {
|
|||||||
readonly address: string;
|
readonly address: string;
|
||||||
readonly info: RelayInfo | undefined;
|
readonly info: RelayInfo | undefined;
|
||||||
readonly isDown: boolean;
|
readonly isDown: boolean;
|
||||||
|
readonly isOpen: boolean;
|
||||||
settings: RelaySettings;
|
settings: RelaySettings;
|
||||||
ephemeral: boolean;
|
ephemeral: boolean;
|
||||||
|
|
||||||
|
@ -3,7 +3,14 @@ import { QueryLike, SystemConfig, SystemInterface } from "./system";
|
|||||||
import { RelaySettings, SyncCommand } from "./connection";
|
import { RelaySettings, SyncCommand } from "./connection";
|
||||||
import { TaggedNostrEvent, NostrEvent, OkResponse, ReqCommand } from "./nostr";
|
import { TaggedNostrEvent, NostrEvent, OkResponse, ReqCommand } from "./nostr";
|
||||||
import { BuiltRawReqFilter, RequestBuilder } from "./request-builder";
|
import { BuiltRawReqFilter, RequestBuilder } from "./request-builder";
|
||||||
import NDK, { NDKConstructorParams, NDKEvent, NDKFilter, NDKRelay, NDKSubscription } from "@nostr-dev-kit/ndk";
|
import NDK, {
|
||||||
|
NDKConstructorParams,
|
||||||
|
NDKEvent,
|
||||||
|
NDKFilter,
|
||||||
|
NDKRelay,
|
||||||
|
NDKSubscription,
|
||||||
|
NDKRelayStatus,
|
||||||
|
} from "@nostr-dev-kit/ndk";
|
||||||
import { SystemBase } from "./system-base";
|
import { SystemBase } from "./system-base";
|
||||||
import { ConnectionPool, ConnectionType, ConnectionTypeEvents, DefaultConnectionPool } from "./connection-pool";
|
import { ConnectionPool, ConnectionType, ConnectionTypeEvents, DefaultConnectionPool } from "./connection-pool";
|
||||||
import { RelayMetadataLoader } from "./outbox";
|
import { RelayMetadataLoader } from "./outbox";
|
||||||
@ -53,7 +60,11 @@ class NDKConnection extends EventEmitter<ConnectionTypeEvents> implements Connec
|
|||||||
}
|
}
|
||||||
|
|
||||||
get isDown() {
|
get isDown() {
|
||||||
return !this.relay.connectivity.isAvailable();
|
return this.relay.connectivity.status === NDKRelayStatus.FLAPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isOpen() {
|
||||||
|
return this.relay.connectivity.status === NDKRelayStatus.CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
info: RelayInfo | undefined;
|
info: RelayInfo | undefined;
|
||||||
|
Reference in New Issue
Block a user