Comparing version 0.0.20240630 to 0.0.20250122
@@ -26,3 +26,3 @@ import { Data, Interest, Nack, Name, NameMultiSet } from "@ndn/packet"; | ||
} | ||
return Name.from(announcement); | ||
return announcement; | ||
} | ||
@@ -34,3 +34,2 @@ export class FaceImpl extends TypedEventTarget { | ||
routes = new NameMultiSet(); | ||
announcements = new NameMultiSet(); | ||
running = true; | ||
@@ -66,5 +65,3 @@ txQueue = pushable(); | ||
} | ||
for (const [name] of this.announcements.multiplicities()) { | ||
this.fw.readvertise.removeAnnouncement(this, name); | ||
} | ||
this.fw.readvertise.clearFace(this); | ||
this.txQueue.fail(new Error("close")); | ||
@@ -103,19 +100,13 @@ this.dispatchTypedEvent("close", new Event("close")); | ||
} | ||
addAnnouncement(nameInput) { | ||
addAnnouncement(announcement) { | ||
if (!this.attributes.advertiseFrom) { | ||
return; | ||
} | ||
const name = Name.from(nameInput); | ||
if (this.announcements.add(name) === 1) { | ||
this.fw.readvertise.addAnnouncement(this, name); | ||
} | ||
this.fw.readvertise.addAnnouncement(this, announcement); | ||
} | ||
removeAnnouncement(nameInput) { | ||
removeAnnouncement(announcement) { | ||
if (!this.attributes.advertiseFrom) { | ||
return; | ||
} | ||
const name = Name.from(nameInput); | ||
if (this.announcements.remove(name) === 0) { | ||
this.fw.readvertise.removeAnnouncement(this, name); | ||
} | ||
this.fw.readvertise.removeAnnouncement(this, announcement); | ||
} | ||
@@ -122,0 +113,0 @@ /** Transmit a packet on the face. */ |
@@ -26,3 +26,3 @@ import { Data, Interest, Nack, Name, NameMultiSet } from "@ndn/packet"; | ||
} | ||
return Name.from(announcement); | ||
return announcement; | ||
} | ||
@@ -34,3 +34,2 @@ export class FaceImpl extends TypedEventTarget { | ||
routes = new NameMultiSet(); | ||
announcements = new NameMultiSet(); | ||
running = true; | ||
@@ -66,5 +65,3 @@ txQueue = pushable(); | ||
} | ||
for (const [name] of this.announcements.multiplicities()) { | ||
this.fw.readvertise.removeAnnouncement(this, name); | ||
} | ||
this.fw.readvertise.clearFace(this); | ||
this.txQueue.fail(new Error("close")); | ||
@@ -103,19 +100,13 @@ this.dispatchTypedEvent("close", new Event("close")); | ||
} | ||
addAnnouncement(nameInput) { | ||
addAnnouncement(announcement) { | ||
if (!this.attributes.advertiseFrom) { | ||
return; | ||
} | ||
const name = Name.from(nameInput); | ||
if (this.announcements.add(name) === 1) { | ||
this.fw.readvertise.addAnnouncement(this, name); | ||
} | ||
this.fw.readvertise.addAnnouncement(this, announcement); | ||
} | ||
removeAnnouncement(nameInput) { | ||
removeAnnouncement(announcement) { | ||
if (!this.attributes.advertiseFrom) { | ||
return; | ||
} | ||
const name = Name.from(nameInput); | ||
if (this.announcements.remove(name) === 0) { | ||
this.fw.readvertise.removeAnnouncement(this, name); | ||
} | ||
this.fw.readvertise.removeAnnouncement(this, announcement); | ||
} | ||
@@ -122,0 +113,0 @@ /** Transmit a packet on the face. */ |
@@ -1,2 +0,2 @@ | ||
import { type NameLike } from "@ndn/packet"; | ||
import { Name, type NameLike } from "@ndn/packet"; | ||
import { TypedEventTarget } from "typescript-event-target"; | ||
@@ -50,5 +50,5 @@ import { Forwarder, type ForwarderImpl } from "./forwarder.js"; | ||
*/ | ||
addAnnouncement: (name: NameLike) => void; | ||
addAnnouncement: (announcement: FwFace.PrefixAnnouncement) => void; | ||
/** Remove a prefix announcement associated with the face. */ | ||
removeAnnouncement: (name: NameLike) => void; | ||
removeAnnouncement: (announcement: FwFace.PrefixAnnouncement) => void; | ||
} | ||
@@ -89,3 +89,15 @@ export declare namespace FwFace { | ||
*/ | ||
type RouteAnnouncement = boolean | number | NameLike; | ||
type RouteAnnouncement = boolean | number | PrefixAnnouncement; | ||
/** Prefix announcement passed to {@link FwFace.addAnnouncement}. */ | ||
type PrefixAnnouncement = NameLike | PrefixAnnouncementObj; | ||
/** | ||
* Prefix announcement object. | ||
* This would be passed to ReadvertiseDestination for its selective use. | ||
* | ||
* @remarks | ||
* One implementation is `PrefixAnn` in \@ndn/nfdmgmt package. | ||
*/ | ||
interface PrefixAnnouncementObj { | ||
readonly announced: Name; | ||
} | ||
type RxTxEventMap = Pick<EventMap, "up" | "down">; | ||
@@ -119,3 +131,2 @@ interface RxTxBase { | ||
private readonly routes; | ||
private readonly announcements; | ||
running: boolean; | ||
@@ -129,4 +140,4 @@ private readonly txQueue; | ||
removeRoute(nameInput: NameLike, announcement?: FwFace.RouteAnnouncement): void; | ||
addAnnouncement(nameInput: NameLike): void; | ||
removeAnnouncement(nameInput: NameLike): void; | ||
addAnnouncement(announcement: FwFace.PrefixAnnouncement): void; | ||
removeAnnouncement(announcement: FwFace.PrefixAnnouncement): void; | ||
/** Transmit a packet on the face. */ | ||
@@ -133,0 +144,0 @@ send(pkt: FwPacket): void; |
@@ -1,5 +0,3 @@ | ||
import { __importDefault, __importStar } from "tslib"; | ||
import { lpm } from "@ndn/packet"; | ||
import { assert } from "@ndn/util"; | ||
import _cjsDefaultImport0 from "mnemonist/default-map.js"; const DefaultMap = __importDefault(_cjsDefaultImport0).default; | ||
import { assert, getOrInsert } from "@ndn/util"; | ||
class FibEntry { | ||
@@ -9,5 +7,5 @@ nexthops = new Map(); // face=>capture | ||
export class Fib { | ||
table = new DefaultMap(() => new FibEntry()); | ||
table = new Map(); | ||
insert(face, nameHex, capture) { | ||
const entry = this.table.get(nameHex); | ||
const entry = getOrInsert(this.table, nameHex, () => new FibEntry()); | ||
assert(!entry.nexthops.has(face)); | ||
@@ -17,3 +15,3 @@ entry.nexthops.set(face, capture); | ||
delete(face, nameHex) { | ||
const entry = this.table.peek(nameHex); | ||
const entry = this.table.get(nameHex); | ||
assert(!!entry); | ||
@@ -27,3 +25,3 @@ entry.nexthops.delete(face); | ||
const result = new Set(); | ||
for (const entry of lpm(name, (prefixHex) => this.table.peek(prefixHex))) { | ||
for (const entry of lpm(name, (prefixHex) => this.table.get(prefixHex))) { | ||
let capture = false; | ||
@@ -30,0 +28,0 @@ for (const [nh, c] of entry.nexthops) { |
@@ -1,5 +0,3 @@ | ||
import { __importDefault, __importStar } from "tslib"; | ||
import { lpm } from "@ndn/packet"; | ||
import { assert } from "@ndn/util"; | ||
import _cjsDefaultImport0 from "mnemonist/default-map.js"; const DefaultMap = __importDefault(_cjsDefaultImport0).default; | ||
import { assert, getOrInsert } from "@ndn/util"; | ||
class FibEntry { | ||
@@ -9,5 +7,5 @@ nexthops = new Map(); // face=>capture | ||
export class Fib { | ||
table = new DefaultMap(() => new FibEntry()); | ||
table = new Map(); | ||
insert(face, nameHex, capture) { | ||
const entry = this.table.get(nameHex); | ||
const entry = getOrInsert(this.table, nameHex, () => new FibEntry()); | ||
assert(!entry.nexthops.has(face)); | ||
@@ -17,3 +15,3 @@ entry.nexthops.set(face, capture); | ||
delete(face, nameHex) { | ||
const entry = this.table.peek(nameHex); | ||
const entry = this.table.get(nameHex); | ||
assert(!!entry); | ||
@@ -27,3 +25,3 @@ entry.nexthops.delete(face); | ||
const result = new Set(); | ||
for (const entry of lpm(name, (prefixHex) => this.table.peek(prefixHex))) { | ||
for (const entry of lpm(name, (prefixHex) => this.table.get(prefixHex))) { | ||
let capture = false; | ||
@@ -30,0 +28,0 @@ for (const [nh, c] of entry.nexthops) { |
@@ -1,8 +0,5 @@ | ||
import { __importDefault, __importStar } from "tslib"; | ||
import { Interest } from "@ndn/packet"; | ||
import hirestime from "hirestime"; | ||
import _cjsDefaultImport0 from "mnemonist/default-map.js"; const DefaultMap = __importDefault(_cjsDefaultImport0).default; | ||
import { getOrInsert } from "@ndn/util"; | ||
import { filter, flatMap, pipeline, reduce, tap } from "streaming-iterables"; | ||
import { FwPacket, RejectInterest } from "./packet_browser.js"; | ||
const getNow = hirestime(); | ||
/** Aggregated pending Interests from one or more downstream faces. */ | ||
@@ -17,3 +14,3 @@ export class PitEntry { | ||
/** Downstream records. */ | ||
dnRecords = new DefaultMap(() => ({ nRx: 0, expire: 0, nonce: 0, token: undefined })); | ||
dnRecords = new Map(); | ||
/** Last expiration time among downstream. */ | ||
@@ -30,6 +27,6 @@ lastExpire = 0; | ||
receiveInterest(face, { l3: interest, token }) { | ||
const now = getNow(); | ||
const now = performance.now(); | ||
const expire = now + interest.lifetime; | ||
const nonce = interest.nonce ?? Interest.generateNonce(); | ||
const dnR = this.dnRecords.get(face); | ||
const dnR = getOrInsert(this.dnRecords, face, () => ({ nRx: 0, expire: 0, nonce: 0, token: undefined })); | ||
++dnR.nRx; | ||
@@ -43,3 +40,3 @@ dnR.expire = expire; | ||
cancelInterest(face) { | ||
const dnR = this.dnRecords.peek(face); | ||
const dnR = this.dnRecords.get(face); | ||
if (!dnR) { | ||
@@ -54,3 +51,3 @@ return; | ||
forwardInterest(face) { | ||
const lifetime = this.lastExpire - getNow(); | ||
const lifetime = this.lastExpire - performance.now(); | ||
if (lifetime <= 0) { | ||
@@ -66,3 +63,3 @@ return; | ||
this.pit.eraseEntry(this); | ||
const now = getNow(); | ||
const now = performance.now(); | ||
for (const [dn, { expire, token }] of this.dnRecords) { | ||
@@ -74,3 +71,3 @@ if (expire > now && dn !== up) { | ||
} | ||
updateExpire(now = getNow()) { | ||
updateExpire(now = performance.now()) { | ||
let lastExpire = 0; | ||
@@ -77,0 +74,0 @@ for (const { expire } of this.dnRecords.values()) { |
@@ -1,8 +0,5 @@ | ||
import { __importDefault, __importStar } from "tslib"; | ||
import { Interest } from "@ndn/packet"; | ||
import hirestime from "hirestime"; | ||
import _cjsDefaultImport0 from "mnemonist/default-map.js"; const DefaultMap = __importDefault(_cjsDefaultImport0).default; | ||
import { getOrInsert } from "@ndn/util"; | ||
import { filter, flatMap, pipeline, reduce, tap } from "streaming-iterables"; | ||
import { FwPacket, RejectInterest } from "./packet_node.js"; | ||
const getNow = hirestime(); | ||
/** Aggregated pending Interests from one or more downstream faces. */ | ||
@@ -17,3 +14,3 @@ export class PitEntry { | ||
/** Downstream records. */ | ||
dnRecords = new DefaultMap(() => ({ nRx: 0, expire: 0, nonce: 0, token: undefined })); | ||
dnRecords = new Map(); | ||
/** Last expiration time among downstream. */ | ||
@@ -30,6 +27,6 @@ lastExpire = 0; | ||
receiveInterest(face, { l3: interest, token }) { | ||
const now = getNow(); | ||
const now = performance.now(); | ||
const expire = now + interest.lifetime; | ||
const nonce = interest.nonce ?? Interest.generateNonce(); | ||
const dnR = this.dnRecords.get(face); | ||
const dnR = getOrInsert(this.dnRecords, face, () => ({ nRx: 0, expire: 0, nonce: 0, token: undefined })); | ||
++dnR.nRx; | ||
@@ -43,3 +40,3 @@ dnR.expire = expire; | ||
cancelInterest(face) { | ||
const dnR = this.dnRecords.peek(face); | ||
const dnR = this.dnRecords.get(face); | ||
if (!dnR) { | ||
@@ -54,3 +51,3 @@ return; | ||
forwardInterest(face) { | ||
const lifetime = this.lastExpire - getNow(); | ||
const lifetime = this.lastExpire - performance.now(); | ||
if (lifetime <= 0) { | ||
@@ -66,3 +63,3 @@ return; | ||
this.pit.eraseEntry(this); | ||
const now = getNow(); | ||
const now = performance.now(); | ||
for (const [dn, { expire, token }] of this.dnRecords) { | ||
@@ -74,3 +71,3 @@ if (expire > now && dn !== up) { | ||
} | ||
updateExpire(now = getNow()) { | ||
updateExpire(now = performance.now()) { | ||
let lastExpire = 0; | ||
@@ -77,0 +74,0 @@ for (const { expire } of this.dnRecords.values()) { |
import { type Data, Interest } from "@ndn/packet"; | ||
import DefaultMap from "mnemonist/default-map.js"; | ||
import type { FaceImpl } from "./face.js"; | ||
@@ -25,3 +24,3 @@ import { FwPacket } from "./packet.js"; | ||
/** Downstream records. */ | ||
dnRecords: DefaultMap<FaceImpl, PitDn>; | ||
dnRecords: Map<FaceImpl, PitDn>; | ||
/** Last expiration time among downstream. */ | ||
@@ -44,3 +43,3 @@ lastExpire: number; | ||
private updateExpire; | ||
private expire; | ||
private readonly expire; | ||
} | ||
@@ -47,0 +46,0 @@ /** Pending Interest table. */ |
import { __importDefault, __importStar } from "tslib"; | ||
import { NameMap, NameMultiMap } from "@ndn/packet"; | ||
import { pushable } from "@ndn/util"; | ||
import _cjsDefaultImport0 from "retry"; const retry = __importDefault(_cjsDefaultImport0).default; | ||
import { Name, NameMap } from "@ndn/packet"; | ||
import { assert, getOrInsert, pushable } from "@ndn/util"; | ||
import _cjsDefaultImport0 from "obliterator/filter.js"; const filter = __importDefault(_cjsDefaultImport0).default; | ||
import _cjsDefaultImport1 from "retry"; const retry = __importDefault(_cjsDefaultImport1).default; | ||
import { Forwarder } from "./forwarder_browser.js"; | ||
@@ -19,6 +20,40 @@ /** | ||
} | ||
announcements = new NameMultiMap(); | ||
destinations = new Set(); | ||
addAnnouncement(face, name) { | ||
if (this.announcements.add(name, face) > 1) { | ||
/** | ||
* Prefix announcements arranged by name. | ||
* | ||
* NameMap key is the announced name. | ||
* Map key is a reference to the FwFace announcing the name. | ||
* Map value is an array of announcements made by the FwFace. | ||
* Array contains application supplied announcement objects or `undefined` for plain names. | ||
* Neither the Map nor the Array may be empty. | ||
* | ||
* More than one FwFaces can announce the same name simultaneously. | ||
* An FwFace can announce the same name more than once. | ||
* This stack of containers is to deduplicate these announcements. | ||
* | ||
* A name is being announced if at least one FwFace announces the name at least once. | ||
*/ | ||
byName = new NameMap(); | ||
/** | ||
* Prefix announcements arranged by FwFace. | ||
* | ||
* Outer key is the FwFace. | ||
* Inner key is the announced name in hex. | ||
* Inner key is the announced name. | ||
* | ||
* This is for deleting all announcements from a FwFace. | ||
*/ | ||
byFace = new Map(); | ||
addAnnouncement(face, ann) { | ||
const [name, pa] = splitAnnouncement(ann); | ||
const nameFaces = getOrInsert(this.byName, name, () => new Map()); | ||
const isNewName = nameFaces.size === 0; // no face was announcing this name | ||
const nameFaceAnns = getOrInsert(nameFaces, face, () => []); | ||
if (nameFaceAnns.length === 0) { // this face was not announcing this name | ||
const faceNames = getOrInsert(this.byFace, face, () => new Map()); | ||
faceNames.set(name.valueHex, name); | ||
} | ||
nameFaceAnns.push(pa); | ||
if (!isNewName) { | ||
return; | ||
@@ -31,6 +66,34 @@ } | ||
} | ||
removeAnnouncement(face, name) { | ||
if (this.announcements.remove(name, face) > 0) { | ||
removeAnnouncement(face, ann) { | ||
const [name, pa] = splitAnnouncement(ann); | ||
this.removeAnnouncementImpl(face, name, (nameFaceAnns) => { | ||
// If ann is an announcement object, find the same object (must be same instance). | ||
// If ann is a plain name (pa is undefined), find another plain name. | ||
// In case of no match, delete an arbitrary item from the array. | ||
const i = Math.max(nameFaceAnns.indexOf(pa), 0); | ||
nameFaceAnns.splice(i, 1); | ||
}); | ||
} | ||
removeAnnouncementImpl(face, name, delPa) { | ||
const nameFaces = this.byName.get(name); | ||
const nameFaceAnns = nameFaces?.get(face); | ||
if (!nameFaceAnns?.length) { // face was not announcing this name | ||
return; | ||
} | ||
delPa(nameFaceAnns); | ||
if (nameFaceAnns.length > 0) { // face is still announcing this name | ||
return; | ||
} | ||
// face is no longer announcing the name | ||
const faceNames = this.byFace.get(face); | ||
faceNames.delete(name.valueHex); | ||
if (faceNames.size === 0) { // face is no longer announcing any name | ||
this.byFace.delete(face); | ||
} | ||
nameFaces.delete(face); | ||
if (nameFaces.size > 0) { // name is still announced by another face | ||
return; | ||
} | ||
// name is no longer announced by any face | ||
this.byName.delete(name); | ||
this.fw.dispatchTypedEvent("annrm", new Forwarder.AnnouncementEvent("annrm", name)); | ||
@@ -41,2 +104,21 @@ for (const dest of this.destinations) { | ||
} | ||
clearFace(face) { | ||
const faceNames = this.byFace.get(face); | ||
if (!faceNames) { | ||
return; | ||
} | ||
for (const name of faceNames.values()) { | ||
this.removeAnnouncementImpl(face, name, (nameFaceAnns) => nameFaceAnns.splice(0, Infinity)); | ||
} | ||
assert(!this.byFace.has(face)); | ||
} | ||
*listAnnouncementObjs(name) { | ||
const nameFaces = this.byName.get(name); | ||
if (!nameFaces) { | ||
return; | ||
} | ||
for (const nameFaceAnns of nameFaces.values()) { | ||
yield* filter(nameFaceAnns, (ann) => !!ann); | ||
} | ||
} | ||
/** | ||
@@ -77,3 +159,3 @@ * Cancel timers and other I/O resources. | ||
this.readvertise.destinations.add(this); | ||
for (const [name] of this.readvertise.announcements.associations()) { | ||
for (const [name] of this.readvertise.byName) { | ||
this.advertise(name); | ||
@@ -171,3 +253,8 @@ } | ||
} | ||
/** Create per-prefix state. */ | ||
/** | ||
* Create per-prefix state. | ||
* | ||
* @remarks | ||
* Must override if State type parameter is changed from the default. | ||
*/ | ||
makeState(name) { | ||
@@ -177,2 +264,11 @@ void name; | ||
} | ||
/** | ||
* Retrieve application supplied prefix announcement objects. | ||
* | ||
* @remarks | ||
* This is only available during {@link makeState} and {@link doAdvertise}. | ||
*/ | ||
listAnnouncementObjs(name) { | ||
return this.readvertise.listAnnouncementObjs(name); | ||
} | ||
} | ||
@@ -188,1 +284,7 @@ (function (ReadvertiseDestination) { | ||
})(ReadvertiseDestination || (ReadvertiseDestination = {})); | ||
function splitAnnouncement(ann) { | ||
if (Name.isNameLike(ann)) { | ||
return [Name.from(ann), undefined]; | ||
} | ||
return [ann.announced, ann]; | ||
} |
import { __importDefault, __importStar } from "tslib"; | ||
import { NameMap, NameMultiMap } from "@ndn/packet"; | ||
import { pushable } from "@ndn/util"; | ||
import _cjsDefaultImport0 from "retry"; const retry = __importDefault(_cjsDefaultImport0).default; | ||
import { Name, NameMap } from "@ndn/packet"; | ||
import { assert, getOrInsert, pushable } from "@ndn/util"; | ||
import _cjsDefaultImport0 from "obliterator/filter.js"; const filter = __importDefault(_cjsDefaultImport0).default; | ||
import _cjsDefaultImport1 from "retry"; const retry = __importDefault(_cjsDefaultImport1).default; | ||
import { Forwarder } from "./forwarder_node.js"; | ||
@@ -19,6 +20,40 @@ /** | ||
} | ||
announcements = new NameMultiMap(); | ||
destinations = new Set(); | ||
addAnnouncement(face, name) { | ||
if (this.announcements.add(name, face) > 1) { | ||
/** | ||
* Prefix announcements arranged by name. | ||
* | ||
* NameMap key is the announced name. | ||
* Map key is a reference to the FwFace announcing the name. | ||
* Map value is an array of announcements made by the FwFace. | ||
* Array contains application supplied announcement objects or `undefined` for plain names. | ||
* Neither the Map nor the Array may be empty. | ||
* | ||
* More than one FwFaces can announce the same name simultaneously. | ||
* An FwFace can announce the same name more than once. | ||
* This stack of containers is to deduplicate these announcements. | ||
* | ||
* A name is being announced if at least one FwFace announces the name at least once. | ||
*/ | ||
byName = new NameMap(); | ||
/** | ||
* Prefix announcements arranged by FwFace. | ||
* | ||
* Outer key is the FwFace. | ||
* Inner key is the announced name in hex. | ||
* Inner key is the announced name. | ||
* | ||
* This is for deleting all announcements from a FwFace. | ||
*/ | ||
byFace = new Map(); | ||
addAnnouncement(face, ann) { | ||
const [name, pa] = splitAnnouncement(ann); | ||
const nameFaces = getOrInsert(this.byName, name, () => new Map()); | ||
const isNewName = nameFaces.size === 0; // no face was announcing this name | ||
const nameFaceAnns = getOrInsert(nameFaces, face, () => []); | ||
if (nameFaceAnns.length === 0) { // this face was not announcing this name | ||
const faceNames = getOrInsert(this.byFace, face, () => new Map()); | ||
faceNames.set(name.valueHex, name); | ||
} | ||
nameFaceAnns.push(pa); | ||
if (!isNewName) { | ||
return; | ||
@@ -31,6 +66,34 @@ } | ||
} | ||
removeAnnouncement(face, name) { | ||
if (this.announcements.remove(name, face) > 0) { | ||
removeAnnouncement(face, ann) { | ||
const [name, pa] = splitAnnouncement(ann); | ||
this.removeAnnouncementImpl(face, name, (nameFaceAnns) => { | ||
// If ann is an announcement object, find the same object (must be same instance). | ||
// If ann is a plain name (pa is undefined), find another plain name. | ||
// In case of no match, delete an arbitrary item from the array. | ||
const i = Math.max(nameFaceAnns.indexOf(pa), 0); | ||
nameFaceAnns.splice(i, 1); | ||
}); | ||
} | ||
removeAnnouncementImpl(face, name, delPa) { | ||
const nameFaces = this.byName.get(name); | ||
const nameFaceAnns = nameFaces?.get(face); | ||
if (!nameFaceAnns?.length) { // face was not announcing this name | ||
return; | ||
} | ||
delPa(nameFaceAnns); | ||
if (nameFaceAnns.length > 0) { // face is still announcing this name | ||
return; | ||
} | ||
// face is no longer announcing the name | ||
const faceNames = this.byFace.get(face); | ||
faceNames.delete(name.valueHex); | ||
if (faceNames.size === 0) { // face is no longer announcing any name | ||
this.byFace.delete(face); | ||
} | ||
nameFaces.delete(face); | ||
if (nameFaces.size > 0) { // name is still announced by another face | ||
return; | ||
} | ||
// name is no longer announced by any face | ||
this.byName.delete(name); | ||
this.fw.dispatchTypedEvent("annrm", new Forwarder.AnnouncementEvent("annrm", name)); | ||
@@ -41,2 +104,21 @@ for (const dest of this.destinations) { | ||
} | ||
clearFace(face) { | ||
const faceNames = this.byFace.get(face); | ||
if (!faceNames) { | ||
return; | ||
} | ||
for (const name of faceNames.values()) { | ||
this.removeAnnouncementImpl(face, name, (nameFaceAnns) => nameFaceAnns.splice(0, Infinity)); | ||
} | ||
assert(!this.byFace.has(face)); | ||
} | ||
*listAnnouncementObjs(name) { | ||
const nameFaces = this.byName.get(name); | ||
if (!nameFaces) { | ||
return; | ||
} | ||
for (const nameFaceAnns of nameFaces.values()) { | ||
yield* filter(nameFaceAnns, (ann) => !!ann); | ||
} | ||
} | ||
/** | ||
@@ -77,3 +159,3 @@ * Cancel timers and other I/O resources. | ||
this.readvertise.destinations.add(this); | ||
for (const [name] of this.readvertise.announcements.associations()) { | ||
for (const [name] of this.readvertise.byName) { | ||
this.advertise(name); | ||
@@ -171,3 +253,8 @@ } | ||
} | ||
/** Create per-prefix state. */ | ||
/** | ||
* Create per-prefix state. | ||
* | ||
* @remarks | ||
* Must override if State type parameter is changed from the default. | ||
*/ | ||
makeState(name) { | ||
@@ -177,2 +264,11 @@ void name; | ||
} | ||
/** | ||
* Retrieve application supplied prefix announcement objects. | ||
* | ||
* @remarks | ||
* This is only available during {@link makeState} and {@link doAdvertise}. | ||
*/ | ||
listAnnouncementObjs(name) { | ||
return this.readvertise.listAnnouncementObjs(name); | ||
} | ||
} | ||
@@ -188,1 +284,7 @@ (function (ReadvertiseDestination) { | ||
})(ReadvertiseDestination || (ReadvertiseDestination = {})); | ||
function splitAnnouncement(ann) { | ||
if (Name.isNameLike(ann)) { | ||
return [Name.from(ann), undefined]; | ||
} | ||
return [ann.announced, ann]; | ||
} |
@@ -1,4 +0,4 @@ | ||
import { type Name, NameMap, NameMultiMap } from "@ndn/packet"; | ||
import { Name, NameMap } from "@ndn/packet"; | ||
import * as retry from "retry"; | ||
import type { FaceImpl } from "./face.js"; | ||
import type { FaceImpl, FwFace } from "./face.js"; | ||
import { Forwarder, type ForwarderImpl } from "./forwarder.js"; | ||
@@ -16,7 +16,35 @@ /** | ||
constructor(fw: ForwarderImpl); | ||
readonly announcements: NameMultiMap<FaceImpl>; | ||
readonly destinations: Set<ReadvertiseDestination<{}>>; | ||
addAnnouncement(face: FaceImpl, name: Name): void; | ||
removeAnnouncement(face: FaceImpl, name: Name): void; | ||
/** | ||
* Prefix announcements arranged by name. | ||
* | ||
* NameMap key is the announced name. | ||
* Map key is a reference to the FwFace announcing the name. | ||
* Map value is an array of announcements made by the FwFace. | ||
* Array contains application supplied announcement objects or `undefined` for plain names. | ||
* Neither the Map nor the Array may be empty. | ||
* | ||
* More than one FwFaces can announce the same name simultaneously. | ||
* An FwFace can announce the same name more than once. | ||
* This stack of containers is to deduplicate these announcements. | ||
* | ||
* A name is being announced if at least one FwFace announces the name at least once. | ||
*/ | ||
readonly byName: NameMap<Map<FaceImpl, (FwFace.PrefixAnnouncementObj | undefined)[]>>; | ||
/** | ||
* Prefix announcements arranged by FwFace. | ||
* | ||
* Outer key is the FwFace. | ||
* Inner key is the announced name in hex. | ||
* Inner key is the announced name. | ||
* | ||
* This is for deleting all announcements from a FwFace. | ||
*/ | ||
private readonly byFace; | ||
addAnnouncement(face: FaceImpl, ann: FwFace.PrefixAnnouncement): void; | ||
removeAnnouncement(face: FaceImpl, ann: FwFace.PrefixAnnouncement): void; | ||
private removeAnnouncementImpl; | ||
clearFace(face: FaceImpl): void; | ||
listAnnouncementObjs(name: Name): Iterable<FwFace.PrefixAnnouncementObj>; | ||
/** | ||
* Cancel timers and other I/O resources. | ||
@@ -56,4 +84,16 @@ * This instance should not be used after this operation. | ||
private process; | ||
/** Create per-prefix state. */ | ||
/** | ||
* Create per-prefix state. | ||
* | ||
* @remarks | ||
* Must override if State type parameter is changed from the default. | ||
*/ | ||
protected makeState(name: Name): State; | ||
/** | ||
* Retrieve application supplied prefix announcement objects. | ||
* | ||
* @remarks | ||
* This is only available during {@link makeState} and {@link doAdvertise}. | ||
*/ | ||
protected listAnnouncementObjs(name: Name): Iterable<FwFace.PrefixAnnouncementObj>; | ||
/** Advertise a prefix once. */ | ||
@@ -60,0 +100,0 @@ protected abstract doAdvertise(name: Name, state: State): Promise<void>; |
@@ -1,4 +0,2 @@ | ||
import { __importDefault, __importStar } from "tslib"; | ||
import { assert, MultiMap, pushable } from "@ndn/util"; | ||
import _cjsDefaultImport0 from "mnemonist/default-weak-map.js"; const DefaultWeakMap = __importDefault(_cjsDefaultImport0).default; | ||
import { assert, getOrInsert, MultiMap, pushable } from "@ndn/util"; | ||
import { Forwarder } from "./forwarder_browser.js"; | ||
@@ -42,5 +40,5 @@ class TapRxController { | ||
} | ||
const ctrls = new DefaultWeakMap((fw) => new TapRxController(fw)); | ||
const ctrls = new WeakMap(); | ||
/** | ||
* Create a secondary face by tapping on a primary face. | ||
* Create a secondary face that shares the transport of a primary face. | ||
* | ||
@@ -55,6 +53,15 @@ * @remarks | ||
face; | ||
/** | ||
* Create a new secondary {@link Forwarder} and add a {@link TapFace}. | ||
* @param face - FwFace on the existing primary forwarder. | ||
* @returns FwFace on a new forwarder. The forwarder may be retrieved in `.fw` property. | ||
*/ | ||
static create(face) { | ||
const fw = Forwarder.create(); | ||
return fw.addFace(new TapFace(face)); | ||
} | ||
constructor(face) { | ||
this.face = face; | ||
this.ctrl = ctrls.get(face.fw); | ||
this.ctrl.add(this.face, this); | ||
this.ctrl = getOrInsert(ctrls, face.fw, () => new TapRxController(face.fw)); | ||
this.ctrl.add(face, this); | ||
} | ||
@@ -76,13 +83,1 @@ get attributes() { | ||
} | ||
(function (TapFace) { | ||
/** | ||
* Create a new {@link Forwarder} and add a {@link TapFace}. | ||
* @param face - FwFace on the existing forwarder. | ||
* @returns FwFace on a new forwarder. The forwarder may be retrieved in `.fw` property. | ||
*/ | ||
function create(face) { | ||
const fw = Forwarder.create(); | ||
return fw.addFace(new TapFace(face)); | ||
} | ||
TapFace.create = create; | ||
})(TapFace || (TapFace = {})); |
@@ -1,4 +0,2 @@ | ||
import { __importDefault, __importStar } from "tslib"; | ||
import { assert, MultiMap, pushable } from "@ndn/util"; | ||
import _cjsDefaultImport0 from "mnemonist/default-weak-map.js"; const DefaultWeakMap = __importDefault(_cjsDefaultImport0).default; | ||
import { assert, getOrInsert, MultiMap, pushable } from "@ndn/util"; | ||
import { Forwarder } from "./forwarder_node.js"; | ||
@@ -42,5 +40,5 @@ class TapRxController { | ||
} | ||
const ctrls = new DefaultWeakMap((fw) => new TapRxController(fw)); | ||
const ctrls = new WeakMap(); | ||
/** | ||
* Create a secondary face by tapping on a primary face. | ||
* Create a secondary face that shares the transport of a primary face. | ||
* | ||
@@ -55,6 +53,15 @@ * @remarks | ||
face; | ||
/** | ||
* Create a new secondary {@link Forwarder} and add a {@link TapFace}. | ||
* @param face - FwFace on the existing primary forwarder. | ||
* @returns FwFace on a new forwarder. The forwarder may be retrieved in `.fw` property. | ||
*/ | ||
static create(face) { | ||
const fw = Forwarder.create(); | ||
return fw.addFace(new TapFace(face)); | ||
} | ||
constructor(face) { | ||
this.face = face; | ||
this.ctrl = ctrls.get(face.fw); | ||
this.ctrl.add(this.face, this); | ||
this.ctrl = getOrInsert(ctrls, face.fw, () => new TapRxController(face.fw)); | ||
this.ctrl.add(face, this); | ||
} | ||
@@ -76,13 +83,1 @@ get attributes() { | ||
} | ||
(function (TapFace) { | ||
/** | ||
* Create a new {@link Forwarder} and add a {@link TapFace}. | ||
* @param face - FwFace on the existing forwarder. | ||
* @returns FwFace on a new forwarder. The forwarder may be retrieved in `.fw` property. | ||
*/ | ||
function create(face) { | ||
const fw = Forwarder.create(); | ||
return fw.addFace(new TapFace(face)); | ||
} | ||
TapFace.create = create; | ||
})(TapFace || (TapFace = {})); |
import type { FwFace } from "./face.js"; | ||
import type { FwPacket } from "./packet.js"; | ||
/** | ||
* Create a secondary face by tapping on a primary face. | ||
* Create a secondary face that shares the transport of a primary face. | ||
* | ||
@@ -14,3 +14,9 @@ * @remarks | ||
readonly face: FwFace; | ||
constructor(face: FwFace); | ||
/** | ||
* Create a new secondary {@link Forwarder} and add a {@link TapFace}. | ||
* @param face - FwFace on the existing primary forwarder. | ||
* @returns FwFace on a new forwarder. The forwarder may be retrieved in `.fw` property. | ||
*/ | ||
static create(face: FwFace): FwFace; | ||
private constructor(); | ||
get attributes(): { | ||
@@ -26,9 +32,1 @@ describe: string; | ||
} | ||
export declare namespace TapFace { | ||
/** | ||
* Create a new {@link Forwarder} and add a {@link TapFace}. | ||
* @param face - FwFace on the existing forwarder. | ||
* @returns FwFace on a new forwarder. The forwarder may be retrieved in `.fw` property. | ||
*/ | ||
function create(face: FwFace): FwFace; | ||
} |
{ | ||
"name": "@ndn/fw", | ||
"version": "0.0.20240630", | ||
"version": "0.0.20250122", | ||
"description": "NDNts: Logical Forwarder", | ||
@@ -25,10 +25,9 @@ "keywords": [ | ||
"dependencies": { | ||
"@ndn/packet": "0.0.20240630", | ||
"@ndn/util": "0.0.20240630", | ||
"@ndn/packet": "0.0.20250122", | ||
"@ndn/util": "0.0.20250122", | ||
"@types/retry": "^0.12.5", | ||
"hirestime": "^7.0.4", | ||
"mnemonist": "^0.39.8", | ||
"obliterator": "^2.0.5", | ||
"retry": "^0.13.1", | ||
"streaming-iterables": "^8.0.1", | ||
"tslib": "^2.6.3", | ||
"tslib": "^2.8.1", | ||
"typescript-event-target": "^1.1.1" | ||
@@ -35,0 +34,0 @@ }, |
Sorry, the diff of this file is not supported yet
91844
8
2516
+ Addedobliterator@^2.0.5
+ Added@ndn/packet@0.0.20250122(transitive)
+ Added@ndn/tlv@0.0.20250122(transitive)
+ Added@ndn/util@0.0.20250122(transitive)
+ Added@ungap/with-resolvers@0.1.0(transitive)
- Removedhirestime@^7.0.4
- Removedmnemonist@^0.39.8
- Removed@ndn/packet@0.0.20240630(transitive)
- Removed@ndn/tlv@0.0.20240630(transitive)
- Removed@ndn/util@0.0.20240630(transitive)
- Removedhirestime@7.0.4(transitive)
- Removedmnemonist@0.39.8(transitive)
Updated@ndn/packet@0.0.20250122
Updated@ndn/util@0.0.20250122
Updatedtslib@^2.8.1