commit
15ffa7d4b4
@ -12,6 +12,7 @@
|
||||
"@scure/bip39": "^1.1.1",
|
||||
"@snort/shared": "workspace:*",
|
||||
"@snort/system": "workspace:*",
|
||||
"@snort/system-query": "workspace:*",
|
||||
"@snort/system-react": "workspace:*",
|
||||
"@szhsin/react-menu": "^3.3.1",
|
||||
"@void-cat/api": "^1.0.4",
|
||||
@ -101,6 +102,7 @@
|
||||
"prop-types": "^15.8.1",
|
||||
"source-map-loader": "^4.0.1",
|
||||
"terser-webpack-plugin": "^5.3.9",
|
||||
"tinybench": "^2.5.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.4",
|
||||
"typescript": "^5.2.2",
|
||||
|
10
packages/app/public/bench.html
Normal file
10
packages/app/public/bench.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Snort Benchmarks</title>
|
||||
</head>
|
||||
<body>
|
||||
Check console
|
||||
</body>
|
||||
</html>
|
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
@ -38,7 +38,7 @@ export class GiftWrapCache extends RefreshFeedCache<UnwrappedGift> {
|
||||
} catch (e) {
|
||||
console.debug(e, v);
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
)
|
||||
.filter(a => a !== undefined)
|
||||
|
@ -26,7 +26,7 @@ export default function CashuNuts({ token }: { token: string }) {
|
||||
e.stopPropagation();
|
||||
const lnurl = profile?.lud16 ?? "";
|
||||
const url = `https://redeem.cashu.me?token=${encodeURIComponent(token)}&lightning=${encodeURIComponent(
|
||||
lnurl
|
||||
lnurl,
|
||||
)}&autopay=yes`;
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ export default function FollowButton(props: FollowButtonProps) {
|
||||
if (publisher) {
|
||||
const ev = await publisher.contactList(
|
||||
follows.item.filter(a => a !== pubkey),
|
||||
relays.item
|
||||
relays.item,
|
||||
);
|
||||
System.BroadcastEvent(ev);
|
||||
}
|
||||
|
@ -261,9 +261,7 @@ export default function Nip5Service(props: Nip05ServiceProps) {
|
||||
/>
|
||||
@
|
||||
<select value={domain} onChange={onDomainChange}>
|
||||
{serviceConfig?.domains.map(a => (
|
||||
<option key={a.name}>{a.name}</option>
|
||||
))}
|
||||
{serviceConfig?.domains.map(a => <option key={a.name}>{a.name}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
@ -135,7 +135,7 @@ export function NoteInner(props: NoteProps) {
|
||||
{
|
||||
[Reaction.Positive]: [] as TaggedNostrEvent[],
|
||||
[Reaction.Negative]: [] as TaggedNostrEvent[],
|
||||
}
|
||||
},
|
||||
);
|
||||
return {
|
||||
[Reaction.Positive]: dedupeByPubkey(result[Reaction.Positive]),
|
||||
@ -150,7 +150,7 @@ export function NoteInner(props: NoteProps) {
|
||||
...getReactions(related, ev.id, EventKind.TextNote).filter(e => e.tags.some(tagFilterOfTextRepost(e, ev.id))),
|
||||
...getReactions(related, ev.id, EventKind.Repost),
|
||||
]),
|
||||
[related, ev]
|
||||
[related, ev],
|
||||
);
|
||||
const zaps = useMemo(() => {
|
||||
const sortedZaps = getReactions(related, ev.id, EventKind.ZapReceipt)
|
||||
@ -241,7 +241,7 @@ export function NoteInner(props: NoteProps) {
|
||||
function goToEvent(
|
||||
e: React.MouseEvent,
|
||||
eTarget: TaggedNostrEvent,
|
||||
isTargetAllowed: boolean = e.target === e.currentTarget
|
||||
isTargetAllowed: boolean = e.target === e.currentTarget,
|
||||
) {
|
||||
if (!isTargetAllowed || opt?.canClick === false) {
|
||||
return;
|
||||
|
@ -2,7 +2,8 @@
|
||||
border: 1px solid transparent;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0px 0px 6px 1px rgba(182, 108, 156, 0.3);
|
||||
background: linear-gradient(var(--gray-superdark), var(--gray-superdark)) padding-box,
|
||||
background:
|
||||
linear-gradient(var(--gray-superdark), var(--gray-superdark)) padding-box,
|
||||
linear-gradient(90deg, #ef9644, #fd7c49, #ff5e58, #ff3b70, #ff088e, #eb00b1, #c31ed5, #7b41f6) border-box;
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,8 @@ export function NoteCreator() {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Invalid LNURL",
|
||||
})
|
||||
)
|
||||
}),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -256,9 +256,9 @@ export function NoteCreator() {
|
||||
? false
|
||||
: // otherwise return selectedCustomRelays with target relay added / removed
|
||||
a.filter(el =>
|
||||
el === r ? e.target.checked : !selectedCustomRelays || selectedCustomRelays.includes(el)
|
||||
)
|
||||
)
|
||||
el === r ? e.target.checked : !selectedCustomRelays || selectedCustomRelays.includes(el),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
@ -71,7 +71,7 @@ export default function NoteFooter(props: NoteFooterProps) {
|
||||
},
|
||||
{
|
||||
captureEvent: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function hasReacted(emoji: string) {
|
||||
|
@ -10,6 +10,7 @@ import useModeration from "Hooks/useModeration";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import Icon from "Icons/Icon";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
import { useInView } from "react-intersection-observer";
|
||||
|
||||
export interface NoteReactionProps {
|
||||
data: TaggedNostrEvent;
|
||||
@ -19,7 +20,8 @@ export interface NoteReactionProps {
|
||||
export default function NoteReaction(props: NoteReactionProps) {
|
||||
const { data: ev } = props;
|
||||
const { isMuted } = useModeration();
|
||||
const profile = useUserProfile(ev.pubkey);
|
||||
const { inView, ref } = useInView({ triggerOnce: true });
|
||||
const profile = useUserProfile(inView ? ev.pubkey : "");
|
||||
|
||||
const refEvent = useMemo(() => {
|
||||
if (ev) {
|
||||
@ -44,6 +46,7 @@ export default function NoteReaction(props: NoteReactionProps) {
|
||||
* Some clients embed the reposted note in the content
|
||||
*/
|
||||
function extractRoot() {
|
||||
if (!inView) return null;
|
||||
if (ev?.kind === EventKind.Repost && ev.content.length > 0 && ev.content !== "#[0]") {
|
||||
try {
|
||||
const r: NostrEvent = JSON.parse(ev.content);
|
||||
@ -60,7 +63,11 @@ export default function NoteReaction(props: NoteReactionProps) {
|
||||
return props.root;
|
||||
}
|
||||
|
||||
const root = extractRoot();
|
||||
const root = useMemo(() => extractRoot(), [ev, props.root, inView]);
|
||||
|
||||
if (!inView) {
|
||||
return <div className="card reaction" ref={ref}></div>;
|
||||
}
|
||||
const isOpMuted = root && isMuted(root.pubkey);
|
||||
const shouldNotBeRendered = isOpMuted || root?.kind !== EventKind.TextNote;
|
||||
const opt = {
|
||||
|
@ -47,15 +47,15 @@ export default function Poll(props: PollProps) {
|
||||
},
|
||||
{
|
||||
amount,
|
||||
}
|
||||
)
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
setVoting(opt);
|
||||
const r = Object.keys(relays.item);
|
||||
const zap = await publisher.zap(amount * 1000, props.ev.pubkey, r, props.ev.id, undefined, eb =>
|
||||
eb.tag(["poll_option", opt.toString()])
|
||||
eb.tag(["poll_option", opt.toString()]),
|
||||
);
|
||||
|
||||
const lnurl = props.ev.tags.find(a => a[0] === "zap")?.[1] || pollerProfile?.lud16 || pollerProfile?.lud06;
|
||||
@ -68,7 +68,7 @@ export default function Poll(props: PollProps) {
|
||||
throw new Error(
|
||||
formatMessage({
|
||||
defaultMessage: "Can't vote because LNURL service does not support zaps",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ export default function Poll(props: PollProps) {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Failed to send vote",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
|
@ -34,7 +34,7 @@ export default function PubkeyList({ ev, className }: { ev: NostrEvent; classNam
|
||||
pk,
|
||||
Object.keys(login.relays.item),
|
||||
undefined,
|
||||
`Zap from ${hexToBech32("note", ev.id)}`
|
||||
`Zap from ${hexToBech32("note", ev.id)}`,
|
||||
);
|
||||
const invoice = await svc.getInvoice(amtSend, undefined, zap);
|
||||
if (invoice.pr) {
|
||||
|
@ -55,9 +55,9 @@ export function ReBroadcaster() {
|
||||
? false
|
||||
: // otherwise return selectedCustomRelays with target relay added / removed
|
||||
a.filter(el =>
|
||||
el === r ? e.target.checked : !selectedCustomRelays || selectedCustomRelays.includes(el)
|
||||
)
|
||||
)
|
||||
el === r ? e.target.checked : !selectedCustomRelays || selectedCustomRelays.includes(el),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
@ -60,7 +60,7 @@ const Reactions = ({ show, setShow, positive, negative, reposts, zaps }: Reactio
|
||||
value: 3,
|
||||
},
|
||||
]
|
||||
: []
|
||||
: [],
|
||||
);
|
||||
|
||||
const [tab, setTab] = useState(tabs[0]);
|
||||
|
@ -22,7 +22,7 @@ export default function Relay(props: RelayProps) {
|
||||
const navigate = useNavigate();
|
||||
const login = useLogin();
|
||||
const relaySettings = unwrap(
|
||||
login.relays.item[props.addr] ?? System.Sockets.find(a => a.address === props.addr)?.settings ?? {}
|
||||
login.relays.item[props.addr] ?? System.Sockets.find(a => a.address === props.addr)?.settings ?? {},
|
||||
);
|
||||
const state = useRelayState(props.addr);
|
||||
const name = useMemo(() => getRelayName(props.addr), [props.addr]);
|
||||
@ -34,7 +34,7 @@ export default function Relay(props: RelayProps) {
|
||||
...login.relays.item,
|
||||
[props.addr]: o,
|
||||
},
|
||||
unixNowMs()
|
||||
unixNowMs(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ export default function SendSats(props: SendSatsProps) {
|
||||
{makeTab(ZapType.AnonZap, <FormattedMessage defaultMessage="Anon" description="Anonymous Zap" />)}
|
||||
{makeTab(
|
||||
ZapType.NonZap,
|
||||
<FormattedMessage defaultMessage="Non-Zap" description="Non-Zap, Regular LN payment" />
|
||||
<FormattedMessage defaultMessage="Non-Zap" description="Non-Zap, Regular LN payment" />,
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
@ -243,7 +243,7 @@ export default function Thread() {
|
||||
if (t?.root?.key === "a" && t?.root?.value) {
|
||||
const parsed = t.root.value.split(":");
|
||||
replyTo = thread.data?.find(
|
||||
a => a.kind === Number(parsed[0]) && a.pubkey === parsed[1] && findTag(a, "d") === parsed[2]
|
||||
a => a.kind === Number(parsed[0]) && a.pubkey === parsed[1] && findTag(a, "d") === parsed[2],
|
||||
)?.id;
|
||||
}
|
||||
if (replyTo) {
|
||||
@ -264,7 +264,7 @@ export default function Thread() {
|
||||
thread.data?.find(
|
||||
ne =>
|
||||
ne.id === currentId ||
|
||||
(link.type === NostrPrefix.Address && findTag(ne, "d") === currentId && ne.pubkey === link.author)
|
||||
(link.type === NostrPrefix.Address && findTag(ne, "d") === currentId && ne.pubkey === link.author),
|
||||
) ?? (location.state && "sig" in location.state ? (location.state as TaggedNostrEvent) : undefined);
|
||||
if (currentNote) {
|
||||
const currentThread = EventExt.extractThread(currentNote);
|
||||
@ -280,7 +280,7 @@ export default function Thread() {
|
||||
if (replyTo.key === "a" && replyTo.value) {
|
||||
const parsed = replyTo.value.split(":");
|
||||
return thread.data?.find(
|
||||
a => a.kind === Number(parsed[0]) && a.pubkey === parsed[1] && findTag(a, "d") === parsed[2]
|
||||
a => a.kind === Number(parsed[0]) && a.pubkey === parsed[1] && findTag(a, "d") === parsed[2],
|
||||
);
|
||||
}
|
||||
if (replyTo.value) {
|
||||
@ -348,7 +348,7 @@ export default function Thread() {
|
||||
notes={replies}
|
||||
related={getAllReactions(
|
||||
thread.data,
|
||||
replies.map(a => a.id)
|
||||
replies.map(a => a.id),
|
||||
)}
|
||||
chains={chains}
|
||||
onNavigate={navigateThread}
|
||||
|
@ -47,7 +47,7 @@ const Timeline = (props: TimelineProps) => {
|
||||
?.filter(a => (props.postsOnly ? !a.tags.some(b => b[0] === "e") : true))
|
||||
.filter(a => props.ignoreModeration || !isMuted(a.pubkey));
|
||||
},
|
||||
[props.postsOnly, muted, props.ignoreModeration]
|
||||
[props.postsOnly, muted, props.ignoreModeration],
|
||||
);
|
||||
|
||||
const mainFeed = useMemo(() => {
|
||||
@ -60,7 +60,7 @@ const Timeline = (props: TimelineProps) => {
|
||||
(id: u256) => {
|
||||
return (feed.related ?? []).filter(a => findTag(a, "e") === id);
|
||||
},
|
||||
[feed.related]
|
||||
[feed.related],
|
||||
);
|
||||
const liveStreams = useMemo(() => {
|
||||
return (feed.main ?? []).filter(a => a.kind === EventKind.LiveEvent && findTag(a, "status") === "live");
|
||||
|
@ -28,11 +28,11 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
|
||||
const [latest, setLatest] = useState(unixNow());
|
||||
const feed = useSyncExternalStore(
|
||||
cb => FollowsFeed.hook(cb, "*"),
|
||||
() => FollowsFeed.snapshot()
|
||||
() => FollowsFeed.snapshot(),
|
||||
);
|
||||
const reactions = useReactions(
|
||||
"follows-feed-reactions",
|
||||
feed.map(a => a.id)
|
||||
feed.map(a => a.id),
|
||||
);
|
||||
const system = useContext(SnortContext);
|
||||
const login = useLogin();
|
||||
@ -48,7 +48,7 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
|
||||
?.filter(a => (props.postsOnly ? !a.tags.some(b => b[0] === "e") : true))
|
||||
.filter(a => !isMuted(a.pubkey) && login.follows.item.includes(a.pubkey));
|
||||
},
|
||||
[props.postsOnly, muted, login.follows.timestamp]
|
||||
[props.postsOnly, muted, login.follows.timestamp],
|
||||
);
|
||||
|
||||
const mainFeed = useMemo(() => {
|
||||
@ -63,7 +63,7 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
|
||||
(id: u256) => {
|
||||
return (reactions?.data ?? []).filter(a => findTag(a, "e") === id);
|
||||
},
|
||||
[reactions]
|
||||
[reactions],
|
||||
);
|
||||
|
||||
const liveStreams = useMemo(() => {
|
||||
|
@ -17,7 +17,7 @@ export default function ZapstrEmbed({ ev }: { ev: NostrEvent }) {
|
||||
ev.tags.find(a => a[0] === "d")?.[1] ?? "",
|
||||
undefined,
|
||||
ev.kind,
|
||||
ev.pubkey
|
||||
ev.pubkey,
|
||||
);
|
||||
return (
|
||||
<>
|
||||
|
@ -23,7 +23,7 @@ export default function useProfileBadges(pubkey?: HexKey) {
|
||||
if (profileBadges.data) {
|
||||
return chunks(
|
||||
profileBadges.data.tags.filter(t => t[0] === "a" || t[0] === "e"),
|
||||
2
|
||||
2,
|
||||
).reduce((acc, [a, e]) => {
|
||||
return {
|
||||
...acc,
|
||||
@ -44,7 +44,7 @@ export default function useProfileBadges(pubkey?: HexKey) {
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ pubkeys: [], ds: [] } as BadgeAwards
|
||||
{ pubkeys: [], ds: [] } as BadgeAwards,
|
||||
) as BadgeAwards;
|
||||
}, [profile]);
|
||||
|
||||
@ -77,7 +77,7 @@ export default function useProfileBadges(pubkey?: HexKey) {
|
||||
})
|
||||
.filter(
|
||||
({ award, badge }) =>
|
||||
badge && award.pubkey === badge.pubkey && award.tags.find(t => t[0] === "p" && t[1] === pubkey)
|
||||
badge && award.pubkey === badge.pubkey && award.tags.find(t => t[0] === "p" && t[1] === pubkey),
|
||||
)
|
||||
.map(({ badge }) => unwrap(badge));
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ export function useReactions(subId: string, ids: Array<string>, others?: (rb: Re
|
||||
.kinds(
|
||||
pref.enableReactions
|
||||
? [EventKind.Reaction, EventKind.Repost, EventKind.ZapReceipt]
|
||||
: [EventKind.ZapReceipt, EventKind.Repost]
|
||||
: [EventKind.ZapReceipt, EventKind.Repost],
|
||||
)
|
||||
.tag("e", ids);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ export default function useFollowersFeed(pubkey?: HexKey) {
|
||||
|
||||
const followers = useMemo(() => {
|
||||
const contactLists = followersFeed.data?.filter(
|
||||
a => a.kind === EventKind.ContactList && a.tags.some(b => b[0] === "p" && b[1] === pubkey)
|
||||
a => a.kind === EventKind.ContactList && a.tags.some(b => b[0] === "p" && b[1] === pubkey),
|
||||
);
|
||||
return [...new Set(contactLists?.map(a => a.pubkey))];
|
||||
}, [followersFeed, pubkey]);
|
||||
|
@ -85,7 +85,7 @@ export default function useLoginFeed() {
|
||||
Nip4Chats.onEvent(loginFeed.data);
|
||||
|
||||
const subs = loginFeed.data.filter(
|
||||
a => a.kind === EventKind.SnortSubscriptions && a.pubkey === bech32ToHex(SnortPubKey)
|
||||
a => a.kind === EventKind.SnortSubscriptions && a.pubkey === bech32ToHex(SnortPubKey),
|
||||
);
|
||||
Promise.all(
|
||||
subs.map(async a => {
|
||||
@ -97,7 +97,7 @@ export default function useLoginFeed() {
|
||||
...ex,
|
||||
} as SubscriptionEvent;
|
||||
}
|
||||
})
|
||||
}),
|
||||
).then(a => addSubscription(login, ...a.filter(a => a !== undefined).map(unwrap)));
|
||||
}
|
||||
}, [loginFeed, publisher]);
|
||||
@ -106,7 +106,7 @@ export default function useLoginFeed() {
|
||||
useEffect(() => {
|
||||
if (loginFeed.data) {
|
||||
const replies = loginFeed.data.filter(
|
||||
a => a.kind === EventKind.TextNote && !isMuted(a.pubkey) && a.created_at > readNotifications
|
||||
a => a.kind === EventKind.TextNote && !isMuted(a.pubkey) && a.created_at > readNotifications,
|
||||
);
|
||||
replies.forEach(async nx => {
|
||||
const n = await makeNotification(nx);
|
||||
|
@ -35,11 +35,11 @@ export default function useThreadFeed(link: NostrLink) {
|
||||
.kinds(
|
||||
pref.enableReactions
|
||||
? [EventKind.Reaction, EventKind.TextNote, EventKind.Repost, EventKind.ZapReceipt]
|
||||
: [EventKind.TextNote, EventKind.ZapReceipt, EventKind.Repost]
|
||||
: [EventKind.TextNote, EventKind.ZapReceipt, EventKind.Repost],
|
||||
)
|
||||
.tag(
|
||||
"e",
|
||||
allEvents.map(a => a.id)
|
||||
allEvents.map(a => a.id),
|
||||
);
|
||||
}
|
||||
if (trackingATags.length > 0) {
|
||||
@ -50,7 +50,7 @@ export default function useThreadFeed(link: NostrLink) {
|
||||
.authors(parsed.map(a => a[1]))
|
||||
.tag(
|
||||
"d",
|
||||
parsed.map(a => a[2])
|
||||
parsed.map(a => a[2]),
|
||||
);
|
||||
sub.withFilter().tag("a", trackingATags);
|
||||
}
|
||||
@ -85,7 +85,7 @@ export default function useThreadFeed(link: NostrLink) {
|
||||
id: b[1],
|
||||
relay: b[2],
|
||||
};
|
||||
})
|
||||
}),
|
||||
)
|
||||
.flat();
|
||||
const eTagsMissing = eTags.filter(a => !mainNotes.some(b => b.id === a.id));
|
||||
|
@ -43,7 +43,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
.kinds(
|
||||
subject.type === "profile_keyword"
|
||||
? [EventKind.SetMetadata]
|
||||
: [EventKind.TextNote, EventKind.Repost, EventKind.Polls]
|
||||
: [EventKind.TextNote, EventKind.Repost, EventKind.Polls],
|
||||
);
|
||||
|
||||
if (subject.relay) {
|
||||
@ -149,7 +149,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
.map(a => unwrap(a)[1]);
|
||||
const repostsByKind1 = main.data
|
||||
.filter(
|
||||
a => (a.kind === EventKind.Repost || a.kind === EventKind.TextNote) && a.tags.some(tagFilterOfTextRepost(a))
|
||||
a => (a.kind === EventKind.Repost || a.kind === EventKind.TextNote) && a.tags.some(tagFilterOfTextRepost(a)),
|
||||
)
|
||||
.map(a => a.tags.find(tagFilterOfTextRepost(a)))
|
||||
.filter(a => a)
|
||||
|
@ -21,7 +21,7 @@ export default function useImgProxy() {
|
||||
const result = hmacSha256(
|
||||
utils.hexToBytes(unwrap(settings).key),
|
||||
utils.hexToBytes(unwrap(settings).salt),
|
||||
te.encode(u)
|
||||
te.encode(u),
|
||||
);
|
||||
return urlSafe(base64.encode(result));
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export function useInteractionCache(pubkey?: HexKey, event?: u256) {
|
||||
const data =
|
||||
useSyncExternalStore(
|
||||
c => InteractionCache.hook(c, id),
|
||||
() => InteractionCache.snapshot().find(a => a.id === id)
|
||||
() => InteractionCache.snapshot().find(a => a.id === id),
|
||||
) || EmptyInteraction;
|
||||
return {
|
||||
data: data,
|
||||
|
@ -4,6 +4,6 @@ import { useSyncExternalStore } from "react";
|
||||
export default function useLogin() {
|
||||
return useSyncExternalStore(
|
||||
s => LoginStore.hook(s),
|
||||
() => LoginStore.snapshot()
|
||||
() => LoginStore.snapshot(),
|
||||
);
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
||||
type: LoginSessionType,
|
||||
relays?: Record<string, RelaySettings>,
|
||||
remoteSignerRelays?: Array<string>,
|
||||
privateKey?: string
|
||||
privateKey?: string,
|
||||
) {
|
||||
if (this.#accounts.has(key)) {
|
||||
throw new Error("Already logged in with this pubkey");
|
||||
|
@ -97,7 +97,7 @@ export class ServiceProvider {
|
||||
path: string,
|
||||
method?: "GET" | string,
|
||||
body?: unknown,
|
||||
headers?: { [key: string]: string }
|
||||
headers?: { [key: string]: string },
|
||||
): Promise<T | ServiceError> {
|
||||
try {
|
||||
const rsp = await fetch(`${this.url}${path}`, {
|
||||
|
@ -54,7 +54,7 @@ export default class SnortServiceProvider extends ServiceProvider {
|
||||
path: string,
|
||||
method?: "GET" | string,
|
||||
body?: unknown,
|
||||
headers?: { [key: string]: string }
|
||||
headers?: { [key: string]: string },
|
||||
): Promise<T | ServiceError> {
|
||||
const auth = await this.#publisher.generic(eb => {
|
||||
eb.kind(EventKind.HttpAuthentication);
|
||||
|
@ -25,7 +25,7 @@ const ErrorPage = () => {
|
||||
{JSON.stringify(
|
||||
error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : error,
|
||||
undefined,
|
||||
" "
|
||||
" ",
|
||||
)}
|
||||
</pre>
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ export default function Layout() {
|
||||
useEffect(() => {
|
||||
const osTheme = window.matchMedia("(prefers-color-scheme: light)");
|
||||
setTheme(
|
||||
preferences.theme === "system" && osTheme.matches ? "light" : preferences.theme === "light" ? "light" : "dark"
|
||||
preferences.theme === "system" && osTheme.matches ? "light" : preferences.theme === "light" ? "light" : "dark",
|
||||
);
|
||||
|
||||
osTheme.onchange = e => {
|
||||
@ -174,7 +174,7 @@ const AccountHeader = () => {
|
||||
|
||||
const hasNotifications = useMemo(
|
||||
() => latestNotification > readNotifications,
|
||||
[latestNotification, readNotifications]
|
||||
[latestNotification, readNotifications],
|
||||
);
|
||||
const unreadDms = useMemo(() => (publicKey ? 0 : 0), [publicKey]);
|
||||
|
||||
|
@ -55,7 +55,7 @@ const Artwork: Array<ArtworkEntry> = [
|
||||
export async function getNip05PubKey(addr: string): Promise<string> {
|
||||
const [username, domain] = addr.split("@");
|
||||
const rsp = await fetch(
|
||||
`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(username.toLocaleLowerCase())}`
|
||||
`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(username.toLocaleLowerCase())}`,
|
||||
);
|
||||
if (rsp.ok) {
|
||||
const data = await rsp.json();
|
||||
@ -103,7 +103,7 @@ export default function LoginPage() {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Unknown login error",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
console.error(e);
|
||||
|
@ -75,7 +75,7 @@ export default function NotificationsPage() {
|
||||
|
||||
const notifications = useSyncExternalStore(
|
||||
c => Notifications.hook(c, "*"),
|
||||
() => Notifications.snapshot()
|
||||
() => Notifications.snapshot(),
|
||||
);
|
||||
|
||||
const timeKey = (ev: NostrEvent) => {
|
||||
@ -119,7 +119,7 @@ function NotificationGroup({ evs }: { evs: Array<TaggedNostrEvent> }) {
|
||||
return zap.anonZap ? "anon" : zap.sender ?? a.pubkey;
|
||||
}
|
||||
return a.pubkey;
|
||||
})
|
||||
}),
|
||||
);
|
||||
const firstPubkey = pubkeys[0];
|
||||
const firstPubkeyProfile = useUserProfile(inView ? (firstPubkey === "anon" ? "" : firstPubkey) : "");
|
||||
@ -213,7 +213,7 @@ function NotificationGroup({ evs }: { evs: Array<TaggedNostrEvent> }) {
|
||||
pubkeys.length - 1,
|
||||
firstPubkey === "anon"
|
||||
? formatMessage({ defaultMessage: "Anon" })
|
||||
: getDisplayName(firstPubkeyProfile, firstPubkey)
|
||||
: getDisplayName(firstPubkeyProfile, firstPubkey),
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
@ -221,7 +221,7 @@ export default function ProfilePage() {
|
||||
} as { [key: string]: Tab };
|
||||
const [tab, setTab] = useState<Tab>(ProfileTab.Notes);
|
||||
const optionalTabs = [ProfileTab.Zaps, ProfileTab.Relays, ProfileTab.Bookmarks, ProfileTab.Muted].filter(a =>
|
||||
unwrap(a)
|
||||
unwrap(a),
|
||||
) as Tab[];
|
||||
const horizontalScroll = useHorizontalScroll();
|
||||
|
||||
@ -433,7 +433,7 @@ export default function ProfilePage() {
|
||||
type: TLVEntryType.Author,
|
||||
length: 64,
|
||||
value: id,
|
||||
})}`
|
||||
})}`,
|
||||
)
|
||||
}>
|
||||
<Icon name="envelope" size={16} />
|
||||
|
@ -73,7 +73,7 @@ export default function ZapPoolPage() {
|
||||
const login = useLogin();
|
||||
const zapPool = useSyncExternalStore(
|
||||
c => ZapPoolController.hook(c),
|
||||
() => ZapPoolController.snapshot()
|
||||
() => ZapPoolController.snapshot(),
|
||||
);
|
||||
const { wallet } = useWallet();
|
||||
|
||||
|
@ -27,7 +27,7 @@ export default function AccountsPage() {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Unknown login error",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
console.error(e);
|
||||
|
@ -29,7 +29,7 @@ export default function LNForwardAddress({ handle }: { handle: ManageHandle }) {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Invalid LNURL",
|
||||
})
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ const ConnectCashu = () => {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Unknown error",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ const ConnectLNC = () => {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Unknown error",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ const ConnectLNDHub = () => {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Unknown error",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ const ConnectNostrWallet = () => {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Unknown error",
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ export default class SnortApi {
|
||||
path: string,
|
||||
method?: "GET" | string,
|
||||
body?: { [key: string]: string },
|
||||
headers?: { [key: string]: string }
|
||||
headers?: { [key: string]: string },
|
||||
): Promise<T> {
|
||||
if (!this.#publisher) {
|
||||
throw new Error("Publisher not set");
|
||||
@ -110,7 +110,7 @@ export default class SnortApi {
|
||||
path: string,
|
||||
method?: "GET" | string,
|
||||
body?: { [key: string]: string },
|
||||
headers?: { [key: string]: string }
|
||||
headers?: { [key: string]: string },
|
||||
): Promise<T> {
|
||||
const rsp = await fetch(`${this.#url}${path}`, {
|
||||
method: method,
|
||||
|
@ -50,7 +50,7 @@ export async function openFile(): Promise<File | undefined> {
|
||||
}
|
||||
}, 300);
|
||||
},
|
||||
{ once: true }
|
||||
{ once: true },
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -209,7 +209,7 @@ export function dedupeByPubkey(events: TaggedNostrEvent[]) {
|
||||
list: [...list, ev],
|
||||
};
|
||||
},
|
||||
{ list: [], seen: new Set([]) }
|
||||
{ list: [], seen: new Set([]) },
|
||||
);
|
||||
return deduped.list as TaggedNostrEvent[];
|
||||
}
|
||||
@ -226,7 +226,7 @@ export function dedupeById<T extends { id: string }>(events: Array<T>) {
|
||||
list: [...list, ev],
|
||||
};
|
||||
},
|
||||
{ list: [], seen: new Set([]) }
|
||||
{ list: [], seen: new Set([]) },
|
||||
);
|
||||
return deduped.list as Array<T>;
|
||||
}
|
||||
@ -487,7 +487,7 @@ export function kvToObject<T>(o: string, sep?: string) {
|
||||
return [match[1], match[2]];
|
||||
}
|
||||
return [];
|
||||
})
|
||||
}),
|
||||
) as T;
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ export const Toastore = new ToasterSlots();
|
||||
export default function Toaster() {
|
||||
const toast = useSyncExternalStore(
|
||||
c => Toastore.hook(c),
|
||||
() => Toastore.snapshot()
|
||||
() => Toastore.snapshot(),
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -12,7 +12,7 @@ import { magnetURIDecode } from "SnortUtils";
|
||||
export default async function VoidCatUpload(
|
||||
file: File | Blob,
|
||||
filename: string,
|
||||
publisher?: EventPublisher
|
||||
publisher?: EventPublisher,
|
||||
): Promise<UploadResult> {
|
||||
const api = new VoidApi(VoidCatHost);
|
||||
const uploader = api.getUploader(file);
|
||||
|
@ -57,6 +57,6 @@ export interface NutStashBackup {
|
||||
mints: [
|
||||
{
|
||||
mintURL: string;
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ export class LNCWallet implements LNWallet {
|
||||
err => {
|
||||
this.#log(err);
|
||||
reject(err);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ export class NostrConnectWallet implements LNWallet {
|
||||
],
|
||||
() => {
|
||||
// ignored
|
||||
}
|
||||
},
|
||||
);
|
||||
await this.#conn.SendAsync(evCommand);
|
||||
return await new Promise<T>((resolve, reject) => {
|
||||
|
@ -84,7 +84,7 @@ export class WebLNWallet implements LNWallet {
|
||||
await window.webln?.makeInvoice({
|
||||
amount: req.amount,
|
||||
defaultMemo: req.memo,
|
||||
})
|
||||
}),
|
||||
);
|
||||
if (rsp) {
|
||||
const invoice = prToWalletInvoice(rsp.paymentRequest);
|
||||
|
@ -248,7 +248,7 @@ window.document.addEventListener("close", () => {
|
||||
export function useWallet() {
|
||||
const wallet = useSyncExternalStore<WalletStoreSnapshot>(
|
||||
h => Wallets.hook(h),
|
||||
() => Wallets.snapshot()
|
||||
() => Wallets.snapshot(),
|
||||
);
|
||||
useEffect(() => {
|
||||
if (wallet.wallet?.isReady() === false && wallet.wallet.canAutoLogin()) {
|
||||
|
@ -54,7 +54,7 @@ class ZapPool extends ExternalStore<Array<ZapPoolRecipient>> {
|
||||
Toastore.push({
|
||||
element: `Sent ${amtSend.toLocaleString()} sats to ${getDisplayName(
|
||||
profile,
|
||||
x.pubkey
|
||||
x.pubkey,
|
||||
)} from your zap pool`,
|
||||
expire: unixNow() + 10,
|
||||
icon: "zap",
|
||||
|
114
packages/app/src/benchmarks.ts
Normal file
114
packages/app/src/benchmarks.ts
Normal file
@ -0,0 +1,114 @@
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
import { DefaultQueryOptimizer, FlatReqFilter, QueryOptimizer, ReqFilter } from "@snort/system";
|
||||
import { compress, expand_filter, flat_merge, get_diff, default as wasmInit } from "@snort/system-query";
|
||||
import WasmPath from "@snort/system-query/pkg/system_query_bg.wasm";
|
||||
import { Bench } from "tinybench";
|
||||
|
||||
const WasmQueryOptimizer = {
|
||||
expandFilter: (f: ReqFilter) => {
|
||||
return expand_filter(f) as Array<FlatReqFilter>;
|
||||
},
|
||||
getDiff: (prev: Array<ReqFilter>, next: Array<ReqFilter>) => {
|
||||
return get_diff(prev, next) as Array<FlatReqFilter>;
|
||||
},
|
||||
flatMerge: (all: Array<FlatReqFilter>) => {
|
||||
return flat_merge(all) as Array<ReqFilter>;
|
||||
},
|
||||
compress: (all: Array<ReqFilter>) => {
|
||||
return compress(all) as Array<ReqFilter>;
|
||||
},
|
||||
} as QueryOptimizer;
|
||||
|
||||
const makeOnePubkey = () => {
|
||||
const rnd = globalThis.crypto.getRandomValues(new Uint8Array(32));
|
||||
return bytesToHex(rnd);
|
||||
};
|
||||
|
||||
const randomPubkeys = (() => {
|
||||
const ret = [];
|
||||
for (let x = 0; x < 50; x++) {
|
||||
ret.push(makeOnePubkey());
|
||||
}
|
||||
return ret;
|
||||
})();
|
||||
|
||||
const testExpand = (q: QueryOptimizer) => {
|
||||
q.expandFilter({
|
||||
kinds: [1, 2, 3],
|
||||
authors: randomPubkeys,
|
||||
});
|
||||
};
|
||||
const testGetDiff = (q: QueryOptimizer) => {
|
||||
q.getDiff(
|
||||
[
|
||||
{
|
||||
kinds: [1, 2, 3],
|
||||
authors: randomPubkeys,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
kinds: [1, 2, 3, 4, 5],
|
||||
authors: randomPubkeys,
|
||||
},
|
||||
],
|
||||
);
|
||||
};
|
||||
const testFlatMerge = (q: QueryOptimizer) => {
|
||||
q.flatMerge(
|
||||
q.expandFilter({
|
||||
kinds: [1, 6, 7, 6969],
|
||||
authors: randomPubkeys,
|
||||
}),
|
||||
);
|
||||
};
|
||||
const testCompress = (q: QueryOptimizer) => {
|
||||
q.compress([
|
||||
{
|
||||
kinds: [1, 6, 7, 6969],
|
||||
authors: randomPubkeys,
|
||||
},
|
||||
{
|
||||
kinds: [1, 6, 7, 6969],
|
||||
authors: randomPubkeys,
|
||||
},
|
||||
{
|
||||
kinds: [1, 6, 7, 6969],
|
||||
authors: randomPubkeys,
|
||||
},
|
||||
{
|
||||
kinds: [1, 6, 7, 6969],
|
||||
authors: randomPubkeys,
|
||||
},
|
||||
{
|
||||
kinds: [1, 6, 7, 6969],
|
||||
authors: randomPubkeys,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
const wasmSuite = new Bench({ time: 1_000 });
|
||||
const suite = new Bench({ time: 1_000 });
|
||||
|
||||
const addTests = (s: Bench, q: QueryOptimizer) => {
|
||||
s.add("expand", () => testExpand(q));
|
||||
s.add("get_diff", () => testGetDiff(q));
|
||||
s.add("flat_merge", () => testFlatMerge(q));
|
||||
s.add("compress", () => testCompress(q));
|
||||
};
|
||||
|
||||
addTests(suite, DefaultQueryOptimizer);
|
||||
addTests(wasmSuite, WasmQueryOptimizer);
|
||||
|
||||
const runAll = async () => {
|
||||
await wasmInit(WasmPath);
|
||||
|
||||
console.log("DefaultQueryOptimizer");
|
||||
await suite.run();
|
||||
console.table(suite.table());
|
||||
|
||||
console.log("WasmQueryOptimizer");
|
||||
await wasmSuite.run();
|
||||
console.table(wasmSuite.table());
|
||||
};
|
||||
runAll().catch(console.error);
|
@ -116,7 +116,7 @@ export function createChatLink(type: ChatType, ...params: Array<string>) {
|
||||
type: TLVEntryType.Author,
|
||||
length: params[0].length,
|
||||
value: params[0],
|
||||
} as TLVEntry
|
||||
} as TLVEntry,
|
||||
)}`;
|
||||
}
|
||||
case ChatType.PrivateDirectMessage: {
|
||||
@ -127,7 +127,7 @@ export function createChatLink(type: ChatType, ...params: Array<string>) {
|
||||
type: TLVEntryType.Author,
|
||||
length: params[0].length,
|
||||
value: params[0],
|
||||
} as TLVEntry
|
||||
} as TLVEntry,
|
||||
)}`;
|
||||
}
|
||||
case ChatType.PrivateGroupChat: {
|
||||
@ -139,8 +139,8 @@ export function createChatLink(type: ChatType, ...params: Array<string>) {
|
||||
type: TLVEntryType.Author,
|
||||
length: a.length,
|
||||
value: a,
|
||||
} as TLVEntry)
|
||||
)
|
||||
}) as TLVEntry,
|
||||
),
|
||||
)}`;
|
||||
}
|
||||
}
|
||||
@ -161,14 +161,14 @@ export function useNip4Chat() {
|
||||
const { publicKey } = useLogin();
|
||||
return useSyncExternalStore(
|
||||
c => Nip4Chats.hook(c),
|
||||
() => Nip4Chats.snapshot(publicKey)
|
||||
() => Nip4Chats.snapshot(publicKey),
|
||||
);
|
||||
}
|
||||
|
||||
export function useNip29Chat() {
|
||||
return useSyncExternalStore(
|
||||
c => Nip29Chats.hook(c),
|
||||
() => Nip29Chats.snapshot()
|
||||
() => Nip29Chats.snapshot(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -176,7 +176,7 @@ export function useNip24Chat() {
|
||||
const { publicKey } = useLogin();
|
||||
return useSyncExternalStore(
|
||||
c => Nip24Chats.hook(c),
|
||||
() => Nip24Chats.snapshot(publicKey)
|
||||
() => Nip24Chats.snapshot(publicKey),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,8 @@ export class Nip24ChatSystem extends ExternalStore<Array<Chat>> implements ChatS
|
||||
value: v,
|
||||
type: TLVEntryType.Author,
|
||||
length: v.length,
|
||||
} as TLVEntry)
|
||||
)
|
||||
}) as TLVEntry,
|
||||
),
|
||||
);
|
||||
};
|
||||
return dedupe(messages.map(a => chatId(a))).map(a => {
|
||||
@ -72,7 +72,7 @@ export class Nip24ChatSystem extends ExternalStore<Array<Chat>> implements ChatS
|
||||
} as {
|
||||
t: number;
|
||||
title: string | undefined;
|
||||
}
|
||||
},
|
||||
);
|
||||
return {
|
||||
type: ChatType.PrivateDirectMessage,
|
||||
|
@ -46,12 +46,12 @@ export class Nip29ChatSystem extends ExternalStore<Array<Chat>> implements ChatS
|
||||
.map(a => a.tags.find(b => b[0] === "g"))
|
||||
.filter(a => a !== undefined)
|
||||
.map(a => unwrap(a))
|
||||
.map(a => `${a[2]}${a[1]}`)
|
||||
.map(a => `${a[2]}${a[1]}`),
|
||||
);
|
||||
return groups.map(g => {
|
||||
const [relay, channel] = g.split("/", 2);
|
||||
const messages = allMessages.filter(
|
||||
a => `${a.tags.find(b => b[0] === "g")?.[2]}${a.tags.find(b => b[0] === "g")?.[1]}` === g
|
||||
a => `${a.tags.find(b => b[0] === "g")?.[2]}${a.tags.find(b => b[0] === "g")?.[1]}` === g,
|
||||
);
|
||||
const lastRead = lastReadInChat(g);
|
||||
return {
|
||||
|
@ -34,7 +34,7 @@ export class Nip4ChatSystem extends ExternalStore<Array<Chat>> implements ChatSy
|
||||
const dms = this.#cache.snapshot();
|
||||
const dmSince = dms.reduce(
|
||||
(acc, v) => (v.created_at > acc && v.kind === EventKind.DirectMessage ? (acc = v.created_at) : acc),
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
this.#log("Loading DMS since %s", new Date(dmSince * 1000));
|
||||
@ -49,12 +49,15 @@ export class Nip4ChatSystem extends ExternalStore<Array<Chat>> implements ChatSy
|
||||
|
||||
listChats(pk: string): Chat[] {
|
||||
const myDms = this.#nip4Events();
|
||||
const chats = myDms.reduce((acc, v) => {
|
||||
const chats = myDms.reduce(
|
||||
(acc, v) => {
|
||||
const chatId = inChatWith(v, pk);
|
||||
acc[chatId] ??= [];
|
||||
acc[chatId].push(v);
|
||||
return acc;
|
||||
}, {} as Record<string, Array<NostrEvent>>);
|
||||
},
|
||||
{} as Record<string, Array<NostrEvent>>,
|
||||
);
|
||||
|
||||
return [...Object.entries(chats)].map(([k, v]) => Nip4ChatSystem.createChatObj(k, v));
|
||||
}
|
||||
|
@ -2,11 +2,23 @@ import "./index.css";
|
||||
import "@szhsin/react-menu/dist/index.css";
|
||||
import "./fonts/inter.css";
|
||||
|
||||
import { compress, expand_filter, flat_merge, get_diff, default as wasmInit } from "@snort/system-query";
|
||||
import WasmPath from "@snort/system-query/pkg/system_query_bg.wasm";
|
||||
|
||||
import { StrictMode } from "react";
|
||||
import * as ReactDOM from "react-dom/client";
|
||||
import { Provider } from "react-redux";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import { EventPublisher, NostrSystem, ProfileLoaderService, Nip7Signer, PowWorker } from "@snort/system";
|
||||
import {
|
||||
EventPublisher,
|
||||
NostrSystem,
|
||||
ProfileLoaderService,
|
||||
Nip7Signer,
|
||||
PowWorker,
|
||||
QueryOptimizer,
|
||||
FlatReqFilter,
|
||||
ReqFilter,
|
||||
} from "@snort/system";
|
||||
import { SnortContext } from "@snort/system-react";
|
||||
|
||||
import * as serviceWorkerRegistration from "serviceWorkerRegistration";
|
||||
@ -36,6 +48,21 @@ import { db } from "Db";
|
||||
import { preload, RelayMetrics, UserCache, UserRelays } from "Cache";
|
||||
import { LoginStore } from "Login";
|
||||
|
||||
const WasmQueryOptimizer = {
|
||||
expandFilter: (f: ReqFilter) => {
|
||||
return expand_filter(f) as Array<FlatReqFilter>;
|
||||
},
|
||||
getDiff: (prev: Array<ReqFilter>, next: Array<ReqFilter>) => {
|
||||
return get_diff(prev, next) as Array<FlatReqFilter>;
|
||||
},
|
||||
flatMerge: (all: Array<FlatReqFilter>) => {
|
||||
return flat_merge(all) as Array<ReqFilter>;
|
||||
},
|
||||
compress: (all: Array<ReqFilter>) => {
|
||||
return compress(all) as Array<ReqFilter>;
|
||||
},
|
||||
} as QueryOptimizer;
|
||||
|
||||
/**
|
||||
* Singleton nostr system
|
||||
*/
|
||||
@ -43,6 +70,7 @@ export const System = new NostrSystem({
|
||||
relayCache: UserRelays,
|
||||
profileCache: UserCache,
|
||||
relayMetrics: RelayMetrics,
|
||||
queryOptimizer: WasmQueryOptimizer,
|
||||
authHandler: async (c, r) => {
|
||||
const { publicKey, privateKey } = LoginStore.snapshot();
|
||||
if (privateKey) {
|
||||
@ -69,6 +97,7 @@ export const DefaultPowWorker = new PowWorker("/pow.js");
|
||||
serviceWorkerRegistration.register();
|
||||
|
||||
async function initSite() {
|
||||
await wasmInit(WasmPath);
|
||||
const login = LoginStore.takeSnapshot();
|
||||
db.ready = await db.isAvailable();
|
||||
if (db.ready) {
|
||||
@ -173,5 +202,5 @@ root.render(
|
||||
</SnortContext.Provider>
|
||||
</IntlProvider>
|
||||
</Provider>
|
||||
</StrictMode>
|
||||
</StrictMode>,
|
||||
);
|
||||
|
@ -19,6 +19,7 @@ const config = {
|
||||
import: require.resolve("@snort/system/dist/pow-worker.js"),
|
||||
filename: "pow.js",
|
||||
},
|
||||
bench: "./src/benchmarks.ts",
|
||||
},
|
||||
target: "browserslist",
|
||||
mode: isProduction ? "production" : "development",
|
||||
@ -47,7 +48,12 @@ const config = {
|
||||
new HtmlWebpackPlugin({
|
||||
template: "public/index.html",
|
||||
favicon: "public/favicon.ico",
|
||||
excludeChunks: ["pow"],
|
||||
excludeChunks: ["pow", "bench"],
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "bench.html",
|
||||
template: "public/bench.html",
|
||||
chunks: ["bench"],
|
||||
}),
|
||||
new ESLintPlugin({
|
||||
extensions: ["js", "mjs", "jsx", "ts", "tsx"],
|
||||
@ -115,7 +121,7 @@ const config = {
|
||||
use: [MiniCssExtractPlugin.loader, require.resolve("css-loader")],
|
||||
},
|
||||
{
|
||||
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif|webp)$/i,
|
||||
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif|webp|wasm)$/i,
|
||||
type: "asset",
|
||||
},
|
||||
],
|
||||
|
3
packages/system-query/.gitignore
vendored
Normal file
3
packages/system-query/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.idea/
|
||||
target/
|
||||
*.txt
|
831
packages/system-query/Cargo.lock
generated
Normal file
831
packages/system-query/Cargo.lock
generated
Normal file
@ -0,0 +1,831 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anes"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"ciborium-ll",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-io"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-ll"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
|
||||
dependencies = [
|
||||
"anes",
|
||||
"cast",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"is-terminal",
|
||||
"itertools 0.10.5",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"oorandom",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools 0.10.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
"plotters-svg",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters-backend"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
|
||||
|
||||
[[package]]
|
||||
name = "plotters-svg"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
|
||||
dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-query"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"itertools 0.11.0",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"serde_json",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test"
|
||||
version = "0.3.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
"scoped-tls",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-bindgen-test-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test-macro"
|
||||
version = "0.3.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
24
packages/system-query/Cargo.toml
Normal file
24
packages/system-query/Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "system-query"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.11.0"
|
||||
serde = { version = "1.0.188", features = ["derive"] }
|
||||
serde-wasm-bindgen = "0.5.0"
|
||||
wasm-bindgen = "0.2.87"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8.5"
|
||||
wasm-bindgen-test = "0.3.37"
|
||||
serde_json = "1.0.105"
|
||||
criterion = { version = "0.5" }
|
||||
|
||||
[[bench]]
|
||||
name = "basic"
|
||||
harness = false
|
1
packages/system-query/README.md
Normal file
1
packages/system-query/README.md
Normal file
@ -0,0 +1 @@
|
||||
# system-query
|
65
packages/system-query/benches/basic.rs
Normal file
65
packages/system-query/benches/basic.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use rand::prelude::*;
|
||||
use std::collections::HashSet;
|
||||
use system_query::diff::diff_filter;
|
||||
use system_query::filter::{FlatReqFilter, ReqFilter};
|
||||
|
||||
fn random_pubkey(rng: &mut ThreadRng) -> String {
|
||||
let mut bytes = [0u8; 32];
|
||||
rng.fill_bytes(&mut bytes);
|
||||
bytes.iter().map(|byte| format!("{:02x}", byte)).collect()
|
||||
}
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let mut rng = thread_rng();
|
||||
let mut random_pubkeys = HashSet::new();
|
||||
for _ in 0..50 {
|
||||
random_pubkeys.insert(random_pubkey(&mut rng));
|
||||
}
|
||||
let input_authors = ReqFilter {
|
||||
authors: Some(random_pubkeys.clone()),
|
||||
kinds: Some(HashSet::from([1, 2, 3])),
|
||||
ids: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
e_tag: None,
|
||||
};
|
||||
|
||||
let input_authors_diff = ReqFilter {
|
||||
authors: Some(random_pubkeys.clone()),
|
||||
kinds: Some(HashSet::from([1, 2, 3, 4, 5])),
|
||||
ids: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
e_tag: None,
|
||||
};
|
||||
|
||||
|
||||
c.bench_function("expand", |b| {
|
||||
b.iter(|| {
|
||||
let _: Vec<FlatReqFilter> = (&input_authors).into();
|
||||
})
|
||||
});
|
||||
c.bench_function("diff", |b| {
|
||||
b.iter(|| {
|
||||
let prev: Vec<FlatReqFilter> = (&input_authors).into();
|
||||
let next: Vec<FlatReqFilter> = (&input_authors_diff).into();
|
||||
let _ = diff_filter(&prev, &next);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
15
packages/system-query/package.json
Normal file
15
packages/system-query/package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "@snort/system-query",
|
||||
"version": "0.1.0",
|
||||
"packageManager": "yarn@3.6.3",
|
||||
"scripts": {
|
||||
"build": "wasm-pack build -t web -s snort"
|
||||
},
|
||||
"files": [
|
||||
"pkg/system_query_bg.wasm",
|
||||
"pkg/system_query.js",
|
||||
"pkg/system_query.d.ts"
|
||||
],
|
||||
"module": "pkg/system_query.js",
|
||||
"types": "pkg/system_query.d.ts"
|
||||
}
|
1
packages/system-query/pkg/README.md
Normal file
1
packages/system-query/pkg/README.md
Normal file
@ -0,0 +1 @@
|
||||
# system-query
|
14
packages/system-query/pkg/package.json
Normal file
14
packages/system-query/pkg/package.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@snort/system-query",
|
||||
"version": "0.1.0",
|
||||
"files": [
|
||||
"system_query_bg.wasm",
|
||||
"system_query.js",
|
||||
"system_query.d.ts"
|
||||
],
|
||||
"module": "system_query.js",
|
||||
"types": "system_query.d.ts",
|
||||
"sideEffects": [
|
||||
"./snippets/*"
|
||||
]
|
||||
}
|
65
packages/system-query/pkg/system_query.d.ts
vendored
Normal file
65
packages/system-query/pkg/system_query.d.ts
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* @param {any} prev
|
||||
* @param {any} next
|
||||
* @returns {any}
|
||||
*/
|
||||
export function diff_filters(prev: any, next: any): any;
|
||||
/**
|
||||
* @param {any} val
|
||||
* @returns {any}
|
||||
*/
|
||||
export function expand_filter(val: any): any;
|
||||
/**
|
||||
* @param {any} prev
|
||||
* @param {any} next
|
||||
* @returns {any}
|
||||
*/
|
||||
export function get_diff(prev: any, next: any): any;
|
||||
/**
|
||||
* @param {any} val
|
||||
* @returns {any}
|
||||
*/
|
||||
export function flat_merge(val: any): any;
|
||||
/**
|
||||
* @param {any} val
|
||||
* @returns {any}
|
||||
*/
|
||||
export function compress(val: any): any;
|
||||
|
||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
export interface InitOutput {
|
||||
readonly memory: WebAssembly.Memory;
|
||||
readonly diff_filters: (a: number, b: number, c: number) => void;
|
||||
readonly expand_filter: (a: number, b: number) => void;
|
||||
readonly get_diff: (a: number, b: number, c: number) => void;
|
||||
readonly flat_merge: (a: number, b: number) => void;
|
||||
readonly compress: (a: number, b: number) => void;
|
||||
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
||||
readonly __wbindgen_exn_store: (a: number) => void;
|
||||
}
|
||||
|
||||
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
||||
/**
|
||||
* Instantiates the given `module`, which can either be bytes or
|
||||
* a precompiled `WebAssembly.Module`.
|
||||
*
|
||||
* @param {SyncInitInput} module
|
||||
*
|
||||
* @returns {InitOutput}
|
||||
*/
|
||||
export function initSync(module: SyncInitInput): InitOutput;
|
||||
|
||||
/**
|
||||
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
||||
* for everything else, calls `WebAssembly.instantiate` directly.
|
||||
*
|
||||
* @param {InitInput | Promise<InitInput>} module_or_path
|
||||
*
|
||||
* @returns {Promise<InitOutput>}
|
||||
*/
|
||||
export default function __wbg_init(module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;
|
586
packages/system-query/pkg/system_query.js
Normal file
586
packages/system-query/pkg/system_query.js
Normal file
@ -0,0 +1,586 @@
|
||||
let wasm;
|
||||
|
||||
const heap = new Array(128).fill(undefined);
|
||||
|
||||
heap.push(undefined, null, true, false);
|
||||
|
||||
function getObject(idx) {
|
||||
return heap[idx];
|
||||
}
|
||||
|
||||
let heap_next = heap.length;
|
||||
|
||||
function dropObject(idx) {
|
||||
if (idx < 132) return;
|
||||
heap[idx] = heap_next;
|
||||
heap_next = idx;
|
||||
}
|
||||
|
||||
function takeObject(idx) {
|
||||
const ret = getObject(idx);
|
||||
dropObject(idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
let cachedUint8Memory0 = null;
|
||||
|
||||
function getUint8Memory0() {
|
||||
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
|
||||
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedUint8Memory0;
|
||||
}
|
||||
|
||||
const cachedTextEncoder =
|
||||
typeof TextEncoder !== "undefined"
|
||||
? new TextEncoder("utf-8")
|
||||
: {
|
||||
encode: () => {
|
||||
throw Error("TextEncoder not available");
|
||||
},
|
||||
};
|
||||
|
||||
const encodeString =
|
||||
typeof cachedTextEncoder.encodeInto === "function"
|
||||
? function (arg, view) {
|
||||
return cachedTextEncoder.encodeInto(arg, view);
|
||||
}
|
||||
: function (arg, view) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
view.set(buf);
|
||||
return {
|
||||
read: arg.length,
|
||||
written: buf.length,
|
||||
};
|
||||
};
|
||||
|
||||
function passStringToWasm0(arg, malloc, realloc) {
|
||||
if (realloc === undefined) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
const ptr = malloc(buf.length, 1) >>> 0;
|
||||
getUint8Memory0()
|
||||
.subarray(ptr, ptr + buf.length)
|
||||
.set(buf);
|
||||
WASM_VECTOR_LEN = buf.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let len = arg.length;
|
||||
let ptr = malloc(len, 1) >>> 0;
|
||||
|
||||
const mem = getUint8Memory0();
|
||||
|
||||
let offset = 0;
|
||||
|
||||
for (; offset < len; offset++) {
|
||||
const code = arg.charCodeAt(offset);
|
||||
if (code > 0x7f) break;
|
||||
mem[ptr + offset] = code;
|
||||
}
|
||||
|
||||
if (offset !== len) {
|
||||
if (offset !== 0) {
|
||||
arg = arg.slice(offset);
|
||||
}
|
||||
ptr = realloc(ptr, len, (len = offset + arg.length * 3), 1) >>> 0;
|
||||
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
|
||||
const ret = encodeString(arg, view);
|
||||
|
||||
offset += ret.written;
|
||||
}
|
||||
|
||||
WASM_VECTOR_LEN = offset;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function isLikeNone(x) {
|
||||
return x === undefined || x === null;
|
||||
}
|
||||
|
||||
let cachedInt32Memory0 = null;
|
||||
|
||||
function getInt32Memory0() {
|
||||
if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {
|
||||
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedInt32Memory0;
|
||||
}
|
||||
|
||||
const cachedTextDecoder =
|
||||
typeof TextDecoder !== "undefined"
|
||||
? new TextDecoder("utf-8", { ignoreBOM: true, fatal: true })
|
||||
: {
|
||||
decode: () => {
|
||||
throw Error("TextDecoder not available");
|
||||
},
|
||||
};
|
||||
|
||||
if (typeof TextDecoder !== "undefined") {
|
||||
cachedTextDecoder.decode();
|
||||
}
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
ptr = ptr >>> 0;
|
||||
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
function addHeapObject(obj) {
|
||||
if (heap_next === heap.length) heap.push(heap.length + 1);
|
||||
const idx = heap_next;
|
||||
heap_next = heap[idx];
|
||||
|
||||
heap[idx] = obj;
|
||||
return idx;
|
||||
}
|
||||
|
||||
let cachedFloat64Memory0 = null;
|
||||
|
||||
function getFloat64Memory0() {
|
||||
if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) {
|
||||
cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedFloat64Memory0;
|
||||
}
|
||||
|
||||
function debugString(val) {
|
||||
// primitive types
|
||||
const type = typeof val;
|
||||
if (type == "number" || type == "boolean" || val == null) {
|
||||
return `${val}`;
|
||||
}
|
||||
if (type == "string") {
|
||||
return `"${val}"`;
|
||||
}
|
||||
if (type == "symbol") {
|
||||
const description = val.description;
|
||||
if (description == null) {
|
||||
return "Symbol";
|
||||
} else {
|
||||
return `Symbol(${description})`;
|
||||
}
|
||||
}
|
||||
if (type == "function") {
|
||||
const name = val.name;
|
||||
if (typeof name == "string" && name.length > 0) {
|
||||
return `Function(${name})`;
|
||||
} else {
|
||||
return "Function";
|
||||
}
|
||||
}
|
||||
// objects
|
||||
if (Array.isArray(val)) {
|
||||
const length = val.length;
|
||||
let debug = "[";
|
||||
if (length > 0) {
|
||||
debug += debugString(val[0]);
|
||||
}
|
||||
for (let i = 1; i < length; i++) {
|
||||
debug += ", " + debugString(val[i]);
|
||||
}
|
||||
debug += "]";
|
||||
return debug;
|
||||
}
|
||||
// Test for built-in
|
||||
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
|
||||
let className;
|
||||
if (builtInMatches.length > 1) {
|
||||
className = builtInMatches[1];
|
||||
} else {
|
||||
// Failed to match the standard '[object ClassName]'
|
||||
return toString.call(val);
|
||||
}
|
||||
if (className == "Object") {
|
||||
// we're a user defined class or Object
|
||||
// JSON.stringify avoids problems with cycles, and is generally much
|
||||
// easier than looping through ownProperties of `val`.
|
||||
try {
|
||||
return "Object(" + JSON.stringify(val) + ")";
|
||||
} catch (_) {
|
||||
return "Object";
|
||||
}
|
||||
}
|
||||
// errors
|
||||
if (val instanceof Error) {
|
||||
return `${val.name}: ${val.message}\n${val.stack}`;
|
||||
}
|
||||
// TODO we could test for more things here, like `Set`s and `Map`s.
|
||||
return className;
|
||||
}
|
||||
/**
|
||||
* @param {any} prev
|
||||
* @param {any} next
|
||||
* @returns {any}
|
||||
*/
|
||||
export function diff_filters(prev, next) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
wasm.diff_filters(retptr, addHeapObject(prev), addHeapObject(next));
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
||||
if (r2) {
|
||||
throw takeObject(r1);
|
||||
}
|
||||
return takeObject(r0);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} val
|
||||
* @returns {any}
|
||||
*/
|
||||
export function expand_filter(val) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
wasm.expand_filter(retptr, addHeapObject(val));
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
||||
if (r2) {
|
||||
throw takeObject(r1);
|
||||
}
|
||||
return takeObject(r0);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} prev
|
||||
* @param {any} next
|
||||
* @returns {any}
|
||||
*/
|
||||
export function get_diff(prev, next) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
wasm.get_diff(retptr, addHeapObject(prev), addHeapObject(next));
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
||||
if (r2) {
|
||||
throw takeObject(r1);
|
||||
}
|
||||
return takeObject(r0);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} val
|
||||
* @returns {any}
|
||||
*/
|
||||
export function flat_merge(val) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
wasm.flat_merge(retptr, addHeapObject(val));
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
||||
if (r2) {
|
||||
throw takeObject(r1);
|
||||
}
|
||||
return takeObject(r0);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} val
|
||||
* @returns {any}
|
||||
*/
|
||||
export function compress(val) {
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
wasm.compress(retptr, addHeapObject(val));
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
||||
if (r2) {
|
||||
throw takeObject(r1);
|
||||
}
|
||||
return takeObject(r0);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
}
|
||||
}
|
||||
|
||||
function handleError(f, args) {
|
||||
try {
|
||||
return f.apply(this, args);
|
||||
} catch (e) {
|
||||
wasm.__wbindgen_exn_store(addHeapObject(e));
|
||||
}
|
||||
}
|
||||
|
||||
async function __wbg_load(module, imports) {
|
||||
if (typeof Response === "function" && module instanceof Response) {
|
||||
if (typeof WebAssembly.instantiateStreaming === "function") {
|
||||
try {
|
||||
return await WebAssembly.instantiateStreaming(module, imports);
|
||||
} catch (e) {
|
||||
if (module.headers.get("Content-Type") != "application/wasm") {
|
||||
console.warn(
|
||||
"`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",
|
||||
e,
|
||||
);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bytes = await module.arrayBuffer();
|
||||
return await WebAssembly.instantiate(bytes, imports);
|
||||
} else {
|
||||
const instance = await WebAssembly.instantiate(module, imports);
|
||||
|
||||
if (instance instanceof WebAssembly.Instance) {
|
||||
return { instance, module };
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function __wbg_get_imports() {
|
||||
const imports = {};
|
||||
imports.wbg = {};
|
||||
imports.wbg.__wbindgen_object_drop_ref = function (arg0) {
|
||||
takeObject(arg0);
|
||||
};
|
||||
imports.wbg.__wbindgen_string_get = function (arg0, arg1) {
|
||||
const obj = getObject(arg1);
|
||||
const ret = typeof obj === "string" ? obj : undefined;
|
||||
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len1 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len1;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
|
||||
};
|
||||
imports.wbg.__wbindgen_is_object = function (arg0) {
|
||||
const val = getObject(arg0);
|
||||
const ret = typeof val === "object" && val !== null;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_is_undefined = function (arg0) {
|
||||
const ret = getObject(arg0) === undefined;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_in = function (arg0, arg1) {
|
||||
const ret = getObject(arg0) in getObject(arg1);
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_error_new = function (arg0, arg1) {
|
||||
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_object_clone_ref = function (arg0) {
|
||||
const ret = getObject(arg0);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_jsval_loose_eq = function (arg0, arg1) {
|
||||
const ret = getObject(arg0) == getObject(arg1);
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_boolean_get = function (arg0) {
|
||||
const v = getObject(arg0);
|
||||
const ret = typeof v === "boolean" ? (v ? 1 : 0) : 2;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_number_get = function (arg0, arg1) {
|
||||
const obj = getObject(arg1);
|
||||
const ret = typeof obj === "number" ? obj : undefined;
|
||||
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_number_new = function (arg0) {
|
||||
const ret = arg0;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_string_new = function (arg0, arg1) {
|
||||
const ret = getStringFromWasm0(arg0, arg1);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_getwithrefkey_5e6d9547403deab8 = function (arg0, arg1) {
|
||||
const ret = getObject(arg0)[getObject(arg1)];
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_set_841ac57cff3d672b = function (arg0, arg1, arg2) {
|
||||
getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
|
||||
};
|
||||
imports.wbg.__wbg_get_44be0491f933a435 = function (arg0, arg1) {
|
||||
const ret = getObject(arg0)[arg1 >>> 0];
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_length_fff51ee6522a1a18 = function (arg0) {
|
||||
const ret = getObject(arg0).length;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_new_898a68150f225f2e = function () {
|
||||
const ret = new Array();
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_is_function = function (arg0) {
|
||||
const ret = typeof getObject(arg0) === "function";
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_next_526fc47e980da008 = function (arg0) {
|
||||
const ret = getObject(arg0).next;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_next_ddb3312ca1c4e32a = function () {
|
||||
return handleError(function (arg0) {
|
||||
const ret = getObject(arg0).next();
|
||||
return addHeapObject(ret);
|
||||
}, arguments);
|
||||
};
|
||||
imports.wbg.__wbg_done_5c1f01fb660d73b5 = function (arg0) {
|
||||
const ret = getObject(arg0).done;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_value_1695675138684bd5 = function (arg0) {
|
||||
const ret = getObject(arg0).value;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_iterator_97f0c81209c6c35a = function () {
|
||||
const ret = Symbol.iterator;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_get_97b561fb56f034b5 = function () {
|
||||
return handleError(function (arg0, arg1) {
|
||||
const ret = Reflect.get(getObject(arg0), getObject(arg1));
|
||||
return addHeapObject(ret);
|
||||
}, arguments);
|
||||
};
|
||||
imports.wbg.__wbg_call_cb65541d95d71282 = function () {
|
||||
return handleError(function (arg0, arg1) {
|
||||
const ret = getObject(arg0).call(getObject(arg1));
|
||||
return addHeapObject(ret);
|
||||
}, arguments);
|
||||
};
|
||||
imports.wbg.__wbg_new_b51585de1b234aff = function () {
|
||||
const ret = new Object();
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_set_502d29070ea18557 = function (arg0, arg1, arg2) {
|
||||
getObject(arg0)[arg1 >>> 0] = takeObject(arg2);
|
||||
};
|
||||
imports.wbg.__wbg_isArray_4c24b343cb13cfb1 = function (arg0) {
|
||||
const ret = Array.isArray(getObject(arg0));
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_instanceof_ArrayBuffer_39ac22089b74fddb = function (arg0) {
|
||||
let result;
|
||||
try {
|
||||
result = getObject(arg0) instanceof ArrayBuffer;
|
||||
} catch {
|
||||
result = false;
|
||||
}
|
||||
const ret = result;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_isSafeInteger_bb8e18dd21c97288 = function (arg0) {
|
||||
const ret = Number.isSafeInteger(getObject(arg0));
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_buffer_085ec1f694018c4f = function (arg0) {
|
||||
const ret = getObject(arg0).buffer;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_new_8125e318e6245eed = function (arg0) {
|
||||
const ret = new Uint8Array(getObject(arg0));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_set_5cf90238115182c3 = function (arg0, arg1, arg2) {
|
||||
getObject(arg0).set(getObject(arg1), arg2 >>> 0);
|
||||
};
|
||||
imports.wbg.__wbg_length_72e2208bbc0efc61 = function (arg0) {
|
||||
const ret = getObject(arg0).length;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_instanceof_Uint8Array_d8d9cb2b8e8ac1d4 = function (arg0) {
|
||||
let result;
|
||||
try {
|
||||
result = getObject(arg0) instanceof Uint8Array;
|
||||
} catch {
|
||||
result = false;
|
||||
}
|
||||
const ret = result;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_debug_string = function (arg0, arg1) {
|
||||
const ret = debugString(getObject(arg1));
|
||||
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len1;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
|
||||
};
|
||||
imports.wbg.__wbindgen_throw = function (arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
};
|
||||
imports.wbg.__wbindgen_memory = function () {
|
||||
const ret = wasm.memory;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
function __wbg_init_memory(imports, maybe_memory) {}
|
||||
|
||||
function __wbg_finalize_init(instance, module) {
|
||||
wasm = instance.exports;
|
||||
__wbg_init.__wbindgen_wasm_module = module;
|
||||
cachedFloat64Memory0 = null;
|
||||
cachedInt32Memory0 = null;
|
||||
cachedUint8Memory0 = null;
|
||||
|
||||
return wasm;
|
||||
}
|
||||
|
||||
function initSync(module) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
const imports = __wbg_get_imports();
|
||||
|
||||
__wbg_init_memory(imports);
|
||||
|
||||
if (!(module instanceof WebAssembly.Module)) {
|
||||
module = new WebAssembly.Module(module);
|
||||
}
|
||||
|
||||
const instance = new WebAssembly.Instance(module, imports);
|
||||
|
||||
return __wbg_finalize_init(instance, module);
|
||||
}
|
||||
|
||||
async function __wbg_init(input) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
if (typeof input === "undefined") {
|
||||
input = new URL("system_query_bg.wasm", import.meta.url);
|
||||
}
|
||||
const imports = __wbg_get_imports();
|
||||
|
||||
if (
|
||||
typeof input === "string" ||
|
||||
(typeof Request === "function" && input instanceof Request) ||
|
||||
(typeof URL === "function" && input instanceof URL)
|
||||
) {
|
||||
input = fetch(input);
|
||||
}
|
||||
|
||||
__wbg_init_memory(imports);
|
||||
|
||||
const { instance, module } = await __wbg_load(await input, imports);
|
||||
|
||||
return __wbg_finalize_init(instance, module);
|
||||
}
|
||||
|
||||
export { initSync };
|
||||
export default __wbg_init;
|
BIN
packages/system-query/pkg/system_query_bg.wasm
Normal file
BIN
packages/system-query/pkg/system_query_bg.wasm
Normal file
Binary file not shown.
12
packages/system-query/pkg/system_query_bg.wasm.d.ts
vendored
Normal file
12
packages/system-query/pkg/system_query_bg.wasm.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export const memory: WebAssembly.Memory;
|
||||
export function diff_filters(a: number, b: number, c: number): void;
|
||||
export function expand_filter(a: number, b: number): void;
|
||||
export function get_diff(a: number, b: number, c: number): void;
|
||||
export function flat_merge(a: number, b: number): void;
|
||||
export function compress(a: number, b: number): void;
|
||||
export function __wbindgen_malloc(a: number, b: number): number;
|
||||
export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number;
|
||||
export function __wbindgen_add_to_stack_pointer(a: number): number;
|
||||
export function __wbindgen_exn_store(a: number): void;
|
172
packages/system-query/src/diff.rs
Normal file
172
packages/system-query/src/diff.rs
Normal file
@ -0,0 +1,172 @@
|
||||
use crate::FlatReqFilter;
|
||||
use itertools::Itertools;
|
||||
|
||||
pub fn diff_filter(prev: &Vec<FlatReqFilter>, next: &Vec<FlatReqFilter>) -> Vec<FlatReqFilter> {
|
||||
let mut added: Vec<FlatReqFilter> = vec![];
|
||||
|
||||
for n in next.iter() {
|
||||
if !prev.iter().contains(&n) {
|
||||
added.push(n.clone())
|
||||
}
|
||||
}
|
||||
|
||||
added
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn simple_diff_same() {
|
||||
let prev = vec![FlatReqFilter {
|
||||
id: Some("a".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
}];
|
||||
let next = vec![FlatReqFilter {
|
||||
id: Some("a".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
}];
|
||||
|
||||
let result = diff_filter(&prev, &next);
|
||||
assert_eq!(result, vec![])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_diff_add() {
|
||||
let prev = vec![FlatReqFilter {
|
||||
id: Some("a".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
}];
|
||||
let next = vec![
|
||||
FlatReqFilter {
|
||||
id: Some("a".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: Some("b".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
];
|
||||
|
||||
let result = diff_filter(&prev, &next);
|
||||
assert_eq!(
|
||||
result,
|
||||
vec![FlatReqFilter {
|
||||
id: Some("b".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
}]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_diff_replace() {
|
||||
let prev = vec![FlatReqFilter {
|
||||
id: Some("a".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
}];
|
||||
let next = vec![FlatReqFilter {
|
||||
id: Some("b".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
}];
|
||||
|
||||
let result = diff_filter(&prev, &next);
|
||||
assert_eq!(
|
||||
result,
|
||||
vec![FlatReqFilter {
|
||||
id: Some("b".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
}]
|
||||
)
|
||||
}
|
||||
}
|
732
packages/system-query/src/filter.rs
Normal file
732
packages/system-query/src/filter.rs
Normal file
@ -0,0 +1,732 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
#[cfg(test)]
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use itertools::Itertools;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum StringOrNumberEntry<'a> {
|
||||
String((&'static str, &'a String)),
|
||||
Number((&'static str, &'a i32)),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct ReqFilter {
|
||||
#[serde(rename = "ids", skip_serializing_if = "Option::is_none")]
|
||||
pub ids: Option<HashSet<String>>,
|
||||
#[serde(rename = "authors", skip_serializing_if = "Option::is_none")]
|
||||
pub authors: Option<HashSet<String>>,
|
||||
#[serde(rename = "kinds", skip_serializing_if = "Option::is_none")]
|
||||
pub kinds: Option<HashSet<i32>>,
|
||||
#[serde(rename = "#e", skip_serializing_if = "Option::is_none")]
|
||||
pub e_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "#p", skip_serializing_if = "Option::is_none")]
|
||||
pub p_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "#t", skip_serializing_if = "Option::is_none")]
|
||||
pub t_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "#d", skip_serializing_if = "Option::is_none")]
|
||||
pub d_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "#r", skip_serializing_if = "Option::is_none")]
|
||||
pub r_tag: Option<HashSet<String>>,
|
||||
#[serde(rename = "search", skip_serializing_if = "Option::is_none")]
|
||||
pub search: Option<HashSet<String>>,
|
||||
#[serde(rename = "since", skip_serializing_if = "Option::is_none")]
|
||||
pub since: Option<i32>,
|
||||
#[serde(rename = "until", skip_serializing_if = "Option::is_none")]
|
||||
pub until: Option<i32>,
|
||||
#[serde(rename = "limit", skip_serializing_if = "Option::is_none")]
|
||||
pub limit: Option<i32>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Debug for ReqFilter {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&serde_json::to_string(self).unwrap().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, PartialOrd, Clone, Serialize, Deserialize)]
|
||||
pub struct FlatReqFilter {
|
||||
#[serde(rename = "ids", skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<String>,
|
||||
#[serde(rename = "authors", skip_serializing_if = "Option::is_none")]
|
||||
pub author: Option<String>,
|
||||
#[serde(rename = "kinds", skip_serializing_if = "Option::is_none")]
|
||||
pub kind: Option<i32>,
|
||||
#[serde(rename = "#e", skip_serializing_if = "Option::is_none")]
|
||||
pub e_tag: Option<String>,
|
||||
#[serde(rename = "#p", skip_serializing_if = "Option::is_none")]
|
||||
pub p_tag: Option<String>,
|
||||
#[serde(rename = "#t", skip_serializing_if = "Option::is_none")]
|
||||
pub t_tag: Option<String>,
|
||||
#[serde(rename = "#d", skip_serializing_if = "Option::is_none")]
|
||||
pub d_tag: Option<String>,
|
||||
#[serde(rename = "#r", skip_serializing_if = "Option::is_none")]
|
||||
pub r_tag: Option<String>,
|
||||
#[serde(rename = "search", skip_serializing_if = "Option::is_none")]
|
||||
pub search: Option<String>,
|
||||
#[serde(rename = "since", skip_serializing_if = "Option::is_none")]
|
||||
pub since: Option<i32>,
|
||||
#[serde(rename = "until", skip_serializing_if = "Option::is_none")]
|
||||
pub until: Option<i32>,
|
||||
#[serde(rename = "limit", skip_serializing_if = "Option::is_none")]
|
||||
pub limit: Option<i32>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Debug for FlatReqFilter {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&serde_json::to_string(self).unwrap().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Distance {
|
||||
/// Calculate the distance in terms of similarity for merging
|
||||
///
|
||||
/// The goal of this function is to find 2 filters which are very similar where
|
||||
/// one filter may have a single property change like so:
|
||||
///
|
||||
/// ```javascript
|
||||
/// const a = { "kinds": 1, "authors": "a", "since": 99 };
|
||||
/// const b = { "kinds": 1, "authors": "b", "since": 99 };
|
||||
/// ```
|
||||
/// In this case these 2 filters could be merged because their distance is `1`
|
||||
/// ```javascript
|
||||
/// const result = { "kinds": [1], "authors": ["a", "b"], "since": 99 };
|
||||
/// ```
|
||||
fn distance(&self, other: &Self) -> u32;
|
||||
}
|
||||
|
||||
pub trait CanMerge {
|
||||
fn can_merge(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
impl Distance for FlatReqFilter {
|
||||
fn distance(&self, b: &Self) -> u32 {
|
||||
let mut ret = 0u32;
|
||||
|
||||
ret += prop_dist(&self.id, &b.id);
|
||||
ret += prop_dist(&self.kind, &b.kind);
|
||||
ret += prop_dist(&self.author, &b.author);
|
||||
ret += prop_dist(&self.e_tag, &b.e_tag);
|
||||
ret += prop_dist(&self.p_tag, &b.p_tag);
|
||||
ret += prop_dist(&self.d_tag, &b.d_tag);
|
||||
ret += prop_dist(&self.r_tag, &b.r_tag);
|
||||
ret += prop_dist(&self.t_tag, &b.t_tag);
|
||||
ret += prop_dist(&self.search, &b.search);
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl CanMerge for FlatReqFilter {
|
||||
fn can_merge(&self, other: &Self) -> bool {
|
||||
if self.since != other.since
|
||||
|| self.until != other.until
|
||||
|| self.limit != other.limit
|
||||
|| self.search != other.search
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
self.distance(other) <= 1
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<&FlatReqFilter>> for ReqFilter {
|
||||
fn from(value: Vec<&FlatReqFilter>) -> Self {
|
||||
let ret = ReqFilter {
|
||||
ids: None,
|
||||
authors: None,
|
||||
kinds: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
};
|
||||
value.iter().fold(ret, |mut acc, x| {
|
||||
array_prop_append(&x.id, &mut acc.ids);
|
||||
array_prop_append(&x.author, &mut acc.authors);
|
||||
array_prop_append(&x.kind, &mut acc.kinds);
|
||||
array_prop_append(&x.e_tag, &mut acc.e_tag);
|
||||
array_prop_append(&x.p_tag, &mut acc.p_tag);
|
||||
array_prop_append(&x.t_tag, &mut acc.t_tag);
|
||||
array_prop_append(&x.d_tag, &mut acc.d_tag);
|
||||
array_prop_append(&x.r_tag, &mut acc.r_tag);
|
||||
array_prop_append(&x.search, &mut acc.search);
|
||||
acc.since = x.since;
|
||||
acc.until = x.until;
|
||||
acc.limit = x.limit;
|
||||
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<&ReqFilter>> for ReqFilter {
|
||||
fn from(value: Vec<&ReqFilter>) -> Self {
|
||||
let ret = ReqFilter {
|
||||
ids: None,
|
||||
authors: None,
|
||||
kinds: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
};
|
||||
value.iter().fold(ret, |mut acc, x| {
|
||||
array_prop_append_vec(&x.ids, &mut acc.ids);
|
||||
array_prop_append_vec(&x.authors, &mut acc.authors);
|
||||
array_prop_append_vec(&x.kinds, &mut acc.kinds);
|
||||
array_prop_append_vec(&x.e_tag, &mut acc.e_tag);
|
||||
array_prop_append_vec(&x.p_tag, &mut acc.p_tag);
|
||||
array_prop_append_vec(&x.t_tag, &mut acc.t_tag);
|
||||
array_prop_append_vec(&x.d_tag, &mut acc.d_tag);
|
||||
array_prop_append_vec(&x.r_tag, &mut acc.r_tag);
|
||||
array_prop_append_vec(&x.search, &mut acc.search);
|
||||
acc.since = x.since;
|
||||
acc.until = x.until;
|
||||
acc.limit = x.limit;
|
||||
|
||||
acc
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<FlatReqFilter>> for &ReqFilter {
|
||||
fn into(self) -> Vec<FlatReqFilter> {
|
||||
let mut ret: Vec<FlatReqFilter> = Vec::new();
|
||||
|
||||
let mut inputs: Vec<Vec<StringOrNumberEntry>> = vec![];
|
||||
if let Some(ids) = &self.ids {
|
||||
let t_ids = ids
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("id", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(authors) = &self.authors {
|
||||
let t_ids = authors
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("author", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(kinds) = &self.kinds {
|
||||
let t_ids = kinds
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::Number(("kind", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(e_tags) = &self.e_tag {
|
||||
let t_ids = e_tags
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("e_tag", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(p_tags) = &self.p_tag {
|
||||
let t_ids = p_tags
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("p_tag", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(d_tags) = &self.d_tag {
|
||||
let t_ids = d_tags
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("d_tag", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(t_tags) = &self.t_tag {
|
||||
let t_ids = t_tags
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("t_tag", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(r_tags) = &self.r_tag {
|
||||
let t_ids = r_tags
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("r_tag", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
if let Some(search) = &self.search {
|
||||
let t_ids = search
|
||||
.iter()
|
||||
.map(|z| StringOrNumberEntry::String(("search", z)))
|
||||
.collect();
|
||||
inputs.push(t_ids);
|
||||
}
|
||||
|
||||
for p in inputs.iter().multi_cartesian_product() {
|
||||
ret.push(FlatReqFilter {
|
||||
id: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("id") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
author: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("author") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
kind: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::Number((k, v)) = q {
|
||||
if (*k).eq("kind") {
|
||||
return Some((*v).clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
e_tag: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("e_tag") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
p_tag: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("p_tag") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
t_tag: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("t_tag") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
d_tag: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("d_tag") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
r_tag: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("r_tag") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
search: p.iter().find_map(|q| {
|
||||
if let StringOrNumberEntry::String((k, v)) = q {
|
||||
if (*k).eq("search") {
|
||||
return Some((*v).to_string());
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
since: self.since,
|
||||
until: self.until,
|
||||
limit: self.limit,
|
||||
})
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
impl Distance for ReqFilter {
|
||||
fn distance(&self, b: &Self) -> u32 {
|
||||
let mut ret = 0u32;
|
||||
|
||||
ret += prop_dist_vec(&self.ids, &b.ids);
|
||||
ret += prop_dist_vec(&self.kinds, &b.kinds);
|
||||
ret += prop_dist_vec(&self.authors, &b.authors);
|
||||
ret += prop_dist_vec(&self.e_tag, &b.e_tag);
|
||||
ret += prop_dist_vec(&self.p_tag, &b.p_tag);
|
||||
ret += prop_dist_vec(&self.d_tag, &b.d_tag);
|
||||
ret += prop_dist_vec(&self.r_tag, &b.r_tag);
|
||||
ret += prop_dist_vec(&self.t_tag, &b.t_tag);
|
||||
ret += prop_dist_vec(&self.search, &b.search);
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl CanMerge for ReqFilter {
|
||||
fn can_merge(&self, other: &Self) -> bool {
|
||||
if self.since != other.since
|
||||
|| self.until != other.until
|
||||
|| self.limit != other.limit
|
||||
|| self.search != other.search
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
self.distance(other) <= 1
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn prop_dist<T: Eq>(a: &Option<T>, b: &Option<T>) -> u32 {
|
||||
if (a.is_some() && b.is_none()) || (a.is_none() && b.is_some()) {
|
||||
return 10;
|
||||
} else if a.is_some() && a != b {
|
||||
return 1;
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn prop_dist_vec<T: Eq + Hash>(a: &Option<HashSet<T>>, b: &Option<HashSet<T>>) -> u32 {
|
||||
if (a.is_some() && b.is_none()) || (a.is_none() && b.is_some()) {
|
||||
return 10;
|
||||
}
|
||||
match (a, b) {
|
||||
(Some(aa), Some(bb)) => {
|
||||
if aa.len() != bb.len() {
|
||||
1
|
||||
} else if aa == bb {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
(None, None) => 0,
|
||||
_ => panic!("Should not reach here!"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn array_prop_append<T: Clone + Eq + Hash>(val: &Option<T>, arr: &mut Option<HashSet<T>>) {
|
||||
if let Some(ap) = val {
|
||||
if arr.is_none() {
|
||||
*arr = Some(HashSet::from([ap.clone()]))
|
||||
} else {
|
||||
arr.as_mut().unwrap().insert(ap.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn array_prop_append_vec<T: Clone + Eq + Hash>(
|
||||
val: &Option<HashSet<T>>,
|
||||
arr: &mut Option<HashSet<T>>,
|
||||
) {
|
||||
if let Some(ap) = val {
|
||||
if arr.is_none() {
|
||||
*arr = Some(ap.clone())
|
||||
} else {
|
||||
ap.iter().for_each(|v| {
|
||||
arr.as_mut().unwrap().insert((*v).clone());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::ReqFilter;
|
||||
use std::collections::HashSet;
|
||||
use crate::filter::FlatReqFilter;
|
||||
|
||||
#[test]
|
||||
fn test_expand_filter() {
|
||||
let input = ReqFilter {
|
||||
authors: Some(HashSet::from([
|
||||
"a".to_owned(),
|
||||
"b".to_owned(),
|
||||
"c".to_owned(),
|
||||
])),
|
||||
kinds: Some(HashSet::from([1, 2, 3])),
|
||||
ids: Some(HashSet::from(["x".to_owned(), "y".to_owned()])),
|
||||
p_tag: Some(HashSet::from(["a".to_owned()])),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
};
|
||||
|
||||
let output : Vec<FlatReqFilter> = (&input).into();
|
||||
let expected = vec![
|
||||
FlatReqFilter {
|
||||
author: Some("a".to_owned()),
|
||||
kind: Some(1),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("a".to_owned()),
|
||||
kind: Some(1),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("a".to_owned()),
|
||||
kind: Some(2),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("a".to_owned()),
|
||||
kind: Some(2),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("a".to_owned()),
|
||||
kind: Some(3),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("a".to_owned()),
|
||||
kind: Some(3),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("b".to_owned()),
|
||||
kind: Some(1),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("b".to_owned()),
|
||||
kind: Some(1),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("b".to_owned()),
|
||||
kind: Some(2),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("b".to_owned()),
|
||||
kind: Some(2),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("b".to_owned()),
|
||||
kind: Some(3),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("b".to_owned()),
|
||||
kind: Some(3),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("c".to_owned()),
|
||||
kind: Some(1),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("c".to_owned()),
|
||||
kind: Some(1),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("c".to_owned()),
|
||||
kind: Some(2),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("c".to_owned()),
|
||||
kind: Some(2),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("c".to_owned()),
|
||||
kind: Some(3),
|
||||
id: Some("x".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
author: Some("c".to_owned()),
|
||||
kind: Some(3),
|
||||
id: Some("y".to_owned()),
|
||||
p_tag: Some("a".to_owned()),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: Some(99),
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
e_tag: None,
|
||||
},
|
||||
];
|
||||
assert_eq!(output.len(), expected.len());
|
||||
output.iter().for_each(|a| assert!(expected.contains(a)));
|
||||
}
|
||||
}
|
151
packages/system-query/src/lib.rs
Normal file
151
packages/system-query/src/lib.rs
Normal file
@ -0,0 +1,151 @@
|
||||
use crate::filter::{FlatReqFilter, ReqFilter};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub mod diff;
|
||||
pub mod filter;
|
||||
pub mod merge;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn diff_filters(prev: JsValue, next: JsValue) -> Result<JsValue, JsValue> {
|
||||
let prev_parsed: Vec<FlatReqFilter> = serde_wasm_bindgen::from_value(prev)?;
|
||||
let next_parsed: Vec<FlatReqFilter> = serde_wasm_bindgen::from_value(next)?;
|
||||
let result = diff::diff_filter(&prev_parsed, &next_parsed);
|
||||
Ok(serde_wasm_bindgen::to_value(&result)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn expand_filter(val: JsValue) -> Result<JsValue, JsValue> {
|
||||
let parsed: ReqFilter = serde_wasm_bindgen::from_value(val)?;
|
||||
let result: Vec<FlatReqFilter> = (&parsed).into();
|
||||
Ok(serde_wasm_bindgen::to_value(&result)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn get_diff(prev: JsValue, next: JsValue) -> Result<JsValue, JsValue> {
|
||||
let prev_parsed: Vec<ReqFilter> = serde_wasm_bindgen::from_value(prev)?;
|
||||
let next_parsed: Vec<ReqFilter> = serde_wasm_bindgen::from_value(next)?;
|
||||
let expanded_prev: Vec<FlatReqFilter> = prev_parsed
|
||||
.iter()
|
||||
.flat_map(|v| {
|
||||
let vec: Vec<FlatReqFilter> = v.into();
|
||||
vec
|
||||
})
|
||||
.collect();
|
||||
let expanded_next: Vec<FlatReqFilter> = next_parsed
|
||||
.iter()
|
||||
.flat_map(|v| {
|
||||
let vec: Vec<FlatReqFilter> = v.into();
|
||||
vec
|
||||
})
|
||||
.collect();
|
||||
let result = diff::diff_filter(&expanded_prev, &expanded_next);
|
||||
Ok(serde_wasm_bindgen::to_value(&result)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn flat_merge(val: JsValue) -> Result<JsValue, JsValue> {
|
||||
let val_parsed: Vec<FlatReqFilter> = serde_wasm_bindgen::from_value(val)?;
|
||||
let result = merge::merge::<FlatReqFilter, ReqFilter>(val_parsed.iter().collect());
|
||||
Ok(serde_wasm_bindgen::to_value(&result)?)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn compress(val: JsValue) -> Result<JsValue, JsValue> {
|
||||
let val_parsed: Vec<ReqFilter> = serde_wasm_bindgen::from_value(val)?;
|
||||
let result = merge::merge::<ReqFilter, ReqFilter>(val_parsed.iter().collect());
|
||||
Ok(serde_wasm_bindgen::to_value(&result)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use itertools::Itertools;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[test]
|
||||
fn flat_merge_expanded() {
|
||||
let input = vec![
|
||||
ReqFilter {
|
||||
ids: None,
|
||||
kinds: Some(HashSet::from([1, 6969, 6])),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
authors: Some(HashSet::from([
|
||||
"kieran".to_string(),
|
||||
"snort".to_string(),
|
||||
"c".to_string(),
|
||||
"d".to_string(),
|
||||
"e".to_string(),
|
||||
])),
|
||||
since: Some(1),
|
||||
until: Some(100),
|
||||
search: None,
|
||||
limit: None,
|
||||
},
|
||||
ReqFilter {
|
||||
ids: None,
|
||||
kinds: Some(HashSet::from([4])),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
authors: Some(HashSet::from(["kieran".to_string()])),
|
||||
limit: None,
|
||||
},
|
||||
ReqFilter {
|
||||
ids: None,
|
||||
authors: None,
|
||||
kinds: Some(HashSet::from([4])),
|
||||
e_tag: None,
|
||||
p_tag: Some(HashSet::from(["kieran".to_string()])),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
ReqFilter {
|
||||
ids: None,
|
||||
kinds: Some(HashSet::from([1000])),
|
||||
authors: Some(HashSet::from(["snort".to_string()])),
|
||||
p_tag: Some(HashSet::from(["kieran".to_string()])),
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
e_tag: None,
|
||||
limit: None,
|
||||
},
|
||||
];
|
||||
|
||||
let expanded: Vec<FlatReqFilter> = input
|
||||
.iter()
|
||||
.flat_map(|v| {
|
||||
let r: Vec<FlatReqFilter> = v.into();
|
||||
r
|
||||
})
|
||||
.sorted_by(|_, _| {
|
||||
if rand::random() {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let merged_expanded: Vec<ReqFilter> = merge::merge(expanded.iter().collect());
|
||||
assert_eq!(merged_expanded.len(), input.len());
|
||||
assert!(merged_expanded.iter().all(|v| input.contains(v)));
|
||||
}
|
||||
}
|
444
packages/system-query/src/merge.rs
Normal file
444
packages/system-query/src/merge.rs
Normal file
@ -0,0 +1,444 @@
|
||||
use crate::filter::CanMerge;
|
||||
|
||||
pub fn merge<'a, T, Z>(all: Vec<&'a T>) -> Vec<Z>
|
||||
where
|
||||
T: CanMerge,
|
||||
for<'b> Z: CanMerge + From<Vec<&'a T>> + From<Vec<&'b Z>>,
|
||||
{
|
||||
let mut ret: Vec<Z> = merge_once(all);
|
||||
loop {
|
||||
let last_len = ret.len();
|
||||
ret = merge_once(ret.iter().collect());
|
||||
if last_len == ret.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn merge_once<'a, T, Z>(all: Vec<&'a T>) -> Vec<Z>
|
||||
where
|
||||
T: CanMerge,
|
||||
Z: From<Vec<&'a T>>,
|
||||
{
|
||||
let mut ret: Vec<Z> = vec![];
|
||||
if all.is_empty() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
let merge_sets: Vec<Vec<&T>> = vec![vec![all.first().unwrap()]];
|
||||
let merge_sets = all.iter().skip(1).fold(merge_sets, |mut acc, x| {
|
||||
let mut did_match = false;
|
||||
for y in acc.iter_mut() {
|
||||
if y.iter().all(|z| z.can_merge(x)) {
|
||||
y.push(x);
|
||||
did_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !did_match {
|
||||
acc.push(vec![x]);
|
||||
}
|
||||
acc
|
||||
});
|
||||
|
||||
for s in merge_sets {
|
||||
ret.push(Z::from(s));
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::filter::{Distance, FlatReqFilter, ReqFilter};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[test]
|
||||
fn distance() {
|
||||
let a = FlatReqFilter {
|
||||
id: Some("a".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
};
|
||||
let b = FlatReqFilter {
|
||||
id: Some("a".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
};
|
||||
let c = FlatReqFilter {
|
||||
id: Some("c".to_owned()),
|
||||
author: None,
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
};
|
||||
let d = FlatReqFilter {
|
||||
id: Some("a".to_owned()),
|
||||
author: None,
|
||||
kind: Some(1),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
};
|
||||
let e = FlatReqFilter {
|
||||
id: Some("e".to_owned()),
|
||||
author: None,
|
||||
kind: Some(1),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
};
|
||||
assert_eq!(a.distance(&b), 0);
|
||||
assert_eq!(a.distance(&c), 1);
|
||||
assert_eq!(a.distance(&d), 10);
|
||||
assert_eq!(a.distance(&e), 11);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_set() {
|
||||
let a = FlatReqFilter {
|
||||
id: Some("0".to_owned()),
|
||||
author: Some("a".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
};
|
||||
let b = FlatReqFilter {
|
||||
id: Some("0".to_owned()),
|
||||
author: Some("b".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
};
|
||||
|
||||
let output = ReqFilter {
|
||||
ids: Some(HashSet::from(["0".to_owned()])),
|
||||
authors: Some(HashSet::from(["a".to_owned(), "b".to_owned()])),
|
||||
kinds: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
};
|
||||
assert_eq!(ReqFilter::from(vec![&a, &b]), output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_merge_filters() {
|
||||
let a = FlatReqFilter {
|
||||
id: Some("0".to_owned()),
|
||||
author: Some("a".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
};
|
||||
let b = FlatReqFilter {
|
||||
id: Some("0".to_owned()),
|
||||
author: Some("b".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: Some(10),
|
||||
};
|
||||
let c = FlatReqFilter {
|
||||
id: Some("0".to_owned()),
|
||||
author: Some("b".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: Some(100),
|
||||
};
|
||||
assert!(&a.can_merge(&b));
|
||||
assert!(!&b.can_merge(&c));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flat_merge() {
|
||||
let input = vec![
|
||||
FlatReqFilter {
|
||||
id: Some("0".to_owned()),
|
||||
author: Some("a".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: Some("0".to_owned()),
|
||||
author: Some("b".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: None,
|
||||
author: None,
|
||||
kind: Some(1),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: None,
|
||||
author: None,
|
||||
kind: Some(2),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: None,
|
||||
author: None,
|
||||
kind: Some(2),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: Some("0".to_owned()),
|
||||
author: Some("c".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: None,
|
||||
author: Some("c".to_owned()),
|
||||
kind: Some(1),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: None,
|
||||
author: Some("c".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: Some(100),
|
||||
},
|
||||
FlatReqFilter {
|
||||
id: Some("1".to_owned()),
|
||||
author: Some("c".to_owned()),
|
||||
kind: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
];
|
||||
let output = vec![
|
||||
ReqFilter {
|
||||
ids: Some(HashSet::from(["0".to_owned()])),
|
||||
authors: Some(HashSet::from([
|
||||
"a".to_owned(),
|
||||
"b".to_owned(),
|
||||
"c".to_owned(),
|
||||
])),
|
||||
kinds: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
ReqFilter {
|
||||
ids: None,
|
||||
authors: None,
|
||||
kinds: Some(HashSet::from([1, 2])),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
ReqFilter {
|
||||
ids: None,
|
||||
authors: Some(HashSet::from(["c".to_owned()])),
|
||||
kinds: Some(HashSet::from([1])),
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
ReqFilter {
|
||||
ids: None,
|
||||
authors: Some(HashSet::from(["c".to_owned()])),
|
||||
kinds: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: Some(100),
|
||||
},
|
||||
ReqFilter {
|
||||
ids: Some(HashSet::from(["1".to_owned()])),
|
||||
authors: Some(HashSet::from(["c".to_owned()])),
|
||||
kinds: None,
|
||||
e_tag: None,
|
||||
p_tag: None,
|
||||
t_tag: None,
|
||||
d_tag: None,
|
||||
r_tag: None,
|
||||
search: None,
|
||||
since: None,
|
||||
until: None,
|
||||
limit: None,
|
||||
},
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
merge::<FlatReqFilter, ReqFilter>(input.iter().collect()),
|
||||
output
|
||||
)
|
||||
}
|
||||
}
|
0
packages/system-query/src/utils.rs
Normal file
0
packages/system-query/src/utils.rs
Normal file
13
packages/system-query/system-query.iml
Normal file
13
packages/system-query/system-query.iml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="RUST_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
@ -34,6 +34,7 @@
|
||||
"@noble/hashes": "^1.3.2",
|
||||
"@scure/base": "^1.1.2",
|
||||
"@snort/shared": "^1.0.5",
|
||||
"@snort/system-query": "workspace:*",
|
||||
"@stablelib/xchacha20": "^1.0.1",
|
||||
"debug": "^4.3.4",
|
||||
"dexie": "^3.2.4",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ReqFilter, UsersRelays } from ".";
|
||||
import { dedupe, unwrap } from "@snort/shared";
|
||||
import debug from "debug";
|
||||
import { FlatReqFilter } from "request-expander";
|
||||
import { FlatReqFilter } from "./query-optimizer";
|
||||
|
||||
const PickNRelays = 2;
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { AuthHandler, RelaySettings, ConnectionStateSnapshot } from "./connection";
|
||||
import { RequestBuilder } from "./request-builder";
|
||||
import { NoteStore, NoteStoreHook, NoteStoreSnapshotData } from "./note-collection";
|
||||
import { NoteStore, NoteStoreSnapshotData } from "./note-collection";
|
||||
import { Query } from "./query";
|
||||
import { NostrEvent, ReqFilter, TaggedNostrEvent } from "./nostr";
|
||||
import { ProfileLoaderService } from "./profile-cache";
|
||||
import { RelayCache } from "./gossip-model";
|
||||
import { QueryOptimizer } from "./query-optimizer";
|
||||
|
||||
export * from "./nostr-system";
|
||||
export { default as EventKind } from "./event-kind";
|
||||
@ -24,6 +26,7 @@ export * from "./signer";
|
||||
export * from "./text";
|
||||
export * from "./pow";
|
||||
export * from "./pow-util";
|
||||
export * from "./query-optimizer";
|
||||
|
||||
export * from "./impl/nip4";
|
||||
export * from "./impl/nip44";
|
||||
@ -96,6 +99,16 @@ export interface SystemInterface {
|
||||
* Profile cache/loader
|
||||
*/
|
||||
get ProfileLoader(): ProfileLoaderService;
|
||||
|
||||
/**
|
||||
* Relay cache for "Gossip" model
|
||||
*/
|
||||
get RelayCache(): RelayCache;
|
||||
|
||||
/**
|
||||
* Query optimizer
|
||||
*/
|
||||
get QueryOptimizer(): QueryOptimizer;
|
||||
}
|
||||
|
||||
export interface SystemSnapshot {
|
||||
|
@ -4,7 +4,7 @@ import { unwrap, sanitizeRelayUrl, ExternalStore, FeedCache } from "@snort/share
|
||||
import { NostrEvent, TaggedNostrEvent } from "./nostr";
|
||||
import { AuthHandler, Connection, RelaySettings, ConnectionStateSnapshot } from "./connection";
|
||||
import { Query } from "./query";
|
||||
import { NoteCollection, NoteStore, NoteStoreHook, NoteStoreSnapshotData } from "./note-collection";
|
||||
import { NoteCollection, NoteStore, NoteStoreSnapshotData } from "./note-collection";
|
||||
import { BuiltRawReqFilter, RequestBuilder } from "./request-builder";
|
||||
import { RelayMetricHandler } from "./relay-metric-handler";
|
||||
import {
|
||||
@ -20,6 +20,8 @@ import {
|
||||
UsersRelays,
|
||||
} from ".";
|
||||
import { EventsCache } from "./cache/events";
|
||||
import { RelayCache } from "./gossip-model";
|
||||
import { QueryOptimizer, DefaultQueryOptimizer } from "./query-optimizer";
|
||||
|
||||
/**
|
||||
* Manages nostr content retrieval system
|
||||
@ -72,12 +74,18 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
*/
|
||||
#eventsCache: FeedCache<NostrEvent>;
|
||||
|
||||
/**
|
||||
* Query optimizer instance
|
||||
*/
|
||||
#queryOptimizer: QueryOptimizer;
|
||||
|
||||
constructor(props: {
|
||||
authHandler?: AuthHandler;
|
||||
relayCache?: FeedCache<UsersRelays>;
|
||||
profileCache?: FeedCache<MetadataCache>;
|
||||
relayMetrics?: FeedCache<RelayMetrics>;
|
||||
eventsCache?: FeedCache<NostrEvent>;
|
||||
queryOptimizer?: QueryOptimizer;
|
||||
}) {
|
||||
super();
|
||||
this.#handleAuth = props.authHandler;
|
||||
@ -85,6 +93,7 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
this.#profileCache = props.profileCache ?? new UserProfileCache();
|
||||
this.#relayMetricsCache = props.relayMetrics ?? new RelayMetricCache();
|
||||
this.#eventsCache = props.eventsCache ?? new EventsCache();
|
||||
this.#queryOptimizer = props.queryOptimizer ?? DefaultQueryOptimizer;
|
||||
|
||||
this.#profileLoader = new ProfileLoaderService(this, this.#profileCache);
|
||||
this.#relayMetrics = new RelayMetricHandler(this.#relayMetricsCache);
|
||||
@ -92,9 +101,6 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
}
|
||||
HandleAuth?: AuthHandler | undefined;
|
||||
|
||||
/**
|
||||
* Profile loader service allows you to request profiles
|
||||
*/
|
||||
get ProfileLoader() {
|
||||
return this.#profileLoader;
|
||||
}
|
||||
@ -103,6 +109,14 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
return [...this.#sockets.values()].map(a => a.snapshot());
|
||||
}
|
||||
|
||||
get RelayCache(): RelayCache {
|
||||
return this.#relayCache;
|
||||
}
|
||||
|
||||
get QueryOptimizer(): QueryOptimizer {
|
||||
return this.#queryOptimizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup caches
|
||||
*/
|
||||
@ -240,9 +254,7 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
if (existing.fromInstance === req.instance) {
|
||||
return existing;
|
||||
}
|
||||
const filters = !req.options?.skipDiff
|
||||
? req.buildDiff(this.#relayCache, existing.flatFilters)
|
||||
: req.build(this.#relayCache);
|
||||
const filters = !req.options?.skipDiff ? req.buildDiff(this, existing.filters) : req.build(this);
|
||||
if (filters.length === 0 && !!req.options?.skipDiff) {
|
||||
return existing;
|
||||
} else {
|
||||
@ -255,11 +267,15 @@ export class NostrSystem extends ExternalStore<SystemSnapshot> implements System
|
||||
} else {
|
||||
const store = new type();
|
||||
|
||||
const filters = req.build(this.#relayCache);
|
||||
const filters = req.build(this);
|
||||
const q = new Query(req.id, req.instance, store, req.options?.leaveOpen);
|
||||
if (filters.some(a => a.filters.some(b => b.ids))) {
|
||||
const expectIds = new Set(filters.flatMap(a => a.filters).flatMap(a => a.ids ?? []));
|
||||
q.feed.onEvent(async evs => {
|
||||
await this.#eventsCache.bulkSet(evs);
|
||||
const toSet = evs.filter(a => expectIds.has(a.id) && this.#eventsCache.getFromCache(a.id) === undefined);
|
||||
if (toSet.length > 0) {
|
||||
await this.#eventsCache.bulkSet(toSet);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.Queries.set(req.id, q);
|
||||
|
46
packages/system/src/query-optimizer/index.ts
Normal file
46
packages/system/src/query-optimizer/index.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { ReqFilter } from "../nostr";
|
||||
import { expandFilter } from "./request-expander";
|
||||
import { flatMerge, mergeSimilar } from "./request-merger";
|
||||
import { diffFilters } from "./request-splitter";
|
||||
|
||||
export interface FlatReqFilter {
|
||||
keys: number;
|
||||
ids?: string;
|
||||
authors?: string;
|
||||
kinds?: number;
|
||||
"#e"?: string;
|
||||
"#p"?: string;
|
||||
"#t"?: string;
|
||||
"#d"?: string;
|
||||
"#r"?: string;
|
||||
search?: string;
|
||||
since?: number;
|
||||
until?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface QueryOptimizer {
|
||||
expandFilter(f: ReqFilter): Array<FlatReqFilter>;
|
||||
getDiff(prev: Array<ReqFilter>, next: Array<ReqFilter>): Array<FlatReqFilter>;
|
||||
flatMerge(all: Array<FlatReqFilter>): Array<ReqFilter>;
|
||||
compress(all: Array<ReqFilter>): Array<ReqFilter>;
|
||||
}
|
||||
|
||||
export const DefaultQueryOptimizer = {
|
||||
expandFilter: (f: ReqFilter) => {
|
||||
return expandFilter(f);
|
||||
},
|
||||
getDiff: (prev: Array<ReqFilter>, next: Array<ReqFilter>) => {
|
||||
const diff = diffFilters(
|
||||
prev.flatMap(a => expandFilter(a)),
|
||||
next.flatMap(a => expandFilter(a)),
|
||||
);
|
||||
return diff.added;
|
||||
},
|
||||
flatMerge: (all: Array<FlatReqFilter>) => {
|
||||
return flatMerge(all);
|
||||
},
|
||||
compress: (all: Array<ReqFilter>) => {
|
||||
return mergeSimilar(all);
|
||||
},
|
||||
} as QueryOptimizer;
|
@ -1,20 +1,5 @@
|
||||
import { ReqFilter } from "./nostr";
|
||||
|
||||
export interface FlatReqFilter {
|
||||
keys: number;
|
||||
ids?: string;
|
||||
authors?: string;
|
||||
kinds?: number;
|
||||
"#e"?: string;
|
||||
"#p"?: string;
|
||||
"#t"?: string;
|
||||
"#d"?: string;
|
||||
"#r"?: string;
|
||||
search?: string;
|
||||
since?: number;
|
||||
until?: number;
|
||||
limit?: number;
|
||||
}
|
||||
import { FlatReqFilter } from ".";
|
||||
import { ReqFilter } from "../nostr";
|
||||
|
||||
/**
|
||||
* Expand a filter into its most fine grained form
|
@ -1,6 +1,6 @@
|
||||
import { distance } from "@snort/shared";
|
||||
import { ReqFilter } from ".";
|
||||
import { FlatReqFilter } from "./request-expander";
|
||||
import { ReqFilter } from "..";
|
||||
import { FlatReqFilter } from ".";
|
||||
|
||||
/**
|
||||
* Keys which can change the entire meaning of the filter outside the array types
|
||||
@ -105,7 +105,7 @@ export function flatMerge(all: Array<FlatReqFilter>): Array<ReqFilter> {
|
||||
function mergeFiltersInSet(filters: Array<FlatReqFilter>) {
|
||||
return filters.reduce((acc, a) => {
|
||||
Object.entries(a).forEach(([k, v]) => {
|
||||
if (k === "keys") return;
|
||||
if (k === "keys" || v === undefined) return;
|
||||
if (DiscriminatorKeys.includes(k)) {
|
||||
acc[k] = v;
|
||||
} else {
|
@ -1,5 +1,5 @@
|
||||
import { flatFilterEq } from "./utils";
|
||||
import { FlatReqFilter } from "./request-expander";
|
||||
import { flatFilterEq } from "../utils";
|
||||
import { FlatReqFilter } from ".";
|
||||
|
||||
export function diffFilters(prev: Array<FlatReqFilter>, next: Array<FlatReqFilter>, calcRemoved?: boolean) {
|
||||
const added = [];
|
@ -4,9 +4,7 @@ import { unixNowMs, unwrap } from "@snort/shared";
|
||||
|
||||
import { Connection, ReqFilter, Nips, TaggedNostrEvent } from ".";
|
||||
import { NoteStore } from "./note-collection";
|
||||
import { flatMerge } from "./request-merger";
|
||||
import { BuiltRawReqFilter } from "./request-builder";
|
||||
import { FlatReqFilter, expandFilter } from "./request-expander";
|
||||
import { eventMatchesFilter } from "./request-matcher";
|
||||
|
||||
/**
|
||||
@ -19,7 +17,6 @@ class QueryTrace {
|
||||
eose?: number;
|
||||
close?: number;
|
||||
#wasForceClosed = false;
|
||||
readonly flatFilters: Array<FlatReqFilter>;
|
||||
readonly #fnClose: (id: string) => void;
|
||||
readonly #fnProgress: () => void;
|
||||
|
||||
@ -34,7 +31,6 @@ class QueryTrace {
|
||||
this.start = unixNowMs();
|
||||
this.#fnClose = fnClose;
|
||||
this.#fnProgress = fnProgress;
|
||||
this.flatFilters = filters.flatMap(expandFilter);
|
||||
}
|
||||
|
||||
sentToRelay() {
|
||||
@ -166,11 +162,7 @@ export class Query implements QueryBase {
|
||||
* Recompute the complete set of compressed filters from all query traces
|
||||
*/
|
||||
get filters() {
|
||||
return flatMerge(this.flatFilters);
|
||||
}
|
||||
|
||||
get flatFilters() {
|
||||
return this.#tracing.flatMap(a => a.flatFilters);
|
||||
return this.#tracing.flatMap(a => a.filters);
|
||||
}
|
||||
|
||||
get feed() {
|
||||
|
@ -2,11 +2,10 @@ import debug from "debug";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { appendDedupe, sanitizeRelayUrl, unixNowMs } from "@snort/shared";
|
||||
|
||||
import { ReqFilter, u256, HexKey, EventKind } from ".";
|
||||
import { diffFilters } from "./request-splitter";
|
||||
import EventKind from "./event-kind";
|
||||
import { SystemInterface } from "index";
|
||||
import { ReqFilter, u256, HexKey } from "./nostr";
|
||||
import { RelayCache, splitByWriteRelays, splitFlatByWriteRelays } from "./gossip-model";
|
||||
import { flatMerge, mergeSimilar } from "./request-merger";
|
||||
import { FlatReqFilter, expandFilter } from "./request-expander";
|
||||
|
||||
/**
|
||||
* Which strategy is used when building REQ filters
|
||||
@ -95,26 +94,25 @@ export class RequestBuilder {
|
||||
return this.#builders.map(f => f.filter);
|
||||
}
|
||||
|
||||
build(relays: RelayCache): Array<BuiltRawReqFilter> {
|
||||
const expanded = this.#builders.flatMap(a => a.build(relays, this.id));
|
||||
return this.#groupByRelay(expanded);
|
||||
build(system: SystemInterface): Array<BuiltRawReqFilter> {
|
||||
const expanded = this.#builders.flatMap(a => a.build(system.RelayCache, this.id));
|
||||
return this.#groupByRelay(system, expanded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects a change in request from a previous set of filters
|
||||
*/
|
||||
buildDiff(relays: RelayCache, prev: Array<FlatReqFilter>): Array<BuiltRawReqFilter> {
|
||||
buildDiff(system: SystemInterface, prev: Array<ReqFilter>): Array<BuiltRawReqFilter> {
|
||||
const start = unixNowMs();
|
||||
|
||||
const next = this.#builders.flatMap(f => expandFilter(f.filter));
|
||||
const diff = diffFilters(prev, next);
|
||||
const diff = system.QueryOptimizer.getDiff(prev, this.buildRaw());
|
||||
const ts = unixNowMs() - start;
|
||||
this.#log("buildDiff %s %d ms", this.id, ts);
|
||||
if (diff.changed) {
|
||||
return splitFlatByWriteRelays(relays, diff.added).map(a => {
|
||||
if (diff.length > 0) {
|
||||
return splitFlatByWriteRelays(system.RelayCache, diff).map(a => {
|
||||
return {
|
||||
strategy: RequestStrategy.AuthorsRelays,
|
||||
filters: flatMerge(a.filters),
|
||||
filters: system.QueryOptimizer.flatMerge(a.filters),
|
||||
relay: a.relay,
|
||||
};
|
||||
});
|
||||
@ -129,7 +127,7 @@ export class RequestBuilder {
|
||||
* @param expanded
|
||||
* @returns
|
||||
*/
|
||||
#groupByRelay(expanded: Array<BuiltRawReqFilter>) {
|
||||
#groupByRelay(system: SystemInterface, expanded: Array<BuiltRawReqFilter>) {
|
||||
const relayMerged = expanded.reduce((acc, v) => {
|
||||
const existing = acc.get(v.relay);
|
||||
if (existing) {
|
||||
@ -142,7 +140,7 @@ export class RequestBuilder {
|
||||
|
||||
const filtersSquashed = [...relayMerged.values()].map(a => {
|
||||
return {
|
||||
filters: mergeSimilar(a.flatMap(b => b.filters)),
|
||||
filters: system.QueryOptimizer.compress(a.flatMap(b => b.filters)),
|
||||
relay: a[0].relay,
|
||||
strategy: a[0].strategy,
|
||||
} as BuiltRawReqFilter;
|
||||
|
@ -6,6 +6,8 @@ import { NostrEvent, TaggedNostrEvent } from "./nostr";
|
||||
import { NoteStore, NoteStoreSnapshotData } from "./note-collection";
|
||||
import { Query } from "./query";
|
||||
import { RequestBuilder } from "./request-builder";
|
||||
import { RelayCache } from "./gossip-model";
|
||||
import { QueryOptimizer } from "./query-optimizer";
|
||||
|
||||
export class SystemWorker extends ExternalStore<SystemSnapshot> implements SystemInterface {
|
||||
#port: MessagePort;
|
||||
@ -29,6 +31,13 @@ export class SystemWorker extends ExternalStore<SystemSnapshot> implements Syste
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
get RelayCache(): RelayCache {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
get QueryOptimizer(): QueryOptimizer {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
HandleAuth?: AuthHandler;
|
||||
|
||||
get Sockets(): ConnectionStateSnapshot[] {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { equalProp } from "@snort/shared";
|
||||
import { FlatReqFilter } from "./request-expander";
|
||||
import { FlatReqFilter } from "./query-optimizer";
|
||||
import { NostrEvent, ReqFilter } from "./nostr";
|
||||
|
||||
export function findTag(e: NostrEvent, tag: string) {
|
||||
|
@ -4,6 +4,8 @@ import { HexKey, NostrEvent } from "./nostr";
|
||||
import { findTag } from "./utils";
|
||||
import { MetadataCache } from "./cache";
|
||||
|
||||
const ParsedZapCache = new Map<string, ParsedZap>();
|
||||
|
||||
function getInvoice(zap: NostrEvent): InvoiceDetails | undefined {
|
||||
const bolt11 = findTag(zap, "bolt11");
|
||||
if (!bolt11) {
|
||||
@ -13,6 +15,11 @@ function getInvoice(zap: NostrEvent): InvoiceDetails | undefined {
|
||||
}
|
||||
|
||||
export function parseZap(zapReceipt: NostrEvent, userCache: FeedCache<MetadataCache>, refNote?: NostrEvent): ParsedZap {
|
||||
const existing = ParsedZapCache.get(zapReceipt.id);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
let innerZapJson = findTag(zapReceipt, "description");
|
||||
if (innerZapJson) {
|
||||
try {
|
||||
@ -67,7 +74,7 @@ export function parseZap(zapReceipt: NostrEvent, userCache: FeedCache<MetadataCa
|
||||
// ignored: console.debug("Invalid zap", zapReceipt, e);
|
||||
}
|
||||
}
|
||||
return {
|
||||
const ret = {
|
||||
id: zapReceipt.id,
|
||||
zapService: zapReceipt.pubkey,
|
||||
amount: 0,
|
||||
@ -75,6 +82,8 @@ export function parseZap(zapReceipt: NostrEvent, userCache: FeedCache<MetadataCa
|
||||
anonZap: false,
|
||||
errors: ["invalid zap, parsing failed"],
|
||||
};
|
||||
ParsedZapCache.set(ret.id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export interface ParsedZap {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {NostrSystem, SystemInterface} from "..";
|
||||
import { NostrSystem, SystemInterface } from "..";
|
||||
|
||||
const Relay = "wss://relay.snort.social/";
|
||||
|
||||
const system = new NostrSystem({}) as SystemInterface;
|
||||
|
||||
async function test() {
|
||||
await system.ConnectToRelay(Relay, {read: true, write: true});
|
||||
await system.ConnectToRelay(Relay, { read: true, write: true });
|
||||
setTimeout(() => {
|
||||
system.DisconnectRelay(Relay);
|
||||
}, 1000);
|
||||
|
16
yarn.lock
16
yarn.lock
@ -2711,6 +2711,7 @@ __metadata:
|
||||
"@scure/bip39": ^1.1.1
|
||||
"@snort/shared": "workspace:*"
|
||||
"@snort/system": "workspace:*"
|
||||
"@snort/system-query": "workspace:*"
|
||||
"@snort/system-react": "workspace:*"
|
||||
"@szhsin/react-menu": ^3.3.1
|
||||
"@types/debug": ^4.1.8
|
||||
@ -2756,6 +2757,7 @@ __metadata:
|
||||
react-twitter-embed: ^4.0.4
|
||||
source-map-loader: ^4.0.1
|
||||
terser-webpack-plugin: ^5.3.9
|
||||
tinybench: ^2.5.0
|
||||
ts-jest: ^29.1.0
|
||||
ts-loader: ^9.4.4
|
||||
typescript: ^5.2.2
|
||||
@ -2822,6 +2824,12 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@snort/system-query@workspace:*, @snort/system-query@workspace:packages/system-query":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@snort/system-query@workspace:packages/system-query"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@snort/system-react@workspace:*, @snort/system-react@workspace:packages/system-react":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@snort/system-react@workspace:packages/system-react"
|
||||
@ -2844,6 +2852,7 @@ __metadata:
|
||||
"@peculiar/webcrypto": ^1.4.3
|
||||
"@scure/base": ^1.1.2
|
||||
"@snort/shared": ^1.0.5
|
||||
"@snort/system-query": "workspace:*"
|
||||
"@stablelib/xchacha20": ^1.0.1
|
||||
"@types/debug": ^4.1.8
|
||||
"@types/jest": ^29.5.1
|
||||
@ -13153,6 +13162,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinybench@npm:^2.5.0":
|
||||
version: 2.5.0
|
||||
resolution: "tinybench@npm:2.5.0"
|
||||
checksum: 284bb9428f197ec8b869c543181315e65e41ccfdad3c4b6c916bb1fdae1b5c6785661b0d90cf135b48d833b03cb84dc5357b2d33ec65a1f5971fae0ab2023821
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tmp@npm:^0.0.33":
|
||||
version: 0.0.33
|
||||
resolution: "tmp@npm:0.0.33"
|
||||
|
Loading…
x
Reference in New Issue
Block a user