From c59f94460d8b002d4119306f804ec12410e88b32 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sun, 3 Mar 2024 14:23:27 +0000 Subject: [PATCH] rdr: Endpoint => consume / produce --- pkg/endpoint/src/endpoint.ts | 29 +++++++++++++---- pkg/rdr/package.json | 1 + pkg/rdr/src/consumer.ts | 62 ++++++++++++++---------------------- pkg/rdr/src/producer.ts | 24 +++++++++----- pkg/rdr/tests/rdr.t.ts | 18 +++++------ 5 files changed, 73 insertions(+), 61 deletions(-) diff --git a/pkg/endpoint/src/endpoint.ts b/pkg/endpoint/src/endpoint.ts index f7af4a63..9fdce160 100644 --- a/pkg/endpoint/src/endpoint.ts +++ b/pkg/endpoint/src/endpoint.ts @@ -14,6 +14,15 @@ import { produce, type Producer, type ProducerHandler, type ProducerOptions } fr export interface Options extends ConsumerOptions, ProducerOptions { } +const cOptsKeys: readonly string[] = [ + "fw", "describe", "signal", "modifyInterest", "retx", "verifier", +] satisfies ReadonlyArray; + +const pOptsKeys: readonly string[] = [ + "fw", "describe", "signal", "routeCapture", "announcement", + "concurrency", "dataSigner", "dataBuffer", "autoBuffer", +] satisfies ReadonlyArray; + /** * Endpoint provides basic consumer and producer functionality. It is the main entry point for an * application to interact with the logical forwarder. @@ -23,19 +32,27 @@ export interface Options extends ConsumerOptions, ProducerOptions { * functions instead. This class will be deprecated in the future. */ export class Endpoint { - constructor(public readonly opts: Options = {}) { - this.fw = opts.fw ?? Forwarder.getDefault(); - } + constructor(public readonly opts: Options = {}) {} /** Logical forwarder instance. */ - public readonly fw: Forwarder; + public get fw(): Forwarder { + return this.opts.fw ?? Forwarder.getDefault(); + } + + public get cOpts(): ConsumerOptions { + return Object.fromEntries(Object.entries(this.opts).filter(([key]) => cOptsKeys.includes(key))); + } + + public get pOpts(): ProducerOptions { + return Object.fromEntries(Object.entries(this.opts).filter(([key]) => pOptsKeys.includes(key))); + } /** * Retrieve a single piece of Data. * @param interest - Interest or Interest name. */ public consume(interest: Interest | NameLike, opts: ConsumerOptions = {}): ConsumerContext { - return consume(interest, { ...this.opts, fw: this.fw, ...opts }); + return consume(interest, { ...this.opts, ...opts }); } /** @@ -44,7 +61,7 @@ export class Endpoint { * @param handler - Function to handle incoming Interest. */ public produce(prefix: NameLike | undefined, handler: ProducerHandler, opts: ProducerOptions = {}): Producer { - return produce(prefix, handler, { ...this.opts, fw: this.fw, ...opts }); + return produce(prefix, handler, { ...this.opts, ...opts }); } } diff --git a/pkg/rdr/package.json b/pkg/rdr/package.json index e53f4922..81ba3c71 100644 --- a/pkg/rdr/package.json +++ b/pkg/rdr/package.json @@ -33,6 +33,7 @@ "tslib": "^2.6.2" }, "devDependencies": { + "@ndn/fw": "workspace:^", "@ndn/keychain": "workspace:*", "@ndn/util": "workspace:*" } diff --git a/pkg/rdr/src/consumer.ts b/pkg/rdr/src/consumer.ts index b09fd366..47147128 100644 --- a/pkg/rdr/src/consumer.ts +++ b/pkg/rdr/src/consumer.ts @@ -1,5 +1,5 @@ -import { Endpoint, type RetxPolicy } from "@ndn/endpoint"; -import { Interest, Name, type NameLike, type Verifier } from "@ndn/packet"; +import { consume, type ConsumerOptions, type Endpoint } from "@ndn/endpoint"; +import { Interest, Name, type NameLike } from "@ndn/packet"; import { Decoder } from "@ndn/tlv"; import { Metadata, MetadataKeyword } from "./metadata"; @@ -23,7 +23,10 @@ export function makeDiscoveryInterest(prefix: NameLike): Interest { * @param opts - Other options. * @returns Metadata packet. */ -export async function retrieveMetadata(prefix: NameLike, opts?: retrieveMetadata.Options): Promise; +export async function retrieveMetadata( + prefix: NameLike, + cOpts?: ConsumerOptions & EndpointOptions +): Promise; /** * Retrieve metadata packet of subclass type. @@ -33,52 +36,35 @@ export async function retrieveMetadata(prefix: NameLike, opts?: retrieveMetadata * @param opts - Other options. * @returns Metadata packet of type C. */ -export async function retrieveMetadata(prefix: NameLike, ctor: C, opts?: retrieveMetadata.Options): Promise>; +export async function retrieveMetadata( + prefix: NameLike, ctor: C, + cOpts?: ConsumerOptions & EndpointOptions +): Promise>; -export async function retrieveMetadata(prefix: NameLike, arg2: any = {}, opts: retrieveMetadata.Options = {}) { +export async function retrieveMetadata( + prefix: NameLike, arg2: any, + cOpts?: ConsumerOptions & EndpointOptions, +) { let ctor: Metadata.Constructor = Metadata; if (typeof arg2 === "function") { ctor = arg2; } else { - opts = arg2; + cOpts = arg2; } - const { - endpoint = new Endpoint(), - retx, - signal, - verifier, - } = opts; const interest = makeDiscoveryInterest(prefix); - const data = await endpoint.consume(interest, { + const data = await consume(interest, { describe: `RDR-c(${prefix})`, - retx, - signal, - verifier, + ...cOpts?.endpoint?.cOpts, // eslint-disable-line etc/no-deprecated + ...cOpts, }); return Decoder.decode(data.content, ctor); } -export namespace retrieveMetadata { - export interface Options { - /** - * Endpoint for communication. - * @defaultValue - * Endpoint on default logical forwarder. - */ - endpoint?: Endpoint; - - /** Interest retransmission policy. */ - retx?: RetxPolicy; - - /** Abort signal to cancel retrieval. */ - signal?: AbortSignal; - - /** - * Data verifier. - * @defaultValue - * No verification. - */ - verifier?: Verifier; - } +interface EndpointOptions { + /** + * Endpoint for communication. + * @deprecated Use {@link ConsumerOptions} fields only. + */ + endpoint?: Endpoint; } diff --git a/pkg/rdr/src/producer.ts b/pkg/rdr/src/producer.ts index f42d91bb..4bf7179d 100644 --- a/pkg/rdr/src/producer.ts +++ b/pkg/rdr/src/producer.ts @@ -1,4 +1,4 @@ -import { Endpoint, type Producer } from "@ndn/endpoint"; +import { type Endpoint, produce, type Producer, type ProducerOptions } from "@ndn/endpoint"; import { Segment, Version } from "@ndn/naming-convention2"; import { Data, type Interest, Name, type NameLike, noopSigning, type Signer } from "@ndn/packet"; import { Encoder } from "@ndn/tlv"; @@ -57,13 +57,14 @@ export function isDiscoveryInterest({ name, canBePrefix, mustBeFresh }: Interest export function serveMetadata(m: Metadata | (() => Metadata), opts: serveMetadata.Options = {}): Producer { const { prefix: prefixInput, - endpoint = new Endpoint(), - announcement, + endpoint, // eslint-disable-line etc/no-deprecated + pOpts, + announcement, // eslint-disable-line etc/no-deprecated } = opts; const makeMetadata = typeof m === "function" ? m : () => m; const prefix = makeName(makeMetadata(), prefixInput).getPrefix(-2); - return endpoint.produce(prefix, + return produce(prefix, async (interest) => { if (isDiscoveryInterest(interest) && interest.name.length === prefix.length) { return makeMetadataPacket(makeMetadata(), opts); @@ -73,19 +74,26 @@ export function serveMetadata(m: Metadata | (() => Metadata), opts: serveMetadat { describe: `RDR-s(${prefix})`, announcement, + ...endpoint?.pOpts, + ...pOpts, }); } export namespace serveMetadata { export interface Options extends makeMetadataPacket.Options { /** * Endpoint for communication. - * @defaultValue - * Endpoint on default logical forwarder. + * @deprecated Specify `.pOpts`. */ endpoint?: Endpoint; - /** Prefix to announce from producer. */ - announcement?: Endpoint.RouteAnnouncement; + /** Producer options. */ + pOpts?: ProducerOptions; + + /** + * Prefix to announce from producer. + * @deprecated Specify in `.pOpts.announcement`. + */ + announcement?: ProducerOptions.RouteAnnouncement; } } diff --git a/pkg/rdr/tests/rdr.t.ts b/pkg/rdr/tests/rdr.t.ts index 02a22695..dabab9f6 100644 --- a/pkg/rdr/tests/rdr.t.ts +++ b/pkg/rdr/tests/rdr.t.ts @@ -1,11 +1,12 @@ import "@ndn/packet/test-fixture/expect"; -import { Endpoint } from "@ndn/endpoint"; +import { consume } from "@ndn/endpoint"; +import { Forwarder } from "@ndn/fw"; import { generateSigningKey } from "@ndn/keychain"; import { Version } from "@ndn/naming-convention2"; import { Interest, Name, type Signer, type Verifier } from "@ndn/packet"; import { Decoder, Extensible, Extension, ExtensionRegistry, NNI, StructFieldNNI, StructFieldText } from "@ndn/tlv"; -import { Closers, toUtf8 } from "@ndn/util"; +import { Closers } from "@ndn/util"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import { Metadata, retrieveMetadata, serveMetadata } from ".."; @@ -20,7 +21,7 @@ beforeAll(async () => { const closers = new Closers(); afterEach(() => { closers.close(); - Endpoint.deleteDefaultForwarder(); + Forwarder.deleteDefault(); }); describe("consumer", () => { @@ -50,14 +51,13 @@ describe("producer", () => { const p = serveMetadata(simpleMetadata); closers.push(p); - const endpoint = new Endpoint(); const [data] = await Promise.all([ - endpoint.consume(new Interest("/D/32=metadata", Interest.CanBePrefix, Interest.MustBeFresh)), - expect(endpoint.consume(new Interest("/D/32=metadata", Interest.CanBePrefix, + consume(new Interest("/D/32=metadata", Interest.CanBePrefix, Interest.MustBeFresh)), + expect(consume(new Interest("/D/32=metadata", Interest.CanBePrefix, Interest.Lifetime(100)))).rejects.toThrow(), - expect(endpoint.consume(new Interest("/D/32=metadata", Interest.MustBeFresh, + expect(consume(new Interest("/D/32=metadata", Interest.MustBeFresh, Interest.Lifetime(100)))).rejects.toThrow(), - expect(endpoint.consume(new Interest(new Name("/D/32=metadata").append(Version, 4), + expect(consume(new Interest(new Name("/D/32=metadata").append(Version, 4), Interest.CanBePrefix, Interest.MustBeFresh, Interest.Lifetime(100)))).rejects.toThrow(), ]); @@ -73,7 +73,7 @@ describe("producer", () => { const p = serveMetadata(makeMetadata, { prefix: "/R", freshnessPeriod: 100 }); closers.push(p); - const data = await new Endpoint().consume(new Interest("/R/32=metadata", Interest.CanBePrefix, Interest.MustBeFresh)); + const data = await consume(new Interest("/R/32=metadata", Interest.CanBePrefix, Interest.MustBeFresh)); expect(data.name).toHaveLength(4); expect(data.freshnessPeriod).toBe(100); const name2 = Decoder.decode(data.content, Name);