refactor(frontend/player):player lists

This commit is contained in:
Alex Kaminskii 2022-11-18 16:52:38 +01:00
parent a111dc95e9
commit f31ae3efa0
4 changed files with 158 additions and 63 deletions

View file

@ -1,23 +1,76 @@
import type { Message } from './messages'
import ListWalker from './managers/ListWalker';
import ListWalkerWithMarks from './managers/ListWalkerWithMarks';
export const LIST_NAMES = ["redux", "mobx", "vuex", "zustand", "ngrx", "graphql", "exceptions", "profiles"] as const;
import type { Message } from './messages'
export const INITIAL_STATE = {}
LIST_NAMES.forEach(name => {
INITIAL_STATE[`${name}ListNow`] = []
INITIAL_STATE[`${name}List`] = []
})
const SIMPLE_LIST_NAMES = [ "event", "redux", "mobx", "vuex", "zustand", "ngrx", "graphql", "exceptions", "profiles"] as const;
const MARKED_LIST_NAMES = [ "log", "resource", "fetch", "stack" ] as const;
//const entityNamesSimple = [ "event", "profile" ];
const LIST_NAMES = [...SIMPLE_LIST_NAMES, ...MARKED_LIST_NAMES ];
type ListsObject = {
[key in typeof LIST_NAMES[number]]: ListWalker<any>
}
// TODO: provide correct types
export function initLists(): ListsObject {
const lists: Partial<ListsObject> = {};
for (var i = 0; i < LIST_NAMES.length; i++) {
lists[LIST_NAMES[i]] = new ListWalker();
export const INITIAL_STATE = LIST_NAMES.reduce((state, name) => {
state[`${name}List`] = []
state[`${name}ListNow`] = []
if (MARKED_LIST_NAMES.includes(name)) {
state[`${name}MarkedCountNow`] = 0
state[`${name}MarkedCount`] = 0
}
return lists as ListsObject;
return state
}, {})
type SimpleListsObject = {
[key in typeof SIMPLE_LIST_NAMES[number]]: ListWalker<any>
}
type MarkedListsObject = {
[key in typeof MARKED_LIST_NAMES[number]]: ListWalkerWithMarks<any>
}
type ListsObject = SimpleListsObject & MarkedListsObject
type InitialLists = {
[key in typeof LIST_NAMES[number]]: any[]
}
export default class Lists {
lists: ListsObject
constructor(initialLists: Partial<InitialLists> = {}) {
const lists: Partial<ListsObject> = {}
for (const name of SIMPLE_LIST_NAMES) {
lists[name] = new ListWalker(initialLists[name])
}
for (const name of MARKED_LIST_NAMES) {
// TODO: provide types
lists[name] = new ListWalkerWithMarks((el) => el.isRed(), initialLists[name])
}
this.lists = lists as ListsObject
}
getFullListsState() {
return LIST_NAMES.reduce((state, name) => {
state[`${name}List`] = this.lists[name].list
return state
}, MARKED_LIST_NAMES.reduce((state, name) => {
state[`${name}MarkedCount`] = this.lists[name].markedCount
return state
}, {})
)
}
moveGetState(t: number)/* : Partial<State> */ {
return LIST_NAMES.reduce((state, name) => {
const lastMsg = this.lists[name].moveGetLast(t) // index: name === 'exceptions' ? undefined : index);
if (lastMsg != null) {
state[`${name}ListNow`] = this.lists[name].listNow
}
return state
}, MARKED_LIST_NAMES.reduce((state, name) => {
state[`${name}MarkedCountNow`] = this.lists[name].markedCountNow
return state
}, {})
);
}
}

View file

@ -9,12 +9,6 @@ import Log from 'Types/session/log';
import { update } from '../store';
import { toast } from 'react-toastify';
import {
init as initListsDepr,
append as listAppend,
setStartTime as setListsStartTime
} from '../lists';
import StatedScreen from './StatedScreen/StatedScreen';
import ListWalker from './managers/ListWalker';
@ -32,7 +26,7 @@ import { decryptSessionBytes } from './network/crypto';
import { INITIAL_STATE as SUPER_INITIAL_STATE, State as SuperState } from './StatedScreen/StatedScreen';
import { INITIAL_STATE as ASSIST_INITIAL_STATE, State as AssistState } from './managers/AssistManager';
import { INITIAL_STATE as LISTS_INITIAL_STATE , LIST_NAMES, initLists } from './Lists';
import Lists, { INITIAL_STATE as LISTS_INITIAL_STATE } from './Lists';
import type { PerformanceChartPoint } from './managers/PerformanceTrackManager';
import type { SkipInterval } from './managers/ActivityManager';
@ -100,7 +94,7 @@ export default class MessageDistributor extends StatedScreen {
private scrollManager: ListWalker<SetViewportScroll> = new ListWalker();
private readonly decoder = new Decoder();
private readonly lists = initLists();
private readonly lists: Lists;
private activityManager: ActivityManager | null = null;
@ -118,28 +112,27 @@ export default class MessageDistributor extends StatedScreen {
this.sessionStart = this.session.startedAt;
if (live) {
initListsDepr({})
this.lists = new Lists()
this.assistManager.connect(this.session.agentToken);
} else {
this.activityManager = new ActivityManager(this.session.duration.milliseconds);
/* == REFACTOR_ME == */
const eventList = this.session.events.toJSON();
initListsDepr({
event: eventList,
stack: this.session.stackEvents.toJSON(),
resource: this.session.resources.toJSON(),
});
const eventList = session.events.toJSON();
// TODO: fix types for events, remove immutable js
eventList.forEach((e: Record<string, string>) => {
if (e.type === EVENT_TYPES.LOCATION) { //TODO type system
this.locationEventManager.append(e);
}
});
this.session.errors.forEach((e: Record<string, string>) => {
this.lists.exceptions.append(e);
});
})
this.lists = new Lists({
event: eventList,
stack: session.stackEvents.toJSON(),
resource: session.resources.toJSON(),
exceptions: session.errors.toJSON(),
})
/* === */
this.loadMessages();
}
@ -187,13 +180,11 @@ export default class MessageDistributor extends StatedScreen {
private waitingForFiles: boolean = false
private onFileReadSuccess = () => {
const stateToUpdate: {[key:string]: any} = {
const stateToUpdate = {
performanceChartData: this.performanceTrackManager.chartData,
performanceAvaliability: this.performanceTrackManager.avaliability,
...this.lists.getFullListsState()
}
LIST_NAMES.forEach(key => {
stateToUpdate[ `${ key }List` ] = this.lists[ key ].list
})
if (this.activityManager) {
this.activityManager.end()
stateToUpdate.skipIntervals = this.activityManager.list
@ -304,7 +295,6 @@ export default class MessageDistributor extends StatedScreen {
/* == REFACTOR_ME == */
const lastLoadedLocationMsg = this.loadedLocationManager.moveGetLast(t, index);
if (!!lastLoadedLocationMsg) {
setListsStartTime(lastLoadedLocationMsg.time)
this.navigationStartOffset = lastLoadedLocationMsg.navigationStart - this.sessionStart;
}
const llEvent = this.locationEventManager.moveGetLast(t, index);
@ -340,14 +330,7 @@ export default class MessageDistributor extends StatedScreen {
stateToUpdate.performanceChartTime = lastPerformanceTrackMessage.time;
}
LIST_NAMES.forEach(key => {
const lastMsg = this.lists[key].moveGetLast(t, key === 'exceptions' ? undefined : index);
if (lastMsg != null) {
// @ts-ignore TODO: fix types
stateToUpdate[`${key}ListNow`] = this.lists[key].listNow;
}
});
Object.assign(stateToUpdate, this.lists.moveGetState(t))
Object.keys(stateToUpdate).length > 0 && update(stateToUpdate);
/* Sequence of the managers is important here */
@ -414,15 +397,15 @@ export default class MessageDistributor extends StatedScreen {
/* Lists: */
case "console_log":
if (msg.level === 'debug') break;
listAppend("log", Log({
this.lists.lists.log.append(Log({
level: msg.level,
value: msg.value,
time,
index,
}));
}))
break;
case "fetch":
listAppend("fetch", Resource({
this.lists.lists.fetch.append(Resource({
method: msg.method,
url: msg.url,
payload: msg.request,
@ -469,42 +452,42 @@ export default class MessageDistributor extends StatedScreen {
decoded = this.decodeStateMessage(msg, ["state", "action"]);
logger.log('redux', decoded)
if (decoded != null) {
this.lists.redux.append(decoded);
this.lists.lists.redux.append(decoded);
}
break;
case "ng_rx":
decoded = this.decodeStateMessage(msg, ["state", "action"]);
logger.log('ngrx', decoded)
if (decoded != null) {
this.lists.ngrx.append(decoded);
this.lists.lists.ngrx.append(decoded);
}
break;
case "vuex":
decoded = this.decodeStateMessage(msg, ["state", "mutation"]);
logger.log('vuex', decoded)
if (decoded != null) {
this.lists.vuex.append(decoded);
this.lists.lists.vuex.append(decoded);
}
break;
case "zustand":
decoded = this.decodeStateMessage(msg, ["state", "mutation"])
logger.log('zustand', decoded)
if (decoded != null) {
this.lists.zustand.append(decoded)
this.lists.lists.zustand.append(decoded)
}
case "mob_x":
decoded = this.decodeStateMessage(msg, ["payload"]);
logger.log('mobx', decoded)
if (decoded != null) {
this.lists.mobx.append(decoded);
this.lists.lists.mobx.append(decoded);
}
break;
case "graph_ql":
this.lists.graphql.append(msg);
this.lists.lists.graphql.append(msg);
break;
case "profiler":
this.lists.profiles.append(msg);
this.lists.lists.profiles.append(msg);
break;
default:
switch (msg.tp) {

View file

@ -79,6 +79,23 @@ export default class ListWalker<T extends Timed> {
return this.p;
}
private hasNext() {
return this.p < this.length
}
private hasPrev() {
return this.p > 0
}
protected moveNext(): T | null {
return this.hasNext()
? this.list[ this.p++ ]
: null
}
protected movePrev(): T | null {
return this.hasPrev()
? this.list[ --this.p ]
: null
}
/*
Returns last message with the time <= t.
Assumed that the current message is already handled so
@ -94,11 +111,11 @@ export default class ListWalker<T extends Timed> {
let changed = false;
while (this.p < this.length && this.list[this.p][key] <= val) {
this.p++;
this.moveNext()
changed = true;
}
while (this.p > 0 && this.list[ this.p - 1 ][key] > val) {
this.p--;
this.movePrev()
changed = true;
}
return changed ? this.list[ this.p - 1 ] : null;
@ -112,10 +129,10 @@ export default class ListWalker<T extends Timed> {
const list = this.list
while (list[this.p] && list[this.p].time <= t) {
fn(list[ this.p++ ]);
fn(this.moveNext())
}
while (fnBack && this.p > 0 && list[ this.p - 1 ].time > t) {
fnBack(list[ --this.p ]);
fnBack(this.movePrev());
}
}

View file

@ -0,0 +1,42 @@
import type { Timed } from '../messages/timed';
import ListWalker from './ListWalker'
type CheckFn<T> = (t: T) => boolean
export default class ListWalkerWithMarks<T extends Timed> extends ListWalker<T> {
private _markCountNow: number = 0
private _markCount: number = 0
constructor(private isMarked: CheckFn<T>, initialList: T[] = []) {
super(initialList)
this._markCount = initialList.reduce((n, item) => isMarked(item) ? n+1 : n, 0)
}
append(item: T) {
if (this.isMarked(item)) { this._markCount++ }
super.append(item)
}
protected moveNext() {
const val = super.moveNext()
if (val && this.isMarked(val)) {
this._markCountNow++
}
return val
}
protected movePrev() {
const val = super.movePrev()
if (val && this.isMarked(val)) {
this._markCountNow--
}
return val
}
get markedCountNow(): number {
return this._markCountNow
}
get markedCount(): number {
return this._markCount
}
}