Skip to content

Commit

Permalink
refactor(core)!: abandon core/nips.ts
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Abandon `nips` query parameter for imported modules.

Also remove an unused `logger` field in `NostrNodeOption`.
  • Loading branch information
hasundue committed Feb 27, 2024
1 parent 3ee3d45 commit 2c145af
Show file tree
Hide file tree
Showing 15 changed files with 98 additions and 176 deletions.
25 changes: 7 additions & 18 deletions core/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,11 @@ import type {
} from "./protocol.d.ts";
import {
NostrNode,
NostrNodeBase,
NostrNodeConfig,
NostrNodeEvent,
NostrNodeModule,
} from "./nodes.ts";
import { importNips } from "./nips.ts";

// ----------------------
// NIPs
// ----------------------

const NIPs = await importNips<
RelayToClientMessage,
ClientEventTypeRecord,
Client
>(import.meta.url, "../nips");

// ----------------------
// Interfaces
Expand All @@ -30,16 +20,18 @@ export type ClientConfig = NostrNodeConfig<
RelayToClientMessage,
ClientEventTypeRecord
>;

export type ClientOptions = Partial<ClientConfig>;

/**
* A class that represents a remote Nostr client.
*/
export class Client extends NostrNode<
export class Client extends NostrNodeBase<
RelayToClientMessage,
ClientEventTypeRecord
> {
> implements NostrNode<RelayToClientMessage, ClientEventTypeRecord> {
/**
* The WebSocket connection to the client.
*/
declare ws: WebSocket;

/**
Expand All @@ -51,10 +43,7 @@ export class Client extends NostrNode<
>();

constructor(ws: WebSocket, opts?: ClientOptions) {
super(ws, {
...opts,
modules: NIPs.concat(opts?.modules ?? []),
});
super(ws, opts);
this.ws.addEventListener("message", (ev: MessageEvent<string>) => {
const message = JSON.parse(ev.data) as ClientToRelayMessage;
// TODO: Validate the message.
Expand Down
39 changes: 0 additions & 39 deletions core/nips.ts

This file was deleted.

104 changes: 55 additions & 49 deletions core/nodes.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import type { NostrMessage } from "./protocol.d.ts";
import type { Logger } from "./types.ts";
import { WebSocketLike } from "./websockets.ts";

export interface NostrNodeConfig<
W extends NostrMessage = NostrMessage,
R extends EventTypeRecord = EventTypeRecord,
> {
modules: NostrNodeModule<W, R>[];
logger: Logger;
nbuffer: number;
}

Expand All @@ -16,83 +14,90 @@ export type NostrNodeOptions<
R extends EventTypeRecord = EventTypeRecord,
> = Partial<NostrNodeConfig<W, R>>;

/**
* Common interface for relays and clients.
*/
export interface NostrNode<
W extends NostrMessage = NostrMessage,
R extends EventTypeRecord = EventTypeRecord,
> extends EventTarget {
readonly config: Readonly<NostrNodeConfig<W, R>>;
readonly ws: WebSocketLike;
readonly writable: WritableStream<W>;

status: WebSocketLike["readyState"];
send(msg: W): void | Promise<void>;
close(): Promise<void>;

install(mod: NostrNodeModule<W, R>): void;

addEventListener<T extends EventType<R>>(
type: T,
listener:
| NostrNodeEventListenerOrEventListenerObject<W, R, T>
| null,
options?: AddEventListenerOptions,
): void;

removeEventListener<T extends EventType<R>>(
type: T,
listener:
| NostrNodeEventListenerOrEventListenerObject<W, R, T>
| null,
options?: boolean | EventListenerOptions,
): void;

dispatchEvent<T extends EventType<R>>(event: NostrNodeEvent<R, T>): boolean;
}

/**
* Common base class for relays and clients.
*/
export class NostrNode<
export class NostrNodeBase<
W extends NostrMessage = NostrMessage,
R extends EventTypeRecord = EventTypeRecord,
> extends WritableStream<W> implements EventTarget {
readonly #eventTarget = new EventTarget();
readonly #aborter = new AbortController();
> extends EventTarget implements NostrNode<W, R> {
readonly writable: WritableStream<W>;
readonly config: Readonly<NostrNodeConfig<W, R>>;

constructor(
readonly ws: WebSocketLike,
opts: NostrNodeOptions<W, R> = {},
opts: NostrNodeOptions = {},
) {
super({
super();
this.writable = new WritableStream({
write: (msg) => this.ws.send(JSON.stringify(msg)),
close: () => this.ws.close(),
});
this.config = { modules: [], logger: {}, nbuffer: 10, ...opts };
this.config.modules.forEach((m) => this.addModule(m));
this.config = { modules: [], nbuffer: 10, ...opts };
this.config.modules.forEach((m) => this.install(m));
}

send(msg: W) {
return this.ws.send(JSON.stringify(msg));
}

get status(): WebSocket["readyState"] {
get status() {
return this.ws.readyState;
}

async close() {
this.#aborter.abort();
try {
await super.close();
await this.writable.close();
} catch (err) {
if (super.locked) { // This should not happen.
if (this.writable.locked) { // This should not happen.
throw err;
} // Otherwise the stream is already closed, which is fine.
}
}

addModule(module: NostrNodeModule<W, R>) {
return module.default(this);
}

addEventListener<T extends EventType<R>>(
type: T,
listener:
| NostrNodeEventListenerOrEventListenerObject<W, R, T>
| null,
options?: AddEventListenerOptions,
) {
return this.#eventTarget.addEventListener(
type,
listener as EventListenerOrEventListenerObject,
{ signal: this.#aborter.signal, ...options },
);
}

removeEventListener<T extends EventType<R>>(
type: T,
listener:
| NostrNodeEventListenerOrEventListenerObject<W, R, T>
| null,
options?: boolean | EventListenerOptions,
) {
return this.#eventTarget.removeEventListener(
type,
listener as EventListenerOrEventListenerObject,
options,
);
}

dispatchEvent<T extends EventType<R>>(event: NostrNodeEvent<R, T>) {
return this.#eventTarget.dispatchEvent(event);
install(mod: NostrNodeModule<W, R>) {
return mod.install(this);
}

declare addEventListener: NostrNode<W, R>["addEventListener"];
declare removeEventListener: NostrNode<W, R>["removeEventListener"];
declare dispatchEvent: NostrNode<W, R>["dispatchEvent"];
}

// ------------------------------
Expand All @@ -104,7 +109,8 @@ export interface NostrNodeModule<
R extends EventTypeRecord = EventTypeRecord,
N extends NostrNode<W, R> = NostrNode<W, R>,
> {
default(node: N): void;
// deno-lint-ignore no-explicit-any
install(node: N): any;
}

// ------------------------------
Expand Down
14 changes: 5 additions & 9 deletions core/nodes_test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { NostrNode } from "./nodes.ts";
import { NostrNode, NostrNodeBase } from "./nodes.ts";
import { afterAll, beforeAll, describe, it } from "../lib/std/testing.ts";
import { assert, assertEquals } from "../lib/std/assert.ts";
import { assertEquals } from "../lib/std/assert.ts";
import { MockWebSocket } from "../lib/testing.ts";

describe("NostrNode", () => {
describe("NostrNodeBase", () => {
let node: NostrNode;
let writer: WritableStreamDefaultWriter;

beforeAll(() => {
node = new NostrNode(new MockWebSocket());
node = new NostrNodeBase(new MockWebSocket());
});

afterAll(async () => {
Expand All @@ -19,12 +19,8 @@ describe("NostrNode", () => {
});
});

it("should be able to create a NostrNode instance", () => {
assert(node instanceof NostrNode);
});

it("should be connected to the WebSocket after a message is sent", async () => {
writer = node.getWriter();
writer = node.writable.getWriter();
await writer.write(["NOTICE", "test"]);
writer.releaseLock();
assertEquals(node.status, WebSocket.OPEN);
Expand Down
28 changes: 5 additions & 23 deletions core/relays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,11 @@ import type {
} from "./protocol.d.ts";
import { LazyWebSocket } from "./websockets.ts";
import {
NostrNode,
NostrNodeBase,
NostrNodeConfig,
NostrNodeEvent,
NostrNodeModule,
} from "./nodes.ts";
import { importNips } from "./nips.ts";

// ----------------------
// NIPs
// ----------------------

const NIPs = await importNips<
ClientToRelayMessage,
RelayEventTypeRecord,
Relay
>(import.meta.url, "../nips");

// ----------------------
// Errors
Expand Down Expand Up @@ -63,7 +52,7 @@ export interface SubscriptionOptions {
/**
* A class that represents a remote Nostr Relay.
*/
export class Relay extends NostrNode<
export class Relay extends NostrNodeBase<
ClientToRelayMessage,
RelayEventTypeRecord
> {
Expand All @@ -75,12 +64,7 @@ export class Relay extends NostrNode<
options?: RelayOptions,
) {
const url = typeof init === "string" ? init : init.url;
const config = {
nbuffer: 10,
logger: {},
...options,
modules: NIPs.concat(options?.modules ?? []),
};
const config = { nbuffer: 64, modules: [], ...options };
super(new LazyWebSocket(url), config);
this.config = {
url,
Expand Down Expand Up @@ -158,11 +142,9 @@ export class Relay extends NostrNode<
// RelayLikes
// ----------------------

export interface RelayLike extends WritableStream<ClientToRelayMessage> {
export interface RelayLike
extends Pick<Relay, "writable" | "send" | "subscribe" | "publish" | "close"> {
readonly config: RelayLikeConfig;
send: Relay["send"];
subscribe: Relay["subscribe"];
publish: Relay["publish"];
}

export type RelayLikeConfig = Pick<RelayConfig, "name" | "read" | "write">;
Expand Down
3 changes: 0 additions & 3 deletions core/relays_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,12 @@ describe("Relay", () => {
});

describe("constructed with url and options", () => {
const logger = { info: () => {} };
beforeAll(() => {
relay = new Relay(url, {
name: "test",
read: false,
write: false,
nbuffer: 20,
logger,
});
});
afterAll(() => {
Expand All @@ -58,7 +56,6 @@ describe("Relay", () => {
nbuffer: 20,
read: false,
write: false,
logger,
});
});
});
Expand Down
11 changes: 0 additions & 11 deletions core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,3 @@ export type AlphabetLetter =
| "H" | "I" | "J" | "K" | "L" | "M" | "N"
| "O" | "P" | "Q" | "R" | "S" | "T" | "U"
| "V" | "W" | "X" | "Y" | "Z";

// ----------------------
// Loggers
// ----------------------

export interface Logger {
debug?: (...args: unknown[]) => void;
info?: (...args: unknown[]) => void;
warn?: (...args: unknown[]) => void;
error?: (...args: unknown[]) => void;
}
Loading

0 comments on commit 2c145af

Please sign in to comment.