add node deletion to maintainer

This commit is contained in:
Андрей Бабушкин 2025-04-17 14:55:18 +02:00
parent 93e0ff3635
commit d22fcb3a2d
5 changed files with 28 additions and 14 deletions

View file

@ -279,6 +279,7 @@ export default class App {
this.nodes.unregisterNodeById(id)
this.send(RemoveNode(id))
})
private readonly iframes: Map<number, HTMLIFrameElement> = new Map();
constructor(
projectKey: string,
@ -367,8 +368,10 @@ export default class App {
node_id: this.options.node_id,
forceNgOff: Boolean(options.forceNgOff),
maintainer: this.options.nodes?.maintainer,
vTree: this.vTree,
iframes: this.iframes,
})
this.observer = new Observer({ app: this, options, vTree: this.vTree })
this.observer = new Observer({ app: this, options }, this.vTree, this.iframes)
this.ticker = new Ticker(this)
this.ticker.attach(() => this.commit())
this.debug = new Logger(this.options.__debug__)

View file

@ -1,4 +1,5 @@
import { createEventListener, deleteEventListener } from '../../utils.js'
import VirtualNodeTree from '../observer/vTree.js'
import Maintainer, { MaintainerOptions } from './maintainer.js'
type NodeCallback = (node: Node, isStart: boolean) => void
@ -8,6 +9,8 @@ export interface NodesOptions {
node_id: string
forceNgOff: boolean
maintainer?: Partial<MaintainerOptions>
vTree: VirtualNodeTree
iframes: Map<number, HTMLIFrameElement>
}
export default class Nodes {
@ -23,7 +26,7 @@ export default class Nodes {
constructor(params: NodesOptions) {
this.node_id = params.node_id
this.forceNgOff = params.forceNgOff
this.maintainer = new Maintainer(this.nodes, this.unregisterNode, params.maintainer)
this.maintainer = new Maintainer(this.nodes, this.unregisterNode, params.vTree, params.iframes, params.maintainer)
this.maintainer.start()
}

View file

@ -1,9 +1,11 @@
import VirtualNodeTree from "../observer/vTree"
const SECOND = 1000
function processMapInBatches(
map: Map<number, Node | void>,
batchSize: number,
processBatchCallback: (node: Node) => void,
processBatchCallback: (node: Node, nodeId: number) => void,
) {
const iterator = map.entries()
@ -17,9 +19,9 @@ function processMapInBatches(
}
if (batch.length > 0) {
batch.forEach(([_, node]) => {
batch.forEach(([nodeId, node]) => {
if (node) {
processBatchCallback(node)
processBatchCallback(node, nodeId)
}
})
@ -87,12 +89,18 @@ const defaults = {
class Maintainer {
private interval: ReturnType<typeof setInterval>
private readonly options: MaintainerOptions
private readonly vTree: VirtualNodeTree
private readonly iframes: Map<number, HTMLIFrameElement>
constructor(
private readonly nodes: Map<number, Node | void>,
private readonly unregisterNode: (node: Node) => void,
vTree: VirtualNodeTree,
iframes: Map<number, HTMLIFrameElement>,
options?: Partial<MaintainerOptions>,
) {
this.options = { ...defaults, ...options }
this.vTree = vTree
this.iframes = iframes
}
public start = () => {
@ -103,10 +111,12 @@ class Maintainer {
this.stop()
this.interval = setInterval(() => {
processMapInBatches(this.nodes, this.options.batchSize, (node) => {
processMapInBatches(this.nodes, this.options.batchSize, (node, nodeId) => {
const isActive = isNodeStillActive(node)[0]
if (!isActive) {
this.unregisterNode(node)
this.vTree?.removeNode(nodeId)
this.iframes.delete(nodeId)
}
})
}, this.options.interval)

View file

@ -184,10 +184,6 @@ enum RecentsType {
export default abstract class Observer {
/** object tree where key is node id, value is null if it has no children, or object with same structure */
// private readonly vTree = new vElTree((id: number) => {
// this.app.nodes.unregisterNodeById(id)
// this.app.send(RemoveNode(id))
// })
private readonly observer: MutationObserver
private readonly commited: Array<boolean | undefined> = []
private readonly recents: Map<number, RecentsType> = new Map()

View file

@ -8,6 +8,7 @@ import IFrameOffsets, { Offset } from './iframe_offsets.js'
import { CreateDocument } from '../messages.gen.js'
import App from '../index.js'
import { IN_BROWSER, hasOpenreplayAttribute, canAccessIframe } from '../../utils.js'
import VirtualNodeTree from './vTree.js'
export interface Options {
captureIFrames: boolean
@ -22,10 +23,10 @@ const attachShadowNativeFn = IN_BROWSER ? Element.prototype.attachShadow : () =>
export default class TopObserver extends Observer {
private readonly options: Options
private readonly iframeOffsets: IFrameOffsets = new IFrameOffsets()
private readonly iframes: Map<number, HTMLIFrameElement>
readonly app: App
public iframes: Map<number, HTMLIFrameElement> = new Map()
constructor(params: { app: App; options: Partial<Options>; vTree: any }) {
constructor(params: { app: App; options: Partial<Options> }, vTree: VirtualNodeTree, iframes: Map<number, HTMLIFrameElement>) {
const opts = Object.assign(
{
captureIFrames: true,
@ -33,10 +34,11 @@ export default class TopObserver extends Observer {
},
params.options,
)
super(params.app, true, opts, params.vTree)
super(params.app, true, opts, vTree)
this.app = params.app
this.options = opts
this.vTree = params.vTree
this.vTree = vTree
this.iframes = iframes
// IFrames
this.app.nodes.attachNodeCallback((node) => {
const nodeId = this.app.nodes.getID(node);