feat(tracker;player): use string dectionaries for attributes
This commit is contained in:
parent
faefe14ac5
commit
8fe01ac46e
3 changed files with 73 additions and 23 deletions
|
|
@ -43,6 +43,7 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
private activeIframeRoots: Map<number, number> = new Map()
|
||||
private styleSheets: Map<number, CSSStyleSheet> = new Map()
|
||||
private ppStyleSheets: Map<number, PostponedStyleSheet> = new Map()
|
||||
private stringDict: Record<string,string> = {}
|
||||
|
||||
|
||||
private upperBodyId: number = -1;
|
||||
|
|
@ -134,6 +135,31 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
parent.insertChildAt(child, index)
|
||||
}
|
||||
|
||||
private setNodeAttribute(msg: { id: number, name: string, value: string }) {
|
||||
let { name, value } = msg;
|
||||
const vn = this.vElements.get(msg.id)
|
||||
if (!vn) { logger.error("Node not found", msg); return }
|
||||
if (vn.node.tagName === "INPUT" && name === "name") {
|
||||
// Otherwise binds local autocomplete values (maybe should ignore on the tracker level)
|
||||
return
|
||||
}
|
||||
if (name === "href" && vn.node.tagName === "LINK") {
|
||||
// @ts-ignore ?global ENV type // It've been done on backend (remove after testing in saas)
|
||||
// if (value.startsWith(window.env.ASSETS_HOST || window.location.origin + '/assets')) {
|
||||
// value = value.replace("?", "%3F");
|
||||
// }
|
||||
if (!value.startsWith("http")) { return }
|
||||
// blob:... value happened here. https://foss.openreplay.com/3/session/7013553567419137
|
||||
// that resulted in that link being unable to load and having 4sec timeout in the below function.
|
||||
this.stylesManager.setStyleHandlers(vn.node as HTMLLinkElement, value);
|
||||
}
|
||||
if (vn.node.namespaceURI === 'http://www.w3.org/2000/svg' && value.startsWith("url(")) {
|
||||
value = "url(#" + (value.split("#")[1] ||")")
|
||||
}
|
||||
vn.setAttribute(name, value)
|
||||
this.removeBodyScroll(msg.id, vn)
|
||||
}
|
||||
|
||||
private applyMessage = (msg: Message): Promise<any> | undefined => {
|
||||
let node: Node | undefined
|
||||
let vn: VNode | undefined
|
||||
|
|
@ -160,10 +186,11 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
this.vRoots.clear()
|
||||
this.vRoots.set(0, vDoc) // watchout: id==0 for both Document and documentElement
|
||||
// this is done for the AdoptedCSS logic
|
||||
// todo: start from 0 (sync logic with tracker)
|
||||
// todo: start from 0-node (sync logic with tracker)
|
||||
this.vTexts.clear()
|
||||
this.stylesManager.reset()
|
||||
this.activeIframeRoots.clear()
|
||||
this.stringDict = {}
|
||||
return
|
||||
case MType.CreateTextNode:
|
||||
vn = new VText()
|
||||
|
|
@ -200,28 +227,20 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
vn.parentNode.removeChild(vn)
|
||||
return
|
||||
case MType.SetNodeAttribute:
|
||||
let { name, value } = msg;
|
||||
vn = this.vElements.get(msg.id)
|
||||
if (!vn) { logger.error("Node not found", msg); return }
|
||||
if (vn.node.tagName === "INPUT" && name === "name") {
|
||||
// Otherwise binds local autocomplete values (maybe should ignore on the tracker level)
|
||||
return
|
||||
}
|
||||
if (name === "href" && vn.node.tagName === "LINK") {
|
||||
// @ts-ignore ?global ENV type // It've been done on backend (remove after testing in saas)
|
||||
// if (value.startsWith(window.env.ASSETS_HOST || window.location.origin + '/assets')) {
|
||||
// value = value.replace("?", "%3F");
|
||||
// }
|
||||
if (!value.startsWith("http")) { return }
|
||||
// blob:... value happened here. https://foss.openreplay.com/3/session/7013553567419137
|
||||
// that resulted in that link being unable to load and having 4sec timeout in the below function.
|
||||
this.stylesManager.setStyleHandlers(vn.node as HTMLLinkElement, value);
|
||||
}
|
||||
if (vn.node.namespaceURI === 'http://www.w3.org/2000/svg' && value.startsWith("url(")) {
|
||||
value = "url(#" + (value.split("#")[1] ||")")
|
||||
}
|
||||
vn.setAttribute(name, value)
|
||||
this.removeBodyScroll(msg.id, vn)
|
||||
this.setNodeAttribute(msg)
|
||||
return
|
||||
case MType.StringDict:
|
||||
this.stringDict[msg.key] = msg.value
|
||||
return
|
||||
case MType.SetNodeAttributeDict:
|
||||
this.stringDict[msg.name] === undefined && logger.error("No dictionary key for msg 'name': ", msg)
|
||||
this.stringDict[msg.value] === undefined && logger.error("No dictionary key for msg 'value': ", msg)
|
||||
if (!this.stringDict[msg.name] || !this.stringDict[msg.value]) { return }
|
||||
this.setNodeAttribute({
|
||||
id: msg.id,
|
||||
name: this.stringDict[msg.name],
|
||||
value: this.stringDict[msg.value],
|
||||
})
|
||||
return
|
||||
case MType.RemoveNodeAttribute:
|
||||
vn = this.vElements.get(msg.id)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type Message from '../common/messages.gen.js'
|
||||
import * as Messages from '../common/messages.gen.js'
|
||||
import MessageEncoder from './MessageEncoder.gen.js'
|
||||
import StringDictionary from './StringDictionary.js'
|
||||
|
||||
const SIZE_BYTES = 3
|
||||
const MAX_M_SIZE = (1 << (SIZE_BYTES * 8)) - 1
|
||||
|
|
@ -9,6 +10,7 @@ export default class BatchWriter {
|
|||
private nextIndex = 0
|
||||
private beaconSize = 2 * 1e5 // Default 200kB
|
||||
private encoder = new MessageEncoder(this.beaconSize)
|
||||
private strDict = new StringDictionary()
|
||||
private readonly sizeBuffer = new Uint8Array(SIZE_BYTES)
|
||||
private isEmpty = true
|
||||
|
||||
|
|
@ -84,6 +86,14 @@ export default class BatchWriter {
|
|||
this.beaconSizeLimit = limit
|
||||
}
|
||||
|
||||
private applyDict(str: string): string {
|
||||
const [key, isNew] = this.strDict.getKey(str)
|
||||
if (isNew) {
|
||||
this.writeMessage([Messages.Type.StringDict, key, str])
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
writeMessage(message: Message) {
|
||||
if (message[0] === Messages.Type.Timestamp) {
|
||||
this.timestamp = message[1] // .timestamp
|
||||
|
|
@ -91,6 +101,14 @@ export default class BatchWriter {
|
|||
if (message[0] === Messages.Type.SetPageLocation) {
|
||||
this.url = message[1] // .url
|
||||
}
|
||||
if (message[0] === Messages.Type.SetNodeAttribute) {
|
||||
message = [
|
||||
Messages.Type.SetNodeAttributeDict,
|
||||
message[1],
|
||||
this.applyDict(message[2]),
|
||||
this.applyDict(message[3]),
|
||||
] as Messages.SetNodeAttributeDict
|
||||
}
|
||||
if (this.writeWithSize(message)) {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
13
tracker/tracker/src/webworker/StringDictionary.ts
Normal file
13
tracker/tracker/src/webworker/StringDictionary.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export default class StringDictionary {
|
||||
private idx = 0
|
||||
private backDict: Record<string, string> = {}
|
||||
|
||||
getKey(str: string): [string, boolean] {
|
||||
let isNew = false
|
||||
if (!this.backDict[str]) {
|
||||
isNew = true
|
||||
this.backDict[str] = `${this.idx++}`
|
||||
}
|
||||
return [this.backDict[str], isNew]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue