PR changes

This commit is contained in:
Kieran 2023-01-28 15:40:19 +00:00
parent fd770f798d
commit 56e8e85f74
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
9 changed files with 77 additions and 39 deletions

View File

@ -48,7 +48,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
break;
}
case "keyword": {
sub.Keywords = new Set(subject.items);
sub.Search = subject.items[0];
break;
}
}
@ -76,7 +76,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
latestSub.Authors = sub.Authors;
latestSub.HashTags = sub.HashTags;
latestSub.Kinds = sub.Kinds;
latestSub.Keywords = sub.Keywords;
latestSub.Search = sub.Search;
latestSub.Limit = 1;
latestSub.Since = Math.floor(new Date().getTime() / 1000);
sub.AddSubscription(latestSub);
@ -128,7 +128,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
if (main.store.notes.length > 0) {
setTrackingEvent(s => {
let ids = main.store.notes.map(a => a.id);
if(ids.some(a => !s.includes(a))) {
if (ids.some(a => !s.includes(a))) {
return Array.from(new Set([...s, ...ids]));
}
return s;

View File

@ -7,6 +7,7 @@ import { DefaultConnectTimeout } from "Const";
import { ConnectionStats } from "Nostr/ConnectionStats";
import { RawEvent, TaggedRawEvent, u256 } from "Nostr";
import { RelayInfo } from "./RelayInfo";
import Nips from "./Nips";
export type CustomHook = (state: Readonly<StateSnapshot>) => void;
@ -238,6 +239,11 @@ export default class Connection {
return;
}
// check relay supports search
if (sub.Search && !this.SupportsNip(Nips.Search)) {
return;
}
if (this.Subscriptions.has(sub.Id)) {
return;
}
@ -281,6 +287,13 @@ export default class Connection {
return this.LastState;
}
/**
* Using relay document to determine if this relay supports a feature
*/
SupportsNip(n: number) {
return this.Info?.supported_nips?.some(a => a === n) ?? false;
}
_UpdateState() {
this.CurrentState.connected = this.Socket?.readyState === WebSocket.OPEN;
this.CurrentState.events.received = this.Stats.EventsReceived;

5
src/Nostr/Nips.ts Normal file
View File

@ -0,0 +1,5 @@
enum Nips {
Search = 50
}
export default Nips;

View File

@ -43,9 +43,9 @@ export class Subscriptions {
HashTags?: Set<string>;
/**
* A list of keywords to search
* A list of search terms
*/
Keywords?: Set<string>;
Search?: string;
/**
* a timestamp, events must be newer than this to pass
@ -94,7 +94,7 @@ export class Subscriptions {
this.Kinds = sub?.kinds ? new Set(sub.kinds) : undefined;
this.ETags = sub?.["#e"] ? new Set(sub["#e"]) : undefined;
this.PTags = sub?.["#p"] ? new Set(sub["#p"]) : undefined;
this.Keywords = sub?.keywords ? new Set(sub.keywords) : undefined;
this.Search = sub?.search ?? undefined;
this.Since = sub?.since ?? undefined;
this.Until = sub?.until ?? undefined;
this.Limit = sub?.limit ?? undefined;
@ -139,8 +139,8 @@ export class Subscriptions {
if(this.HashTags) {
ret["#t"] = Array.from(this.HashTags);
}
if (this.Keywords) {
ret.keywords = Array.from(this.Keywords);
if (this.Search) {
ret.search = this.Search;
}
if (this.Since !== null) {
ret.since = this.Since;

View File

@ -1,7 +1,7 @@
import { HexKey, TaggedRawEvent } from "Nostr";
import { getDb } from "State/Users/Db";
import { ProfileCacheExpire, SearchRelays } from "Const";
import { mapEventToProfile, MetadataCache } from "Db/User";
import { ProfileCacheExpire } from "Const";
import { mapEventToProfile, MetadataCache } from "State/Users";
import Connection, { RelaySettings } from "Nostr/Connection";
import Event from "Nostr/Event";
import EventKind from "Nostr/EventKind";
@ -48,8 +48,7 @@ export class NostrSystem {
let c = new Connection(address, options);
this.Sockets.set(address, c);
for (let [_, s] of this.Subscriptions) {
if (!s.Keywords || SearchRelays.has(address))
c.AddSubscription(s);
c.AddSubscription(s);
}
} else {
// update settings if already connected
@ -73,16 +72,14 @@ export class NostrSystem {
AddSubscription(sub: Subscriptions) {
for (let [a, s] of this.Sockets) {
if (!sub.Keywords || SearchRelays.has(a))
s.AddSubscription(sub);
s.AddSubscription(sub);
}
this.Subscriptions.set(sub.Id, sub);
}
RemoveSubscription(subId: string) {
for (let [a, s] of this.Sockets) {
if (!this.Subscriptions.get(subId)?.Keywords || SearchRelays.has(a))
s.RemoveSubscription(subId);
s.RemoveSubscription(subId);
}
this.Subscriptions.delete(subId);
}

View File

@ -35,7 +35,7 @@ export type RawReqFilter = {
"#e"?: u256[],
"#p"?: u256[],
"#t"?: string[],
keywords?: u256[],
search?: string,
since?: number,
until?: number,
limit?: number

View File

@ -2,7 +2,7 @@ import "./Layout.css";
import { useEffect, useState } from "react"
import { useDispatch, useSelector } from "react-redux";
import { Outlet, useNavigate } from "react-router-dom";
import { faBell, faMessage } from "@fortawesome/free-solid-svg-icons";
import { faBell, faMessage, faSearch } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { RootState } from "State/Store";
@ -41,11 +41,6 @@ export default function Layout() {
}
}
}
for (let [k, v] of SearchRelays) {
if (!System.Sockets.has(k)) {
System.ConnectToRelay(k, v);
}
}
}, [relays]);
function setTheme(theme: "light" | "dark") {
@ -114,21 +109,14 @@ export default function Layout() {
if (typeof isInit !== "boolean") {
return null;
}
async function search() {
if (keyword)
navigate(`/search/${encodeURIComponent(keyword)}/`);
}
return (
<div className="page">
<div className="header">
<div className="logo" onClick={() => navigate("/")}>snort</div>
<div className="search">
<input type="text" placeholder="Search..." value={keyword} onChange={(e) => setKeyword(e.target.value)} onKeyPress={(e) => { if (e.key === 'Enter') search() } }/>
<div className="btn" onClick={() => search()}>&#128269;</div>
</div>
<div>
<div className={`btn btn-rnd mr10`} onClick={(e) => navigate("/search")}>
<FontAwesomeIcon icon={faSearch} size="xl" />
</div>
{key ? accountHeader() :
<div className="btn" onClick={() => navigate("/login")}>Login</div>
}

View File

@ -1,14 +1,49 @@
import { useParams } from "react-router-dom";
import Timeline from "Element/Timeline";
import { useEffect, useState } from "react";
import { debounce } from "Util";
import { router } from "index";
import { SearchRelays } from "Const";
import { System } from "Nostr/System";
const SearchPage = () => {
const params = useParams();
const keyword = params.keyword!.toLowerCase();
const params: any = useParams();
const [search, setSearch] = useState<string>();
const [keyword, setKeyword] = useState<string | undefined>(params.keyword);
useEffect(() => {
if (keyword) {
// "navigate" changing only url
router.navigate(`/search/${encodeURIComponent(keyword)}`)
}
}, [keyword]);
useEffect(() => {
return debounce(500, () => setKeyword(search));
}, [search]);
useEffect(() => {
let addedRelays: string[] = [];
for (let [k, v] of SearchRelays) {
if (!System.Sockets.has(k)) {
System.ConnectToRelay(k, v);
addedRelays.push(k);
}
}
return () => {
for (let r of addedRelays) {
System.DisconnectRelay(r);
}
}
}, []);
return (
<>
<h2>Search results for: {keyword}</h2>
<Timeline key={keyword} subject={{ type: "keyword", items: [keyword] }} postsOnly={false} method={"LIMIT_UNTIL"} />
<h2>Search</h2>
<div className="flex mb10">
<input type="text" className="f-grow mr10" placeholder="Search.." value={search} onChange={e => setSearch(e.target.value)} />
</div>
{keyword && <Timeline key={keyword} subject={{ type: "keyword", items: [keyword] }} postsOnly={false} method={"LIMIT_UNTIL"} />}
</>
)
}

View File

@ -36,7 +36,7 @@ const HTTP = new QueryClient()
serviceWorkerRegistration.register();
const router = createBrowserRouter([
export const router = createBrowserRouter([
{
element: <Layout />,
errorElement: <ErrorPage />,
@ -91,7 +91,7 @@ const router = createBrowserRouter([
element: <HashTagsPage />
},
{
path: "/search/:keyword",
path: "/search/:keyword?",
element: <SearchPage />
}
]