mirror of
https://git.v0l.io/Kieran/dtan.git
synced 2024-12-12 15:06:22 +00:00
feat: relay controls
This commit is contained in:
parent
85151ac008
commit
5c8cb7d359
11
src/main.tsx
11
src/main.tsx
@ -12,8 +12,9 @@ import { NewPage } from "./page/new";
|
||||
import { TorrentPage } from "./page/torrent";
|
||||
import { SearchPage } from "./page/search";
|
||||
import { System, initSystem } from "./system";
|
||||
import { RelaysPage } from "./page/relays";
|
||||
|
||||
const Routes = [
|
||||
const routes = [
|
||||
{
|
||||
element: <Layout />,
|
||||
loader: async () => {
|
||||
@ -41,15 +42,19 @@ const Routes = [
|
||||
path: "/search/:term?",
|
||||
element: <SearchPage />,
|
||||
},
|
||||
{
|
||||
path: "/relays",
|
||||
element: <RelaysPage />,
|
||||
},
|
||||
],
|
||||
},
|
||||
] as Array<RouteObject>;
|
||||
|
||||
const Router = createBrowserRouter(Routes);
|
||||
const router = createBrowserRouter(routes);
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
<SnortContext.Provider value={System}>
|
||||
<RouterProvider router={Router} />
|
||||
<RouterProvider router={router} />
|
||||
</SnortContext.Provider>
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
@ -3,9 +3,35 @@ import { Button } from "../element/button";
|
||||
import { LoginSession, LoginState, useLogin } from "../login";
|
||||
import { ProfileImage } from "../element/profile-image";
|
||||
import { Search } from "../element/search";
|
||||
import { useRelays } from "../relays";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { SnortContext } from "@snort/system-react";
|
||||
import { RelaySettings, SystemInterface } from "@snort/system";
|
||||
|
||||
export function Layout() {
|
||||
const login = useLogin();
|
||||
const system = useContext(SnortContext);
|
||||
const { relays } = useRelays();
|
||||
|
||||
async function updateRelayConnections(system: SystemInterface, relays: Record<string, RelaySettings>) {
|
||||
if (import.meta.env.VITE_SINGLE_RELAY) {
|
||||
system.ConnectToRelay(import.meta.env.VITE_SINGLE_RELAY, { read: true, write: true });
|
||||
} else {
|
||||
for (const [k, v] of Object.entries(relays)) {
|
||||
// note: don't awit this, causes race condition with sending requests to relays
|
||||
system.ConnectToRelay(k, v);
|
||||
}
|
||||
for (const [k, v] of system.pool) {
|
||||
if (!relays[k] && !v.ephemeral) {
|
||||
system.DisconnectRelay(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
updateRelayConnections(system, Object.fromEntries(relays.map((a) => [a, { read: true, write: true }])));
|
||||
}, [system, relays]);
|
||||
|
||||
async function DoLogin() {
|
||||
if ("nostr" in window) {
|
||||
@ -18,14 +44,18 @@ export function Layout() {
|
||||
|
||||
return (
|
||||
<div className="container mx-auto">
|
||||
<header className="flex justify-between items-center pt-4 pb-6">
|
||||
<header className="flex gap-4 items-center pt-4 pb-6">
|
||||
<Link to={"/"} className="flex gap-2 items-center">
|
||||
<img src="/logo_256.jpg" className="rounded-full" height={40} width={40} />
|
||||
<h1 className="font-bold uppercase">dtan.xyz</h1>
|
||||
</Link>
|
||||
<div className="w-1/2">
|
||||
<div className="w-1/3">
|
||||
<Search />
|
||||
</div>
|
||||
<div className="grow"></div>
|
||||
<Link to="/relays">
|
||||
<Button type="secondary">Relays</Button>
|
||||
</Link>
|
||||
{login ? (
|
||||
<LoggedInHeader login={login} />
|
||||
) : (
|
||||
|
47
src/page/relays.tsx
Normal file
47
src/page/relays.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { useState } from "react";
|
||||
import { Button } from "../element/button";
|
||||
import { useRelays } from "../relays";
|
||||
import { sanitizeRelayUrl } from "@snort/shared";
|
||||
|
||||
export function RelaysPage() {
|
||||
const relays = useRelays();
|
||||
const [newRelay, setNewRelay] = useState("");
|
||||
return (
|
||||
<>
|
||||
<h2>Relays</h2>
|
||||
<br />
|
||||
<div className="flex flex-col gap-2">
|
||||
{relays.relays.map((a) => (
|
||||
<div key={a} className="bg-neutral-800 px-3 py-2 rounded-xl flex justify-between items-center">
|
||||
{a}
|
||||
<Button type="danger" onClick={() => relays.remove(a)}>
|
||||
Remove
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<br />
|
||||
<div className="flex gap-4">
|
||||
<input
|
||||
type="text"
|
||||
value={newRelay}
|
||||
onChange={(e) => setNewRelay(e.target.value)}
|
||||
className="px-4 py-2 rounded-xl bg-neutral-800 focus-visible:outline-none"
|
||||
placeholder="wss://myrelay.com"
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
const url = sanitizeRelayUrl(newRelay);
|
||||
if (url) {
|
||||
relays.add(url);
|
||||
setNewRelay("");
|
||||
}
|
||||
}}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
58
src/relays.tsx
Normal file
58
src/relays.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { ExternalStore, appendDedupe, sanitizeRelayUrl } from "@snort/shared";
|
||||
import { useSyncExternalStore } from "react";
|
||||
|
||||
const storageKey = "relays";
|
||||
class RelaysStore extends ExternalStore<Array<string>> {
|
||||
#relays: Array<string> = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const loaded = localStorage.getItem(storageKey);
|
||||
if (loaded) {
|
||||
this.#relays = JSON.parse(loaded);
|
||||
} else {
|
||||
this.#relays = ["wss://nos.lol/", "wss://relay.damus.io/", "wss://relay.nostr.band/"];
|
||||
this.#save();
|
||||
}
|
||||
}
|
||||
|
||||
add(u: string) {
|
||||
const url = sanitizeRelayUrl(u);
|
||||
if (url) {
|
||||
this.#relays = appendDedupe(this.#relays, [url]);
|
||||
this.#save();
|
||||
}
|
||||
}
|
||||
|
||||
remove(u: string) {
|
||||
const url = sanitizeRelayUrl(u);
|
||||
if (url) {
|
||||
this.#relays = this.#relays.filter((a) => a !== url);
|
||||
this.#save();
|
||||
}
|
||||
}
|
||||
|
||||
#save() {
|
||||
localStorage.setItem(storageKey, JSON.stringify(this.#relays));
|
||||
this.notifyChange();
|
||||
}
|
||||
|
||||
takeSnapshot(): string[] {
|
||||
return [...this.#relays];
|
||||
}
|
||||
}
|
||||
|
||||
const relayStore = new RelaysStore();
|
||||
|
||||
export function useRelays() {
|
||||
const relays = useSyncExternalStore(
|
||||
(s) => relayStore.hook(s),
|
||||
() => relayStore.snapshot(),
|
||||
);
|
||||
|
||||
return {
|
||||
relays,
|
||||
add: (a: string) => relayStore.add(a),
|
||||
remove: (a: string) => relayStore.remove(a),
|
||||
};
|
||||
}
|
@ -62,8 +62,5 @@ export async function initSystem() {
|
||||
System.Init(),
|
||||
];
|
||||
|
||||
for (const r of ["wss://nos.lol", "wss://relay.damus.io", "wss://relay.nostr.band"]) {
|
||||
System.ConnectToRelay(r, { read: true, write: true });
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user