change(ui): tracker beta v, improvements for assets loading after click on timeline (player.jump)

This commit is contained in:
nick-delirium 2023-03-21 15:59:06 +01:00
parent 6742435bc9
commit a128060248
8 changed files with 82 additions and 31 deletions

View file

@ -66,7 +66,7 @@ function WebPlayer(props: any) {
React.useEffect(() => {
if (session.events.length > 0 || session.errors.length > 0) {
contextValue.player.updateLists(session)
contextValue.player?.updateLists?.(session)
}
}, [session.events, session.errors])

View file

@ -7,7 +7,7 @@ export interface Indexed {
}
export interface Moveable {
move(time: number): void
move(time: number, isJump?: boolean): void
}
export interface Cleanable {

View file

@ -60,12 +60,12 @@ export default class Animator {
window.playerJump = this.jump.bind(this)
}
private setTime(time: number) {
private setTime(time: number, isJump?: boolean) {
this.store.update({
time,
completed: false,
})
this.mm.move(time)
this.mm.move(time, isJump)
}
private startAnimation() {
@ -183,11 +183,11 @@ export default class Animator {
jump = (time: number) => {
if (this.store.get().playing) {
cancelAnimationFrame(this.animationFrameRequestId)
this.setTime(time)
this.setTime(time, true)
this.startAnimation()
this.store.update({ livePlay: time === this.store.get().endTime })
} else {
this.setTime(time)
this.setTime(time, true)
this.store.update({ livePlay: time === this.store.get().endTime })
}
}

View file

@ -228,7 +228,7 @@ export default class MessageManager {
sorted.forEach(msg => {
if (indx > msg._index) outOfOrderCounter++
else indx = msg._index
this.distributeMessage(msg, msg._index)
this.distributeMessage(msg)
})
if (outOfOrderCounter > 0) console.warn("Unsorted mob file, error count: ", outOfOrderCounter)
@ -287,7 +287,7 @@ export default class MessageManager {
this.activityManager = new ActivityManager(this.session.duration.milliseconds);
}
move(t: number, index?: number): void {
move(t: number, isJump?: boolean, index?: number): void {
const stateToUpdate: Partial<State> = {};
/* == REFACTOR_ME == */
const lastLoadedLocationMsg = this.loadedLocationManager.moveGetLast(t, index);
@ -337,7 +337,7 @@ export default class MessageManager {
if (!!lastResize) {
this.setSize(lastResize)
}
this.pagesManager.moveReady(t).then(() => {
this.pagesManager.moveReady(t, isJump).then(() => {
const lastScroll = this.scrollManager.moveGetLast(t, index);
if (!!lastScroll && this.screen.window) {
@ -374,7 +374,7 @@ export default class MessageManager {
return { ...msg, ...decoded };
}
distributeMessage(msg: Message, index: number): void {
distributeMessage(msg: Message): void {
const lastMessageTime = Math.max(msg.time, this.lastMessageTime)
this.lastMessageTime = lastMessageTime
this.state.update({ lastMessageTime })

View file

@ -43,7 +43,7 @@ export default class DOMManager extends ListWalker<Message> {
private styleSheets: Map<number, CSSStyleSheet> = new Map()
private ppStyleSheets: Map<number, PostponedStyleSheet> = new Map()
private stringDict: Record<number,string> = {}
private attrsBacktrack: Message[] = []
private upperBodyId: number = -1;
private nodeScrollManagers: Map<number, ListWalker<SetNodeScroll>> = new Map()
@ -143,6 +143,7 @@ export default class DOMManager extends ListWalker<Message> {
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
@ -152,9 +153,13 @@ export default class DOMManager extends ListWalker<Message> {
// 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.
if (!value.startsWith("http")) {
return
}
// blob:... value can happen here for some reason.
// which will result in that link being unable to load and having 4sec timeout in the below function.
// TODO: check if node actually exists on the page, not just in memory
this.stylesManager.setStyleHandlers(vn.node as HTMLLinkElement, value);
}
if (vn.node.namespaceURI === 'http://www.w3.org/2000/svg' && value.startsWith("url(")) {
@ -164,8 +169,7 @@ export default class DOMManager extends ListWalker<Message> {
this.removeBodyScroll(msg.id, vn)
}
private applyMessage = (msg: Message): Promise<any> | undefined => {
let node: Node | undefined
private applyMessage = (msg: Message, isJump?: boolean): Promise<any> | undefined => {
let vn: VNode | undefined
let doc: Document | null
let styleSheet: CSSStyleSheet | PostponedStyleSheet | undefined
@ -229,9 +233,12 @@ export default class DOMManager extends ListWalker<Message> {
if (!vn) { logger.error("Node not found", msg); return }
if (!vn.parentNode) { logger.error("Parent node not found", msg); return }
vn.parentNode.removeChild(vn)
this.vElements.delete(msg.id)
this.vTexts.delete(msg.id)
return
case MType.SetNodeAttribute:
this.setNodeAttribute(msg)
if (isJump && msg.name === 'href') this.attrsBacktrack.push(msg)
else this.setNodeAttribute(msg)
return
case MType.StringDict:
this.stringDict[msg.key] = msg.value
@ -240,11 +247,14 @@ export default class DOMManager extends ListWalker<Message> {
this.stringDict[msg.nameKey] === undefined && logger.error("No dictionary key for msg 'name': ", msg)
this.stringDict[msg.valueKey] === undefined && logger.error("No dictionary key for msg 'value': ", msg)
if (this.stringDict[msg.nameKey] === undefined || this.stringDict[msg.valueKey] === undefined ) { return }
this.setNodeAttribute({
id: msg.id,
name: this.stringDict[msg.nameKey],
value: this.stringDict[msg.valueKey],
})
if (isJump && this.stringDict[msg.nameKey] === 'href') this.attrsBacktrack.push(msg)
else {
this.setNodeAttribute({
id: msg.id,
name: this.stringDict[msg.nameKey],
value: this.stringDict[msg.valueKey],
})
}
return
case MType.RemoveNodeAttribute:
vn = this.vElements.get(msg.id)
@ -422,13 +432,53 @@ export default class DOMManager extends ListWalker<Message> {
}
}
async moveReady(t: number): Promise<void> {
applyBacktrack(msg: Message) {
// @ts-ignore
const target = this.vElements.get(msg.id)
if (!target) {
return
}
switch (msg.tp) {
case MType.SetNodeAttribute: {
this.setNodeAttribute(msg)
return
}
case MType.SetNodeAttributeDict: {
this.stringDict[msg.nameKey] === undefined && logger.error("No dictionary key for msg 'name': ", msg)
this.stringDict[msg.valueKey] === undefined && logger.error("No dictionary key for msg 'value': ", msg)
if (this.stringDict[msg.nameKey] === undefined || this.stringDict[msg.valueKey] === undefined) {
return
}
this.setNodeAttribute({
id: msg.id,
name: this.stringDict[msg.nameKey],
value: this.stringDict[msg.valueKey],
})
return;
}
}
}
async moveReady(t: number, isJump?: boolean): Promise<void> {
// MBTODO (back jump optimisation):
// - store intemediate virtual dom state
// - cancel previous moveReady tasks (is it possible?) if new timestamp is less
// This function autoresets pointer if necessary (better name?)
await this.moveWait(t, this.applyMessage)
/**
* Basically just skipping all set attribute with attrs being "href" if user is 'jumping'
* to the other point of replay to save time on NOT downloading any resources before the dom tree changes
* are applied, so it won't try to download and then cancel when node is created in msg N and removed in msg N+2
* which produces weird bug when asset is cached (10-25ms delay)
* */
await this.moveWait(t, (msg) => this.applyMessage(msg, isJump))
if (isJump) {
this.attrsBacktrack.forEach(msg => {
this.applyBacktrack(msg)
})
this.attrsBacktrack = []
}
this.vRoots.forEach(rt => rt.applyChanges()) // MBTODO (optimisation): affected set
// Thinkabout (read): css preload

View file

@ -108,8 +108,8 @@ export class VElement extends VParent {
} else {
try {
this.node.setAttribute(key, value)
} catch {
// log err
} catch (e) {
console.error(e)
}
}
})
@ -134,7 +134,8 @@ export class VStyleElement extends VElement {
this.stylesheetCallbacks.forEach(cb => cb(sheet))
this.stylesheetCallbacks = []
} else {
console.warn("Style onload: sheet is null")
// console.warn("Style onload: sheet is null") ?
// sometimes logs shit ton of errors for some reason
}
this.loaded = true
}

View file

@ -33,14 +33,14 @@ export default class PagesManager extends ListWalker<DOMManager> {
this.forEach(page => page.sort(comparator))
}
moveReady(t: number): Promise<void> {
moveReady(t: number, isJump?: boolean): Promise<void> {
const requiredPage = this.moveGetLast(t)
if (requiredPage != null) {
this.currentPage = requiredPage
this.currentPage.reset() // Otherwise it won't apply create_document
}
if (this.currentPage != null) {
return this.currentPage.moveReady(t)
return this.currentPage.moveReady(t, isJump)
}
return Promise.resolve()
}

View file

@ -1,7 +1,7 @@
{
"name": "@openreplay/tracker",
"description": "The OpenReplay tracker main package",
"version": "5.0.1",
"version": "5.0.2-beta.2",
"keywords": [
"logging",
"replay"