Browse Source

feat: use user and repository relays

- send status events to user and repository relays
- get repoistory events from base relays
- get pr events and replies from repository relays
master
DanConwayDev 2 years ago
parent
commit
7507ea2ea7
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. 41
      src/lib/components/prs/StatusSelector.svelte
  2. 54
      src/lib/stores/PR.ts
  3. 21
      src/lib/stores/PRs.ts
  4. 19
      src/lib/stores/ndk.ts
  5. 38
      src/lib/stores/repo.ts
  6. 89
      src/lib/stores/users.ts

41
src/lib/components/prs/StatusSelector.svelte

@ -1,10 +1,12 @@ @@ -1,10 +1,12 @@
<script lang="ts">
import { ndk } from "$lib/stores/ndk";
import { NDKEvent, type NDKTag } from "@nostr-dev-kit/ndk";
import { NDKEvent, NDKRelaySet, type NDKTag } from "@nostr-dev-kit/ndk";
import type { PRStatus } from "./type";
import { selected_pr_full } from "$lib/stores/PR";
import { load } from "../../../routes/repo/[repo_id]/+page";
import { patch_kind } from "$lib/kinds";
import { getLoggedInUserRelays, logged_in_user } from "$lib/stores/users";
import { selected_repo } from "$lib/stores/repo";
export let status: PRStatus = "Draft";
export let repo_id: string = "";
@ -12,19 +14,41 @@ @@ -12,19 +14,41 @@
let loading = false;
let edit_mode = false;
$: {
edit_mode =
$logged_in_user !== undefined && repo_id === $selected_repo.repo_id;
}
async function changeStatus(new_status: PRStatus) {
let event = new NDKEvent(ndk);
// TODO: use random custom kind for status instead of NIP32?
event.kind = patch_kind;
event.tags.push(["t", new_status]);
event.tags.push(["e", pr_id]);
event.tags.push(["r", `r-${repo_id}`]);
event.sign();
loading = true;
// TODO send to repo relays, current user relay and pr event pubkey relays
let relays = [...$selected_repo.relays];
try {
event.sign();
} catch {
alert("failed to sign event");
}
try {
let user_relays = await getLoggedInUserRelays();
relays = [
...relays,
...(user_relays.ndk_relays
? user_relays.ndk_relays.writeRelayUrls
: []),
// TODO: pr event pubkey relays
];
} catch {
alert("failed to get user relays");
}
try {
// TODO: check if we are signed in a signer is in ndk
// let res = await event.publish();
let res = await event.publish(
NDKRelaySet.fromRelayUrls(relays, ndk),
);
selected_pr_full.update((pr_full) => {
if (pr_full.summary.id !== pr_id) return pr_full;
return {
@ -47,6 +71,7 @@ @@ -47,6 +71,7 @@
class:btn-success={status === "Open"}
class:btn-primary={status === "Merged"}
class:btn-neutral={status === "Draft" || status === "Closed"}
class:cursor-default={edit_mode}
class="btn btn-success btn-sm mr-6 align-middle"
>
{#if status === "Open"}
@ -94,6 +119,7 @@ @@ -94,6 +119,7 @@
>
Draft
{/if}
{#if edit_mode}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
@ -103,7 +129,9 @@ @@ -103,7 +129,9 @@
d="M11.646 15.146L5.854 9.354a.5.5 0 0 1 .353-.854h11.586a.5.5 0 0 1 .353.854l-5.793 5.792a.5.5 0 0 1-.707 0"
/></svg
>
{/if}
</div>
{#if edit_mode}
<ul
tabIndex={0}
class="dropdown-content z-[1] menu p-2 ml-0 shadow bg-base-300 rounded-box w-52"
@ -153,5 +181,6 @@ @@ -153,5 +181,6 @@
</li>
{/if}
</ul>
{/if}
</div>
{/if}

54
src/lib/stores/PR.ts

@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { NDKRelaySet, type NDKEvent } from "@nostr-dev-kit/ndk";
import { writable, type Unsubscriber, type Writable } from "svelte/store"
import { ndk } from "./ndk";
import type { User } from "$lib/components/users/type";
import { ensureUser } from "./users";
import { type PRFull, full_defaults, isPRStatus, type PRStatus } from "$lib/components/prs/type";
import { pr_kind, pr_status_kind } from "$lib/kinds";
import { ensureSelectedRepo } from "./repo";
export let selected_pr_full: Writable<PRFull> = writable({ ...full_defaults });
let selected_repo_id: string = "";
let selected_pr_repo_id: string = "";
let selected_pr_id: string = "";
let pr_summary_author_unsubsriber: Unsubscriber | undefined;
@ -21,33 +21,41 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => { @@ -21,33 +21,41 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => {
if (selected_pr_id == pr_id) return;
if (pr_id == "") {
selected_pr_full.set({ ...full_defaults });
selected_pr_replies.set([]);
return;
}
selected_repo_id = repo_id;
selected_pr_repo_id = repo_id;
selected_pr_id = pr_id;
selected_pr_status_date = 0;
selected_pr_replies.set([]);
selected_pr_full.update(full => {
return {
...full,
selected_pr_full.set({
...full_defaults,
summary: {
...full.summary,
...full_defaults.summary,
id: pr_id,
repo_id: repo_id,
loading: true,
},
loading: true,
};
});
if (pr_summary_author_unsubsriber) pr_summary_author_unsubsriber();
pr_summary_author_unsubsriber = undefined;
let sub = ndk.subscribe({
new Promise(async (r) => {
let repo = await ensureSelectedRepo(repo_id);
let sub = ndk.subscribe(
{
ids: [pr_id],
limit: 1,
});
kinds: [pr_kind],
'#r': [`r-${repo_id}`],
limit: 50,
},
{},
NDKRelaySet.fromRelayUrls(repo.relays, ndk),
);
sub.on("event", (event: NDKEvent) => {
try {
@ -55,7 +63,6 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => { @@ -55,7 +63,6 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => {
&& event.getMatchingTags("r").find(t => t[1] === `r-${repo_id}`)
&& event.id == pr_id
) {
selected_pr_full.update(full => {
return {
...full,
@ -93,19 +100,27 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => { @@ -93,19 +100,27 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => {
sub.on("eose", () => {
selected_pr_full.update(full => {
return {
let updated = {
...full,
summary: {
...full.summary,
loading: false,
},
};
if (full.loading === false) {
r({ ...updated });
}
return updated;
});
});
let sub_replies = ndk.subscribe({
let sub_replies = ndk.subscribe(
{
"#e": [pr_id],
});
},
{},
NDKRelaySet.fromRelayUrls(repo.relays, ndk),
);
sub_replies.on("event", (event: NDKEvent) => {
if (event.kind == pr_status_kind
@ -135,10 +150,15 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => { @@ -135,10 +150,15 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => {
sub.on("eose", () => {
selected_pr_full.update(full => {
return {
let updated = {
...full,
loading: false,
};
if (full.summary.loading === false) {
r({ ...updated });
}
return updated;
});
});
});
}

21
src/lib/stores/PRs.ts

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { NDKRelaySet, type NDKEvent } from "@nostr-dev-kit/ndk";
import { writable, type Unsubscriber, type Writable } from "svelte/store"
import { ndk } from "./ndk";
import type { Repo } from "$lib/components/repo/type";
import { summary_defaults } from "$lib/components/prs/type";
import type { User } from "$lib/components/users/type";
import { ensureUser, users } from "./users";
import type { PRSummaries, PRSummary } from "$lib/components/prs/type";
import { ensureUser } from "./users";
import type { PRSummaries } from "$lib/components/prs/type";
import { ensureSelectedRepo } from "./repo";
export let pr_summaries: Writable<PRSummaries> = writable({
id: "",
@ -19,7 +19,7 @@ let selected_repo_id: string = ""; @@ -19,7 +19,7 @@ let selected_repo_id: string = "";
let authors_unsubscribers: Unsubscriber[] = [];
export let ensurePRSummaries = (repo_id: string) => {
export let ensurePRSummaries = async (repo_id: string) => {
if (selected_repo_id == repo_id) return;
if (repo_id == "") return pr_summaries.set({
id: "",
@ -28,6 +28,9 @@ export let ensurePRSummaries = (repo_id: string) => { @@ -28,6 +28,9 @@ export let ensurePRSummaries = (repo_id: string) => {
});
selected_repo_id = repo_id;
let repo = await ensureSelectedRepo(repo_id);
pr_summaries.update(prs => {
return {
...prs,
@ -38,11 +41,15 @@ export let ensurePRSummaries = (repo_id: string) => { @@ -38,11 +41,15 @@ export let ensurePRSummaries = (repo_id: string) => {
authors_unsubscribers.forEach(u => u());
authors_unsubscribers = [];
let sub = ndk.subscribe({
let sub = ndk.subscribe(
{
kinds: [pr_kind],
'#r': [`r-${repo_id}`],
limit: 50,
});
},
{},
NDKRelaySet.fromRelayUrls(repo.relays, ndk),
);
sub.on("event", (event: NDKEvent) => {
try {

19
src/lib/stores/ndk.ts

@ -1,7 +1,24 @@ @@ -1,7 +1,24 @@
import NDKSvelte from '@nostr-dev-kit/ndk-svelte';
export let base_relays = import.meta.env.DEV
? [
"ws://localhost:8055",
]
: [
"wss://relayable.org",
"wss://relay.f7z.io",
"wss://relay.damus.io",
"wss://relay.snort.social",
// "wss://nostr.wine/",
// "wss://eden.nostr.land/",
// "wss://relay.nostr.band/",
];
// TODO: fallback_relays for if profile cannot be found
export const ndk = new NDKSvelte({
explicitRelayUrls: ['ws://localhost:8055'],
explicitRelayUrls: [...base_relays],
});
ndk.connect();

38
src/lib/stores/repo.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { NDKUser } from "@nostr-dev-kit/ndk";
import { writable, type Unsubscriber, type Writable } from "svelte/store"
import { ndk } from "./ndk";
import { NDKRelaySet } from "@nostr-dev-kit/ndk";
import { writable, type Unsubscriber, type Writable, get } from "svelte/store"
import { base_relays, ndk } from "./ndk";
import type { Repo } from "$lib/components/repo/type";
import { defaults } from "$lib/components/repo/type";
import type { User } from "$lib/components/users/type";
@ -12,15 +12,32 @@ let selected_repo_id: string = ""; @@ -12,15 +12,32 @@ let selected_repo_id: string = "";
let maintainers_unsubscribers: Unsubscriber[] = [];
export let ensureSelectedRepo = (repo_id: string) => {
if (selected_repo_id == repo_id) return selected_repo;
export let ensureSelectedRepo = async (repo_id: string): Promise<Repo> => {
if (selected_repo_id == repo_id) {
return new Promise(r => {
let unsubscriber = selected_repo.subscribe(repo => {
if (repo.repo_id === repo_id && !repo.loading) {
setTimeout(() => {
unsubscriber();
}, 5);
r({ ...repo });
}
});
})
}
selected_repo_id = repo_id;
let sub = ndk.subscribe({
let sub = ndk.subscribe(
{
kinds: [repo_kind],
'#d': [repo_id],
limit: 1,
});
},
{},
NDKRelaySet.fromRelayUrls(base_relays, ndk),
);
return new Promise((r) => {
sub.on("event", (event) => {
try {
if (event.kind == repo_kind && event.tagValue("d") == repo_id) {
@ -63,12 +80,19 @@ export let ensureSelectedRepo = (repo_id: string) => { @@ -63,12 +80,19 @@ export let ensureSelectedRepo = (repo_id: string) => {
}
} catch { }
});
sub.on("eose", () => {
selected_repo.update((repo) => {
r({
...repo,
loading: false,
});
return {
...repo,
loading: false,
}
})
});
});
}

89
src/lib/stores/users.ts

@ -16,6 +16,7 @@ export let ensureUser = (hexpubkey: string): Writable<User> => { @@ -16,6 +16,7 @@ export let ensureUser = (hexpubkey: string): Writable<User> => {
};
users[hexpubkey] = writable(base);
getUserRelays(hexpubkey);
u.fetchProfile().then(
(p) => {
users[hexpubkey].update((u) => ({
@ -35,6 +36,17 @@ export let ensureUser = (hexpubkey: string): Writable<User> => { @@ -35,6 +36,17 @@ export let ensureUser = (hexpubkey: string): Writable<User> => {
return users[hexpubkey];
}
export let returnUser = async (hexpubkey: string): Promise<User> => {
return new Promise((r) => {
let unsubscriber = ensureUser(hexpubkey).subscribe((u) => {
if (!u.loading) {
unsubscriber();
r(u);
}
});
});
}
// nip07_plugin is set in Navbar component
export let nip07_plugin: Writable<undefined | boolean> = writable(undefined);
@ -89,3 +101,80 @@ export let login = async (): Promise<void> => { @@ -89,3 +101,80 @@ export let login = async (): Promise<void> => {
}
});
};
interface UserRelays {
loading: boolean;
ndk_relays: NDKRelayList | undefined;
}
export let user_relays: { [hexpubkey: string]: Writable<UserRelays>; } = {};
export let getUserRelays = async (hexpubkey: string): Promise<UserRelays> => {
return new Promise(async (res, rej) => {
if (user_relays[hexpubkey]) {
let unsubscriber: Unsubscriber;
unsubscriber = user_relays[hexpubkey].subscribe(querying_user_relays => {
if (querying_user_relays && !querying_user_relays.loading) {
res(querying_user_relays);
unsubscriber();
}
});
}
else {
user_relays[hexpubkey] = writable({
loading: true,
ndk_relays: undefined,
});
logged_in_user_relays.set({
loading: true,
ndk_relays: undefined,
});
let relay_list = await ndk.getUser({ hexpubkey }).relayList();
let querying_user_relays = {
loading: false,
ndk_relays: relay_list,
};
user_relays[hexpubkey].set({ ...querying_user_relays });
res(querying_user_relays);
}
});
};
export let logged_in_user_relays: Writable<undefined | UserRelays> = writable(undefined);
export let getLoggedInUserRelays = async (): Promise<UserRelays> => {
return new Promise(async (res, rej) => {
let user_relays = get(logged_in_user_relays);
if (user_relays) {
if (!user_relays.loading) return res(user_relays);
let unsubscriber = logged_in_user_relays.subscribe(user_relays => {
if (user_relays && !user_relays.loading) {
res(user_relays);
unsubscriber();
}
});
}
else {
let unsubscriber: Unsubscriber;
unsubscriber = logged_in_user.subscribe(async user => {
if (user) {
if (unsubscriber) unsubscriber();
logged_in_user_relays.set({
loading: true,
ndk_relays: undefined,
});
let relay_list = await ndk.getUser({ hexpubkey: user.hexpubkey }).relayList();
let user_relays = {
loading: false,
ndk_relays: relay_list,
};
logged_in_user_relays.set({ ...user_relays });
res(user_relays);
}
});
}
});
};
Loading…
Cancel
Save