mirror of
https://github.com/BlowaterNostr/blowater.git
synced 2024-10-18 15:43:20 +00:00
167 lines
4.8 KiB
TypeScript
167 lines
4.8 KiB
TypeScript
import * as csp from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
|
|
import { NostrAccountContext, NostrEvent, NostrKind } from "../lib/nostr-ts/nostr.ts";
|
|
import { ConnectionPool } from "../lib/nostr-ts/relay.ts";
|
|
import { prepareNostrImageEvent, Tag } from "../nostr.ts";
|
|
import { PublicKey } from "../lib/nostr-ts/key.ts";
|
|
import { prepareEncryptedNostrEvent, prepareNormalNostrEvent } from "../lib/nostr-ts/event.ts";
|
|
|
|
export async function sendDMandImages(args: {
|
|
sender: NostrAccountContext;
|
|
receiverPublicKey: PublicKey;
|
|
message: string;
|
|
files: Blob[];
|
|
lamport_timestamp: number;
|
|
pool: ConnectionPool;
|
|
tags: Tag[];
|
|
}) {
|
|
const { tags, sender, receiverPublicKey, message, files, lamport_timestamp, pool } = args;
|
|
console.log("sendDMandImages", message, files);
|
|
const eventsToSend: NostrEvent[] = [];
|
|
if (message.trim().length !== 0) {
|
|
// build the nostr event
|
|
const nostrEvent = await prepareEncryptedNostrEvent(
|
|
sender,
|
|
{
|
|
encryptKey: receiverPublicKey,
|
|
kind: NostrKind.DIRECT_MESSAGE,
|
|
tags: [
|
|
["p", receiverPublicKey.hex],
|
|
["lamport", String(lamport_timestamp)],
|
|
...tags,
|
|
],
|
|
content: message,
|
|
},
|
|
);
|
|
if (nostrEvent instanceof Error) {
|
|
return nostrEvent;
|
|
}
|
|
eventsToSend.push(nostrEvent);
|
|
}
|
|
for (let blob of files) {
|
|
const imgEvent = await prepareNostrImageEvent(
|
|
sender,
|
|
receiverPublicKey,
|
|
blob,
|
|
NostrKind.DIRECT_MESSAGE,
|
|
tags,
|
|
);
|
|
if (imgEvent instanceof Error) {
|
|
return imgEvent;
|
|
}
|
|
let [fileEvent, _] = imgEvent;
|
|
// for (const event of fileEvents) {
|
|
eventsToSend.push(fileEvent);
|
|
// }
|
|
}
|
|
// send the event
|
|
for (const event of eventsToSend) {
|
|
const err = await pool.sendEvent(event);
|
|
if (err instanceof Error) {
|
|
return err;
|
|
}
|
|
}
|
|
return eventsToSend;
|
|
}
|
|
|
|
export async function sendSocialPost(args: {
|
|
sender: NostrAccountContext;
|
|
message: string;
|
|
lamport_timestamp: number;
|
|
pool: ConnectionPool;
|
|
tags: Tag[];
|
|
}) {
|
|
const { sender, message, lamport_timestamp, pool, tags } = args;
|
|
console.log("sendSocialPost", message);
|
|
const event = await prepareNormalNostrEvent(sender, NostrKind.TEXT_NOTE, [
|
|
["lamport", String(lamport_timestamp)],
|
|
...tags,
|
|
], message);
|
|
const err = await pool.sendEvent(event);
|
|
if (err instanceof Error) {
|
|
return err;
|
|
}
|
|
return event;
|
|
}
|
|
|
|
export function getAllEncryptedMessagesOf(
|
|
publicKey: PublicKey,
|
|
relay: ConnectionPool,
|
|
) {
|
|
const stream1 = getAllEncryptedMessagesSendBy(
|
|
publicKey,
|
|
relay,
|
|
);
|
|
const stream2 = getAllEncryptedMessagesReceivedBy(
|
|
publicKey,
|
|
relay,
|
|
);
|
|
return merge(stream1, stream2);
|
|
}
|
|
|
|
async function* getAllEncryptedMessagesSendBy(
|
|
publicKey: PublicKey,
|
|
relay: ConnectionPool,
|
|
) {
|
|
let resp = await relay.newSub(
|
|
`getAllEncryptedMessagesSendBy`,
|
|
{
|
|
authors: [publicKey.hex],
|
|
kinds: [4],
|
|
},
|
|
);
|
|
if (resp instanceof Error) {
|
|
throw resp;
|
|
}
|
|
for await (const nostrMessage of resp.chan) {
|
|
yield nostrMessage;
|
|
}
|
|
}
|
|
|
|
async function* getAllEncryptedMessagesReceivedBy(
|
|
publicKey: PublicKey,
|
|
relay: ConnectionPool,
|
|
) {
|
|
let resp = await relay.newSub(
|
|
`getAllEncryptedMessagesReceivedBy`,
|
|
{
|
|
kinds: [4],
|
|
"#p": [publicKey.hex],
|
|
},
|
|
);
|
|
if (resp instanceof Error) {
|
|
throw resp;
|
|
}
|
|
for await (const nostrMessage of resp.chan) {
|
|
yield nostrMessage;
|
|
}
|
|
}
|
|
|
|
function merge<T>(...iters: AsyncIterable<T>[]) {
|
|
let merged = csp.chan<T>();
|
|
async function coroutine<T>(
|
|
source: AsyncIterable<T>,
|
|
destination: csp.Channel<T>,
|
|
) {
|
|
for await (let ele of source) {
|
|
if (destination.closed()) {
|
|
return;
|
|
}
|
|
let err = await destination.put(ele);
|
|
if (err instanceof csp.PutToClosedChannelError) {
|
|
// this means the merged channel was not closed when
|
|
// line 319 is called,
|
|
// but during waiting time of line 319, no consumer pops it and it was closed.
|
|
// This is normal semantics of channels
|
|
// so that it's fine to not throw it up to the call stack
|
|
// but then this ele has already been popped from the iter,
|
|
// it will be lost.
|
|
throw new Error("destination channel should not be closed");
|
|
}
|
|
}
|
|
}
|
|
for (let iter of iters) {
|
|
coroutine(iter, merged);
|
|
}
|
|
return merged;
|
|
}
|