wip (frontent): assist call functionality
This commit is contained in:
parent
13aaa642d3
commit
3190924c1d
28 changed files with 1362 additions and 1236 deletions
|
|
@ -1,14 +1,49 @@
|
|||
import React from 'react'
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import {
|
||||
PlayerProvider,
|
||||
attach as attachPlayer,
|
||||
init as initPlayer,
|
||||
clean as cleanPlayer,
|
||||
callPeer,
|
||||
// scale
|
||||
} from 'App/player';
|
||||
import ChatWindow from './ChatWindow/ChatWindow'
|
||||
import ScreenSharing from './ScreenSharing/ScreenSharing'
|
||||
//import ScreenSharing from './ScreenSharing/ScreenSharing'
|
||||
|
||||
function Assist() {
|
||||
function Assist({ session, jwt }) {
|
||||
const screeRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
initPlayer(session, jwt);
|
||||
return () => cleanPlayer()
|
||||
}, [ session.sessionId ]);
|
||||
useEffect(() => {
|
||||
if (screeRef.current) {
|
||||
attachPlayer(findDOMNode(screeRef.current));
|
||||
|
||||
}
|
||||
}, [ ])
|
||||
return (
|
||||
<div>
|
||||
<ChatWindow />
|
||||
<div className="h-screen w-screen">
|
||||
<div ref={screeRef}
|
||||
// Just for testing TODO: flexible layout.
|
||||
// It should consider itself as empty but take maximum of the space available
|
||||
// Screen will adapt automatically.
|
||||
style={{margin: "100px", height: "300px", width:"600px" }}
|
||||
className="relative overflow-hidden bg-gray-lightest"
|
||||
/>
|
||||
<ChatWindow call={ callPeer } />
|
||||
{/* <ScreenSharing /> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Assist
|
||||
export default connect(state => ({
|
||||
session: { // Testing mock. Should be retrieved from redux
|
||||
startedAt: 1624314191394,
|
||||
live: true,
|
||||
sessionId: "4870254843916045",
|
||||
},
|
||||
jwt: state.get('jwt'),
|
||||
}))(Assist);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,35 @@
|
|||
import React from 'react'
|
||||
import VideoContainer from '../components/VideoContainer/VideoContainer'
|
||||
import React, { useState } from 'react';
|
||||
import { IconButton } from 'UI';
|
||||
import VideoContainer from '../components/VideoContainer';
|
||||
// import stl from './chatWindow.css';
|
||||
|
||||
function ChatWindow() {
|
||||
|
||||
interface Props {
|
||||
call: (oStream: MediaStream, cb: (iStream: MediaStream)=>void)=>void
|
||||
}
|
||||
|
||||
function ChatWindow({ call }: Props) {
|
||||
const [ inputStream, setInputStream ] = useState<MediaStream | null>(null);
|
||||
const [ outputStream, setOutputStream ] = useState<MediaStream | null>(null);
|
||||
|
||||
const onCallClick = () => {
|
||||
navigator.mediaDevices.getUserMedia({video:true, audio:true})
|
||||
.then(oStream => {
|
||||
setOutputStream(oStream);
|
||||
call(oStream, setInputStream); // Returns false when unable to connect.
|
||||
// TODO: handle calling state
|
||||
})
|
||||
.catch(console.log) // TODO: handle error in ui
|
||||
}
|
||||
return (
|
||||
<div className="fixed border radius bg-white z-50 shadow-xl mt-16">
|
||||
<div className="p-2">
|
||||
<VideoContainer />
|
||||
<VideoContainer stream={ inputStream } />
|
||||
<div className="py-1" />
|
||||
<VideoContainer />
|
||||
<VideoContainer stream={ outputStream } muted/>
|
||||
<div className="cursor-pointer p-2 mr-2">
|
||||
<IconButton icon="telephone" size="20" onClick={ onCallClick }/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ import React from 'react'
|
|||
import { Button } from 'UI'
|
||||
|
||||
function ScreenSharing() {
|
||||
const videoRef: React.RefObject<HTMLVideoElement> = React.createRef()
|
||||
const videoRef = React.createRef<HTMLVideoElement>()
|
||||
|
||||
function handleSuccess(stream) {
|
||||
// startButton.disabled = true;
|
||||
// @ts-ignore
|
||||
videoRef.current.srcObject = stream;
|
||||
//videoRef.current?.srcObject = stream;
|
||||
// @ts-ignore
|
||||
window.stream = stream; // make variable available to browser console
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,22 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import { Button, Icon } from 'UI'
|
||||
|
||||
function VideoContainer() {
|
||||
interface Props {
|
||||
stream: MediaProvider | null
|
||||
muted?: boolean
|
||||
}
|
||||
|
||||
function VideoContainer({ stream, muted = false }: Props) {
|
||||
const ref = useRef<HTMLVideoElement>(null);
|
||||
useEffect(() => {
|
||||
// TODO check for video stream and display
|
||||
}, [])
|
||||
if (ref.current) {
|
||||
ref.current.srcObject = stream;
|
||||
}
|
||||
}, [ ref.current, stream ])
|
||||
return (
|
||||
<div className="relative h-20 bg-gray-light-shade border p-1" style={{ height: '160px', width: '200px' }}>
|
||||
<div className="absolute left-0 right-0 bottom-0 flex justify-center border border-gray-300 p-1 bg-white radius bg-opacity-25">
|
||||
<video autoPlay ref={ ref } muted={ muted } />
|
||||
<Button plain size="small">
|
||||
<Icon name="mic" size="16" />
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ export default class Player extends React.PureComponent {
|
|||
// label="Esc"
|
||||
// />
|
||||
}
|
||||
<div className={ stl.playerView }>
|
||||
<div className="relative flex-1">
|
||||
{ !inspectorMode &&
|
||||
<div
|
||||
className={ stl.overlay }
|
||||
|
|
|
|||
|
|
@ -1,478 +0,0 @@
|
|||
//@flow
|
||||
import { Decoder } from "syncod";
|
||||
import logger from 'App/logger';
|
||||
|
||||
import Resource, { TYPES } from 'Types/session/resource'; // MBTODO: player types?
|
||||
import { TYPES as EVENT_TYPES } from 'Types/session/event';
|
||||
import Log from 'Types/session/log';
|
||||
import Profile from 'Types/session/profile';
|
||||
import ReduxAction from 'Types/session/reduxAction';
|
||||
|
||||
import { update } from '../store';
|
||||
import {
|
||||
init as initListsDepr,
|
||||
append as listAppend,
|
||||
setStartTime as setListsStartTime
|
||||
} from '../lists';
|
||||
|
||||
import StatedScreen from './StatedScreen';
|
||||
|
||||
import ListWalker from './managers/ListWalker';
|
||||
import PagesManager from './managers/PagesManager';
|
||||
import MouseManager from './managers/MouseManager';
|
||||
|
||||
import PerformanceTrackManager from './managers/PerformanceTrackManager';
|
||||
import WindowNodeCounter from './managers/WindowNodeCounter';
|
||||
import ActivityManager from './managers/ActivityManager';
|
||||
|
||||
import MessageGenerator from './MessageGenerator';
|
||||
|
||||
import { INITIAL_STATE as PARENT_INITIAL_STATE } from './StatedScreen';
|
||||
|
||||
|
||||
const LIST_NAMES = [ "redux", "mobx", "vuex", "ngrx", "graphql", "exceptions", "profiles", "longtasks" ]
|
||||
const LISTS_INITIAL_STATE = {};
|
||||
LIST_NAMES.forEach(name => {
|
||||
LISTS_INITIAL_STATE[`${name}ListNow`] = [];
|
||||
LISTS_INITIAL_STATE[`${name}List`] = [];
|
||||
})
|
||||
export const INITIAL_STATE = {
|
||||
...PARENT_INITIAL_STATE,
|
||||
...LISTS_INITIAL_STATE,
|
||||
performanceChartData: [],
|
||||
skipIntervals: [],
|
||||
}
|
||||
|
||||
function initLists() {
|
||||
const lists = {};
|
||||
for (var i = 0; i < LIST_NAMES.length; i++) {
|
||||
lists[ LIST_NAMES[i] ] = new ListWalker();
|
||||
}
|
||||
return lists;
|
||||
}
|
||||
|
||||
|
||||
import type {
|
||||
Message,
|
||||
SetLocation,
|
||||
SetTitle,
|
||||
ConnectionInformation,
|
||||
SetViewportSize,
|
||||
SetViewportScroll,
|
||||
} from './messages';
|
||||
|
||||
|
||||
type ReduxDecoded = Timed & {
|
||||
action: {},
|
||||
state: {},
|
||||
duration: number,
|
||||
}
|
||||
|
||||
export default class MessageDistributor extends StatedScreen {
|
||||
// TODO: consistent with the other data-lists
|
||||
#locationEventManager: ListWalker<> = new ListWalker();
|
||||
#locationManager: ListWalker<SetLocation> = new ListWalker();
|
||||
#loadedLocationManager: ListWalker<SetLocation> = new ListWalker();
|
||||
#titleManager: ListWalker<SetTitle> = new ListWalker();
|
||||
#connectionInfoManger: ListWalker<ConnectionInformation> = new ListWalker();
|
||||
#performanceTrackManager: PerformanceTrackManager = new PerformanceTrackManager();
|
||||
#windowNodeCounter: WindowNodeCounter = new WindowNodeCounter();
|
||||
#clickManager: ListWalker = new ListWalker();
|
||||
|
||||
#resizeManager: ListWalker<SetViewportSize> = new ListWalker();
|
||||
#pagesManager: PagesManager;
|
||||
#mouseManager: MouseManager;
|
||||
|
||||
#scrollManager: ListWalker<SetViewportScroll> = new ListWalker();
|
||||
|
||||
#decoder = new Decoder();
|
||||
#lists = initLists();
|
||||
|
||||
#activirtManager: ActivityManager;
|
||||
|
||||
#sessionStart: number;
|
||||
#navigationStartOffset: number = 0;
|
||||
#lastMessageTime: number = 0;
|
||||
|
||||
constructor(sess: any /*Session*/, jwt: string) {
|
||||
super();
|
||||
this.#pagesManager = new PagesManager(this, sess.isMobile)
|
||||
this.#mouseManager = new MouseManager(this);
|
||||
|
||||
this.#activirtManager = new ActivityManager(sess.duration.milliseconds);
|
||||
|
||||
this.#sessionStart = sess.startedAt;
|
||||
|
||||
/* == REFACTOR_ME == */
|
||||
const eventList = sess.events.toJSON();
|
||||
initListsDepr({
|
||||
event: eventList,
|
||||
stack: sess.stackEvents.toJSON(),
|
||||
resource: sess.resources.toJSON(),
|
||||
});
|
||||
|
||||
eventList.forEach(e => {
|
||||
if (e.type === EVENT_TYPES.LOCATION) { //TODO type system
|
||||
this.#locationEventManager.add(e);
|
||||
}
|
||||
if (e.type === EVENT_TYPES.CLICK) {
|
||||
this.#clickManager.add(e);
|
||||
}
|
||||
});
|
||||
sess.errors.forEach(e => {
|
||||
this.#lists.exceptions.add(e);
|
||||
});
|
||||
/* === */
|
||||
|
||||
|
||||
if (sess.live) {
|
||||
// const sockUrl = `wss://live.openreplay.com/1/${ sess.siteId }/${ sess.sessionId }/${ jwt }`;
|
||||
// this.#subscribeOnMessages(sockUrl);
|
||||
} else {
|
||||
this._loadMessages(sess.mobsUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #subscribeOnMessages(sockUrl) {
|
||||
// this.setMessagesLoading(true);
|
||||
// const socket = new WebSocket(sockUrl);
|
||||
// socket.binaryType = 'arraybuffer';
|
||||
// socket.onerror = (e) => {
|
||||
// // TODO: reconnect
|
||||
// update({ error: true });
|
||||
// }
|
||||
// socket.onmessage = (socketMessage) => {
|
||||
// const data = new Uint8Array(socketMessage.data);
|
||||
// const msgs = [];
|
||||
// messageGenerator // parseBuffer(msgs, data);
|
||||
// // TODO: count indexes. Now will not work due to wrong indexes
|
||||
// //msgs.forEach(this.#distributeMessage);
|
||||
// this.setMessagesLoading(false);
|
||||
// this.setDisconnected(false);
|
||||
// }
|
||||
// this._socket = socket;
|
||||
// }
|
||||
|
||||
_loadMessages(fileUrl): void {
|
||||
this.setMessagesLoading(true);
|
||||
window.fetch(fileUrl)
|
||||
.then(r => r.arrayBuffer())
|
||||
.then(b => {
|
||||
const mGen = new MessageGenerator(new Uint8Array(b), this.#sessionStart);
|
||||
let mCount = 0;
|
||||
const msgs = [];
|
||||
|
||||
while (mGen.hasNext()) {
|
||||
mCount++;
|
||||
const next = mGen.next();
|
||||
if (next != null) {
|
||||
this.#lastMessageTime = next[0].time;
|
||||
this.#distributeMessage(next[0], next[1]);
|
||||
msgs.push(next[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Hack for upet (TODO: fix ordering in one mutation (removes first))
|
||||
const headChildrenIds = msgs.filter(m => m.parentID === 1).map(m => m.id);
|
||||
//const createNodeTypes = ["create_text_node", "create_element_node"];
|
||||
this.#pagesManager.sort((m1, m2) =>{
|
||||
if (m1.time === m2.time) {
|
||||
if (m1.tp === "remove_node" && m2.tp !== "remove_node") {
|
||||
if (headChildrenIds.includes(m1.id)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (m2.tp === "remove_node" && m1.tp !== "remove_node") {
|
||||
if (headChildrenIds.includes(m2.id)) {
|
||||
return 1;
|
||||
}
|
||||
} else if (m2.tp === "remove_node" && m1.tp === "remove_node") {
|
||||
const m1FromHead = headChildrenIds.includes(m1.id);
|
||||
const m2FromHead = headChildrenIds.includes(m2.id);
|
||||
if (m1FromHead && !m2FromHead) {
|
||||
return -1;
|
||||
} else if (m2FromHead && !m1FromHead) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
//
|
||||
|
||||
logger.info("Messages count: ", mCount, msgs);
|
||||
|
||||
const stateToUpdate = {
|
||||
performanceChartData: this.#performanceTrackManager.chartData,
|
||||
performanceAvaliability: this.#performanceTrackManager.avaliability,
|
||||
};
|
||||
this.#activirtManager.end();
|
||||
stateToUpdate.skipIntervals = this.#activirtManager.list;
|
||||
LIST_NAMES.forEach(key => {
|
||||
stateToUpdate[ `${ key }List` ] = this.#lists[ key ].list;
|
||||
});
|
||||
update(stateToUpdate);
|
||||
|
||||
this.#windowNodeCounter.reset();
|
||||
|
||||
this.setMessagesLoading(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
logger.error(e);
|
||||
this.setMessagesLoading(false);
|
||||
update({ error: true });
|
||||
});
|
||||
}
|
||||
|
||||
move(t: number, index: ?number):void {
|
||||
const stateToUpdate = {};
|
||||
/* == REFACTOR_ME == */
|
||||
const lastLoadedLocationMsg = this.#loadedLocationManager.moveToLast(t, index);
|
||||
if (!!lastLoadedLocationMsg) {
|
||||
setListsStartTime(lastLoadedLocationMsg.time)
|
||||
this.#navigationStartOffset = lastLoadedLocationMsg.navigationStart - this.#sessionStart;
|
||||
}
|
||||
const llEvent = this.#locationEventManager.moveToLast(t, index);
|
||||
if (!!llEvent) {
|
||||
if (llEvent.domContentLoadedTime != null) {
|
||||
stateToUpdate.domContentLoadedTime = {
|
||||
time: llEvent.domContentLoadedTime + this.#navigationStartOffset, //TODO: predefined list of load event for the network tab (merge events & setLocation: add navigationStart to db)
|
||||
value: llEvent.domContentLoadedTime,
|
||||
}
|
||||
}
|
||||
if (llEvent.loadTime != null) {
|
||||
stateToUpdate.loadTime = {
|
||||
time: llEvent.loadTime + this.#navigationStartOffset,
|
||||
value: llEvent.loadTime,
|
||||
}
|
||||
}
|
||||
if (llEvent.domBuildingTime != null) {
|
||||
stateToUpdate.domBuildingTime = llEvent.domBuildingTime;
|
||||
}
|
||||
}
|
||||
/* === */
|
||||
const lastLocationMsg = this.#locationManager.moveToLast(t, index);
|
||||
if (!!lastLocationMsg) {
|
||||
stateToUpdate.location = lastLocationMsg.url;
|
||||
}
|
||||
const lastTitleMsg = this.#titleManager.moveToLast(t, index);
|
||||
if (!!lastTitleMsg) {
|
||||
stateToUpdate.title = lastTitleMsg.title;
|
||||
}
|
||||
const lastConnectionInfoMsg = this.#connectionInfoManger.moveToLast(t, index);
|
||||
if (!!lastConnectionInfoMsg) {
|
||||
stateToUpdate.connType = lastConnectionInfoMsg.type;
|
||||
stateToUpdate.connBandwidth = lastConnectionInfoMsg.downlink;
|
||||
}
|
||||
const lastPerformanceTrackMessage = this.#performanceTrackManager.moveToLast(t, index);
|
||||
if (!!lastPerformanceTrackMessage) {
|
||||
stateToUpdate.performanceChartTime = lastPerformanceTrackMessage.time;
|
||||
}
|
||||
|
||||
LIST_NAMES.forEach(key => {
|
||||
const lastMsg = this.#lists[ key ].moveToLast(t, key === 'exceptions' ? null : index);
|
||||
if (lastMsg != null) {
|
||||
stateToUpdate[`${key}ListNow`] = this.#lists[ key ].listNow;
|
||||
}
|
||||
});
|
||||
|
||||
update(stateToUpdate);
|
||||
|
||||
/* Sequence of the managers is important here */
|
||||
// Preparing the size of "screen"
|
||||
const lastResize = this.#resizeManager.moveToLast(t, index);
|
||||
if (!!lastResize) {
|
||||
this.setSize(lastResize)
|
||||
}
|
||||
this.#pagesManager.moveReady(t).then(() => {
|
||||
|
||||
const lastScroll = this.#scrollManager.moveToLast(t, index);
|
||||
if (!!lastScroll && this.window) {
|
||||
this.window.scrollTo(lastScroll.x, lastScroll.y);
|
||||
}
|
||||
// Moving mouse and setting :hover classes on ready view
|
||||
this.#mouseManager.move(t);
|
||||
const lastClick = this.#clickManager.moveToLast(t);
|
||||
// if (!!lastClick) {
|
||||
// this.cursor.click();
|
||||
// }
|
||||
// After all changes - redraw the marker
|
||||
//this.marker.redraw();
|
||||
})
|
||||
}
|
||||
|
||||
_decodeMessage(msg, keys: Array<string>) {
|
||||
const decoded = {};
|
||||
try {
|
||||
keys.forEach(key => {
|
||||
decoded[ key ] = this.#decoder.decode(msg[ key ]);
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error("Error on message decoding: ", e, msg);
|
||||
return null;
|
||||
}
|
||||
return { ...msg, ...decoded };
|
||||
}
|
||||
|
||||
/* Binded */
|
||||
#distributeMessage = (msg: Message, index: number): void => {
|
||||
if ([
|
||||
"mouse_move",
|
||||
"set_input_value",
|
||||
"set_input_checked",
|
||||
"set_viewport_size",
|
||||
"set_viewport_scroll",
|
||||
].includes(msg.tp)) {
|
||||
this.#activirtManager.updateAcctivity(msg.time);
|
||||
}
|
||||
//const index = #i + index; //?
|
||||
let decoded;
|
||||
const time = msg.time;
|
||||
switch (msg.tp) {
|
||||
/* Lists: */
|
||||
case "resource_timing":
|
||||
logger.log(msg)
|
||||
listAppend("resource", Resource({
|
||||
time,
|
||||
duration: msg.duration,
|
||||
ttfb: msg.ttfb,
|
||||
url: msg.url,
|
||||
initiator: msg.initiator,
|
||||
index,
|
||||
}));
|
||||
break;
|
||||
case "console_log":
|
||||
if (msg.level === 'debug') break;
|
||||
listAppend("log", Log({
|
||||
level: msg.level,
|
||||
value: msg.value,
|
||||
time,
|
||||
index,
|
||||
}));
|
||||
break;
|
||||
case "fetch":
|
||||
listAppend("fetch", Resource({
|
||||
method: msg.method,
|
||||
url: msg.url,
|
||||
payload: msg.request,
|
||||
response: msg.response,
|
||||
status: msg.status,
|
||||
duration: msg.duration,
|
||||
type: TYPES.FETCH,
|
||||
time: msg.timestamp - this.#sessionStart, //~
|
||||
index,
|
||||
}));
|
||||
break;
|
||||
/* */
|
||||
case "set_page_location":
|
||||
this.#locationManager.add(msg);
|
||||
if (msg.navigationStart > 0) {
|
||||
this.#loadedLocationManager.add(msg);
|
||||
}
|
||||
break;
|
||||
case "set_title":
|
||||
this.#titleManager.add(msg);
|
||||
break;
|
||||
case "set_viewport_size":
|
||||
this.#resizeManager.add(msg);
|
||||
break;
|
||||
case "mouse_move":
|
||||
this.#mouseManager.add(msg);
|
||||
break;
|
||||
case "set_viewport_scroll":
|
||||
this.#scrollManager.add(msg);
|
||||
break;
|
||||
case "performance_track":
|
||||
this.#performanceTrackManager.add(msg);
|
||||
break;
|
||||
case "set_page_visibility":
|
||||
this.#performanceTrackManager.handleVisibility(msg)
|
||||
break;
|
||||
case "connection_information":
|
||||
this.#connectionInfoManger.add(msg);
|
||||
break;
|
||||
case "o_table":
|
||||
this.#decoder.set(msg.key, msg.value);
|
||||
break;
|
||||
case "redux":
|
||||
decoded = this._decodeMessage(msg, ["state", "action"]);
|
||||
logger.log(decoded)
|
||||
if (decoded != null) {
|
||||
this.#lists.redux.add(decoded);
|
||||
}
|
||||
break;
|
||||
case "ng_rx":
|
||||
decoded = this._decodeMessage(msg, ["state", "action"]);
|
||||
logger.log(decoded)
|
||||
if (decoded != null) {
|
||||
this.#lists.ngrx.add(decoded);
|
||||
}
|
||||
break;
|
||||
case "vuex":
|
||||
decoded = this._decodeMessage(msg, ["state", "mutation"]);
|
||||
logger.log(decoded)
|
||||
if (decoded != null) {
|
||||
this.#lists.vuex.add(decoded);
|
||||
}
|
||||
break;
|
||||
case "mob_x":
|
||||
decoded = this._decodeMessage(msg, ["payload"]);
|
||||
logger.log(decoded)
|
||||
|
||||
if (decoded != null) {
|
||||
this.#lists.mobx.add(decoded);
|
||||
}
|
||||
break;
|
||||
case "graph_ql":
|
||||
msg.duration = 0;
|
||||
this.#lists.graphql.add(msg);
|
||||
break;
|
||||
case "profiler":
|
||||
this.#lists.profiles.add(msg);
|
||||
break;
|
||||
case "long_task":
|
||||
this.#lists.longtasks.add({
|
||||
...msg,
|
||||
time: msg.timestamp - this.#sessionStart,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
switch (msg.tp){
|
||||
case "create_document":
|
||||
this.#windowNodeCounter.reset();
|
||||
this.#performanceTrackManager.setCurrentNodesCount(this.#windowNodeCounter.count);
|
||||
break;
|
||||
case "create_text_node":
|
||||
case "create_element_node":
|
||||
this.#windowNodeCounter.addNode(msg.id, msg.parentID);
|
||||
this.#performanceTrackManager.setCurrentNodesCount(this.#windowNodeCounter.count);
|
||||
break;
|
||||
case "move_node":
|
||||
this.#windowNodeCounter.moveNode(msg.id, msg.parentID);
|
||||
this.#performanceTrackManager.setCurrentNodesCount(this.#windowNodeCounter.count);
|
||||
break;
|
||||
case "remove_node":
|
||||
this.#windowNodeCounter.removeNode(msg.id);
|
||||
this.#performanceTrackManager.setCurrentNodesCount(this.#windowNodeCounter.count);
|
||||
break;
|
||||
}
|
||||
this.#pagesManager.add(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
getLastMessageTime():number {
|
||||
return this.#lastMessageTime;
|
||||
}
|
||||
|
||||
getFirstMessageTime():number {
|
||||
return 0; //this.#pagesManager.minTime;
|
||||
}
|
||||
|
||||
// TODO: clean managers?
|
||||
clean() {
|
||||
super.clean();
|
||||
if (this._socket) this._socket.close();
|
||||
update(INITIAL_STATE);
|
||||
}
|
||||
}
|
||||
526
frontend/app/player/MessageDistributor/MessageDistributor.ts
Normal file
526
frontend/app/player/MessageDistributor/MessageDistributor.ts
Normal file
|
|
@ -0,0 +1,526 @@
|
|||
import { Decoder } from "syncod";
|
||||
import logger from 'App/logger';
|
||||
|
||||
import Resource, { TYPES } from 'Types/session/resource'; // MBTODO: player types?
|
||||
import { TYPES as EVENT_TYPES } from 'Types/session/event';
|
||||
import Log from 'Types/session/log';
|
||||
import Profile from 'Types/session/profile';
|
||||
import ReduxAction from 'Types/session/reduxAction';
|
||||
|
||||
import { update } from '../store';
|
||||
import {
|
||||
init as initListsDepr,
|
||||
append as listAppend,
|
||||
setStartTime as setListsStartTime
|
||||
} from '../lists';
|
||||
|
||||
import StatedScreen from './StatedScreen';
|
||||
|
||||
import ListWalker from './managers/ListWalker';
|
||||
import PagesManager from './managers/PagesManager';
|
||||
import MouseManager from './managers/MouseManager';
|
||||
|
||||
import PerformanceTrackManager from './managers/PerformanceTrackManager';
|
||||
import WindowNodeCounter from './managers/WindowNodeCounter';
|
||||
import ActivityManager from './managers/ActivityManager';
|
||||
|
||||
import MessageReader from './MessageReader';
|
||||
import { ID_TP_MAP } from './messages';
|
||||
|
||||
import { INITIAL_STATE as PARENT_INITIAL_STATE } from './StatedScreen';
|
||||
|
||||
import type Peer from 'peerjs';
|
||||
import type { TimedMessage } from './Timed';
|
||||
|
||||
const LIST_NAMES = [ "redux", "mobx", "vuex", "ngrx", "graphql", "exceptions", "profiles", "longtasks" ] as const;
|
||||
const LISTS_INITIAL_STATE = {};
|
||||
LIST_NAMES.forEach(name => {
|
||||
LISTS_INITIAL_STATE[`${name}ListNow`] = [];
|
||||
LISTS_INITIAL_STATE[`${name}List`] = [];
|
||||
})
|
||||
export const INITIAL_STATE = {
|
||||
...PARENT_INITIAL_STATE,
|
||||
...LISTS_INITIAL_STATE,
|
||||
performanceChartData: [],
|
||||
skipIntervals: [],
|
||||
} as const;
|
||||
|
||||
type ListsObject = {
|
||||
[key in typeof LIST_NAMES[number]]: ListWalker<any> //
|
||||
}
|
||||
|
||||
function initLists(): ListsObject {
|
||||
const lists: Partial<ListsObject> = {} ;
|
||||
for (var i = 0; i < LIST_NAMES.length; i++) {
|
||||
lists[ LIST_NAMES[i] ] = new ListWalker();
|
||||
}
|
||||
return lists as ListsObject;
|
||||
}
|
||||
|
||||
|
||||
import type {
|
||||
Message,
|
||||
SetPageLocation,
|
||||
ConnectionInformation,
|
||||
SetViewportSize,
|
||||
SetViewportScroll,
|
||||
} from './messages';
|
||||
|
||||
interface Timed { //TODO: to common space
|
||||
time: number;
|
||||
}
|
||||
|
||||
type ReduxDecoded = Timed & {
|
||||
action: {},
|
||||
state: {},
|
||||
duration: number,
|
||||
}
|
||||
|
||||
export default class MessageDistributor extends StatedScreen {
|
||||
// TODO: consistent with the other data-lists
|
||||
private readonly locationEventManager: ListWalker<any>/*<LocationEvent>*/ = new ListWalker();
|
||||
private readonly locationManager: ListWalker<SetPageLocation & Timed> = new ListWalker();
|
||||
private readonly loadedLocationManager: ListWalker<SetPageLocation & Timed> = new ListWalker();
|
||||
private readonly connectionInfoManger: ListWalker<ConnectionInformation & Timed> = new ListWalker();
|
||||
private readonly performanceTrackManager: PerformanceTrackManager = new PerformanceTrackManager();
|
||||
private readonly windowNodeCounter: WindowNodeCounter = new WindowNodeCounter();
|
||||
private readonly clickManager: ListWalker<Timed> = new ListWalker();
|
||||
|
||||
private readonly resizeManager: ListWalker<SetViewportSize & Timed> = new ListWalker([]);
|
||||
private readonly pagesManager: PagesManager;
|
||||
private readonly mouseManager: MouseManager;
|
||||
|
||||
private readonly scrollManager: ListWalker<SetViewportScroll & Timed> = new ListWalker();
|
||||
|
||||
private readonly decoder = new Decoder();
|
||||
private readonly lists = initLists();
|
||||
|
||||
private activirtManager: ActivityManager | null = null;
|
||||
|
||||
private readonly sessionStart: number;
|
||||
private navigationStartOffset: number = 0;
|
||||
private lastMessageTime: number = 0;
|
||||
|
||||
constructor(private readonly session: any /*Session*/, jwt: string) {
|
||||
super();
|
||||
this.pagesManager = new PagesManager(this, this.session.isMobile)
|
||||
this.mouseManager = new MouseManager(this);
|
||||
|
||||
this.sessionStart = this.session.startedAt;
|
||||
|
||||
if (this.session.live) {
|
||||
// const sockUrl = `wss://live.openreplay.com/1/${ this.session.siteId }/${ this.session.sessionId }/${ jwt }`;
|
||||
// this.subscribeOnMessages(sockUrl);
|
||||
initListsDepr({})
|
||||
this.connectToPeer();
|
||||
} else {
|
||||
this.activirtManager = 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(),
|
||||
});
|
||||
|
||||
eventList.forEach(e => {
|
||||
if (e.type === EVENT_TYPES.LOCATION) { //TODO type system
|
||||
this.locationEventManager.add(e);
|
||||
}
|
||||
if (e.type === EVENT_TYPES.CLICK) {
|
||||
this.clickManager.add(e);
|
||||
}
|
||||
});
|
||||
this.session.errors.forEach(e => {
|
||||
this.lists.exceptions.add(e);
|
||||
});
|
||||
/* === */
|
||||
this._loadMessages();
|
||||
}
|
||||
}
|
||||
|
||||
private peer: Peer | null = null;
|
||||
private connectToPeer() {
|
||||
this.setMessagesLoading(true);
|
||||
import('peerjs').then(({ default: Peer }) => {
|
||||
const peer = new Peer();
|
||||
this.peer = peer;
|
||||
peer.on("open", me => {
|
||||
console.log("peer opened", me);
|
||||
const id = `Amva-sf98-234fd-OR-test-${this.session.sessionId}`;
|
||||
console.log("trying to connect to", id)
|
||||
const conn = peer.connect(id);
|
||||
conn.on('open', () => {
|
||||
this.setMessagesLoading(false);
|
||||
let i = 0;
|
||||
console.log("peer connected")
|
||||
conn.on('data', (data) => {
|
||||
if (!Array.isArray(data)) { return; }
|
||||
let time = 0;
|
||||
let ts0 = 0;
|
||||
(data as Array<Message & { _id: number}>).forEach(msg => {
|
||||
msg.tp = ID_TP_MAP[msg._id]; // _id goes from tracker
|
||||
if (msg.tp === "timestamp") {
|
||||
ts0 = ts0 || msg.timestamp
|
||||
time = msg.timestamp - ts0;
|
||||
return;
|
||||
}
|
||||
const tMsg: TimedMessage = Object.assign(msg, {
|
||||
time,
|
||||
_index: i,
|
||||
});
|
||||
this.distributeMessage(tMsg, i++);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
callPeer(localStream: MediaStream, cb: (s: MediaStream)=>void): boolean {
|
||||
if (!this.peer) { return false; }
|
||||
const conn = this.peer.connections[`Amva-sf98-234fd-OR-test-${this.session.sessionId}`]?.[0];
|
||||
if (!conn || !conn.open) { return false; } // Conn not established
|
||||
const call = this.peer.call(conn.peer, localStream);
|
||||
console.log('calling...')
|
||||
// on refuse?
|
||||
call.on('stream', function(stream) {
|
||||
cb(stream);
|
||||
});
|
||||
//@ts-ignore
|
||||
this.document?.
|
||||
addEventListener("mousemove", ({ x, y }) => {
|
||||
conn.send([ x, y ]); // debounce?
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// subscribeOnMessages(sockUrl) {
|
||||
// this.setMessagesLoading(true);
|
||||
// const socket = new WebSocket(sockUrl);
|
||||
// socket.binaryType = 'arraybuffer';
|
||||
// socket.onerror = (e) => {
|
||||
// // TODO: reconnect
|
||||
// update({ error: true });
|
||||
// }
|
||||
// socket.onmessage = (socketMessage) => {
|
||||
// const data = new Uint8Array(socketMessage.data);
|
||||
// const msgs = [];
|
||||
// messageGenerator // parseBuffer(msgs, data);
|
||||
// // TODO: count indexes. Now will not work due to wrong indexes
|
||||
// //msgs.forEach(this.distributeMessage);
|
||||
// this.setMessagesLoading(false);
|
||||
// this.setDisconnected(false);
|
||||
// }
|
||||
// this._socket = socket;
|
||||
// }
|
||||
|
||||
_loadMessages(): void {
|
||||
const fileUrl: string = this.session.mobsUrl;
|
||||
this.setMessagesLoading(true);
|
||||
window.fetch(fileUrl)
|
||||
.then(r => r.arrayBuffer())
|
||||
.then(b => {
|
||||
const r = new MessageReader(new Uint8Array(b), this.sessionStart);
|
||||
const msgs: Array<Message> = [];
|
||||
|
||||
while (r.hasNext()) {
|
||||
const next = r.next();
|
||||
if (next != null) {
|
||||
this.lastMessageTime = next[0].time;
|
||||
this.distributeMessage(next[0], next[1]);
|
||||
msgs.push(next[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore Hack for upet (TODO: fix ordering in one mutation (removes first))
|
||||
const headChildrenIds = msgs.filter(m => m.parentID === 1).map(m => m.id);
|
||||
//const createNodeTypes = ["create_text_node", "create_element_node"];
|
||||
this.pagesManager.sort((m1, m2) =>{
|
||||
if (m1.time === m2.time) {
|
||||
if (m1.tp === "remove_node" && m2.tp !== "remove_node") {
|
||||
if (headChildrenIds.includes(m1.id)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (m2.tp === "remove_node" && m1.tp !== "remove_node") {
|
||||
if (headChildrenIds.includes(m2.id)) {
|
||||
return 1;
|
||||
}
|
||||
} else if (m2.tp === "remove_node" && m1.tp === "remove_node") {
|
||||
const m1FromHead = headChildrenIds.includes(m1.id);
|
||||
const m2FromHead = headChildrenIds.includes(m2.id);
|
||||
if (m1FromHead && !m2FromHead) {
|
||||
return -1;
|
||||
} else if (m2FromHead && !m1FromHead) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
//
|
||||
|
||||
logger.info("Messages count: ", msgs.length, msgs);
|
||||
|
||||
const stateToUpdate: {[key:string]: any} = {
|
||||
performanceChartData: this.performanceTrackManager.chartData,
|
||||
performanceAvaliability: this.performanceTrackManager.avaliability,
|
||||
};
|
||||
this.activirtManager?.end();
|
||||
stateToUpdate.skipIntervals = this.activirtManager?.list || [];
|
||||
LIST_NAMES.forEach(key => {
|
||||
stateToUpdate[ `${ key }List` ] = this.lists[ key ].list;
|
||||
});
|
||||
update(stateToUpdate);
|
||||
|
||||
this.windowNodeCounter.reset();
|
||||
|
||||
this.setMessagesLoading(false);
|
||||
})
|
||||
.catch((e) => {
|
||||
logger.error(e);
|
||||
this.setMessagesLoading(false);
|
||||
update({ error: true });
|
||||
});
|
||||
}
|
||||
|
||||
move(t: number, index?: number):void {
|
||||
const stateToUpdate: typeof INITIAL_STATE = {};
|
||||
/* == REFACTOR_ME == */
|
||||
const lastLoadedLocationMsg = this.loadedLocationManager.moveToLast(t, index);
|
||||
if (!!lastLoadedLocationMsg) {
|
||||
setListsStartTime(lastLoadedLocationMsg.time)
|
||||
this.navigationStartOffset = lastLoadedLocationMsg.navigationStart - this.sessionStart;
|
||||
}
|
||||
const llEvent = this.locationEventManager.moveToLast(t, index);
|
||||
if (!!llEvent) {
|
||||
if (llEvent.domContentLoadedTime != null) {
|
||||
stateToUpdate.domContentLoadedTime = {
|
||||
time: llEvent.domContentLoadedTime + this.navigationStartOffset, //TODO: predefined list of load event for the network tab (merge events & SetPageLocation: add navigationStart to db)
|
||||
value: llEvent.domContentLoadedTime,
|
||||
}
|
||||
}
|
||||
if (llEvent.loadTime != null) {
|
||||
stateToUpdate.loadTime = {
|
||||
time: llEvent.loadTime + this.navigationStartOffset,
|
||||
value: llEvent.loadTime,
|
||||
}
|
||||
}
|
||||
if (llEvent.domBuildingTime != null) {
|
||||
stateToUpdate.domBuildingTime = llEvent.domBuildingTime;
|
||||
}
|
||||
}
|
||||
/* === */
|
||||
const lastLocationMsg = this.locationManager.moveToLast(t, index);
|
||||
if (!!lastLocationMsg) {
|
||||
stateToUpdate.location = lastLocationMsg.url;
|
||||
}
|
||||
const lastConnectionInfoMsg = this.connectionInfoManger.moveToLast(t, index);
|
||||
if (!!lastConnectionInfoMsg) {
|
||||
stateToUpdate.connType = lastConnectionInfoMsg.type;
|
||||
stateToUpdate.connBandwidth = lastConnectionInfoMsg.downlink;
|
||||
}
|
||||
const lastPerformanceTrackMessage = this.performanceTrackManager.moveToLast(t, index);
|
||||
if (!!lastPerformanceTrackMessage) {
|
||||
stateToUpdate.performanceChartTime = lastPerformanceTrackMessage.time;
|
||||
}
|
||||
|
||||
LIST_NAMES.forEach(key => {
|
||||
const lastMsg = this.lists[ key ].moveToLast(t, key === 'exceptions' ? undefined : index);
|
||||
if (lastMsg != null) {
|
||||
stateToUpdate[`${key}ListNow`] = this.lists[ key ].listNow;
|
||||
}
|
||||
});
|
||||
|
||||
update(stateToUpdate);
|
||||
|
||||
/* Sequence of the managers is important here */
|
||||
// Preparing the size of "screen"
|
||||
const lastResize = this.resizeManager.moveToLast(t, index);
|
||||
if (!!lastResize) {
|
||||
this.setSize(lastResize)
|
||||
}
|
||||
this.pagesManager.moveReady(t).then(() => {
|
||||
|
||||
const lastScroll = this.scrollManager.moveToLast(t, index);
|
||||
// @ts-ignore ??can't see double inheritance
|
||||
if (!!lastScroll && this.window) {
|
||||
// @ts-ignore
|
||||
this.window.scrollTo(lastScroll.x, lastScroll.y);
|
||||
}
|
||||
// Moving mouse and setting :hover classes on ready view
|
||||
this.mouseManager.move(t);
|
||||
const lastClick = this.clickManager.moveToLast(t);
|
||||
// if (!!lastClick) {
|
||||
// this.cursor.click();
|
||||
// }
|
||||
// After all changes - redraw the marker
|
||||
//this.marker.redraw();
|
||||
})
|
||||
}
|
||||
|
||||
_decodeMessage(msg, keys: Array<string>) {
|
||||
const decoded = {};
|
||||
try {
|
||||
keys.forEach(key => {
|
||||
decoded[ key ] = this.decoder.decode(msg[ key ]);
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error("Error on message decoding: ", e, msg);
|
||||
return null;
|
||||
}
|
||||
return { ...msg, ...decoded };
|
||||
}
|
||||
|
||||
/* Binded */
|
||||
distributeMessage = (msg: TimedMessage, index: number): void => {
|
||||
if ([
|
||||
"mouse_move",
|
||||
"set_input_value",
|
||||
"set_input_checked",
|
||||
"set_viewport_size",
|
||||
"set_viewport_scroll",
|
||||
].includes(msg.tp)) {
|
||||
this.activirtManager?.updateAcctivity(msg.time);
|
||||
}
|
||||
//const index = i + index; //?
|
||||
let decoded;
|
||||
const time = msg.time;
|
||||
switch (msg.tp) {
|
||||
/* Lists: */
|
||||
case "console_log":
|
||||
if (msg.level === 'debug') break;
|
||||
listAppend("log", Log({
|
||||
level: msg.level,
|
||||
value: msg.value,
|
||||
time,
|
||||
index,
|
||||
}));
|
||||
break;
|
||||
case "fetch":
|
||||
listAppend("fetch", Resource({
|
||||
method: msg.method,
|
||||
url: msg.url,
|
||||
payload: msg.request,
|
||||
response: msg.response,
|
||||
status: msg.status,
|
||||
duration: msg.duration,
|
||||
type: TYPES.FETCH,
|
||||
time: msg.timestamp - this.sessionStart, //~
|
||||
index,
|
||||
}));
|
||||
break;
|
||||
/* */
|
||||
case "set_page_location":
|
||||
this.locationManager.add(msg);
|
||||
if (msg.navigationStart > 0) {
|
||||
this.loadedLocationManager.add(msg);
|
||||
}
|
||||
break;
|
||||
case "set_viewport_size":
|
||||
console.log("setvvs", msg)
|
||||
this.resizeManager.add(msg);
|
||||
break;
|
||||
case "mouse_move":
|
||||
this.mouseManager.add(msg);
|
||||
break;
|
||||
case "set_viewport_scroll":
|
||||
this.scrollManager.add(msg);
|
||||
break;
|
||||
case "performance_track":
|
||||
this.performanceTrackManager.add(msg);
|
||||
break;
|
||||
case "set_page_visibility":
|
||||
this.performanceTrackManager.handleVisibility(msg)
|
||||
break;
|
||||
case "connection_information":
|
||||
this.connectionInfoManger.add(msg);
|
||||
break;
|
||||
case "o_table":
|
||||
this.decoder.set(msg.key, msg.value);
|
||||
break;
|
||||
case "redux":
|
||||
decoded = this._decodeMessage(msg, ["state", "action"]);
|
||||
logger.log(decoded)
|
||||
if (decoded != null) {
|
||||
this.lists.redux.add(decoded);
|
||||
}
|
||||
break;
|
||||
case "ng_rx":
|
||||
decoded = this._decodeMessage(msg, ["state", "action"]);
|
||||
logger.log(decoded)
|
||||
if (decoded != null) {
|
||||
this.lists.ngrx.add(decoded);
|
||||
}
|
||||
break;
|
||||
case "vuex":
|
||||
decoded = this._decodeMessage(msg, ["state", "mutation"]);
|
||||
logger.log(decoded)
|
||||
if (decoded != null) {
|
||||
this.lists.vuex.add(decoded);
|
||||
}
|
||||
break;
|
||||
case "mob_x":
|
||||
decoded = this._decodeMessage(msg, ["payload"]);
|
||||
logger.log(decoded)
|
||||
|
||||
if (decoded != null) {
|
||||
this.lists.mobx.add(decoded);
|
||||
}
|
||||
break;
|
||||
case "graph_ql":
|
||||
// @ts-ignore some hack? TODO: remove
|
||||
msg.duration = 0;
|
||||
this.lists.graphql.add(msg);
|
||||
break;
|
||||
case "profiler":
|
||||
this.lists.profiles.add(msg);
|
||||
break;
|
||||
case "long_task":
|
||||
this.lists.longtasks.add({
|
||||
...msg,
|
||||
time: msg.timestamp - this.sessionStart,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
switch (msg.tp){
|
||||
case "create_document":
|
||||
this.windowNodeCounter.reset();
|
||||
this.performanceTrackManager.setCurrentNodesCount(this.windowNodeCounter.count);
|
||||
break;
|
||||
case "create_text_node":
|
||||
case "create_element_node":
|
||||
this.windowNodeCounter.addNode(msg.id, msg.parentID);
|
||||
this.performanceTrackManager.setCurrentNodesCount(this.windowNodeCounter.count);
|
||||
break;
|
||||
case "move_node":
|
||||
this.windowNodeCounter.moveNode(msg.id, msg.parentID);
|
||||
this.performanceTrackManager.setCurrentNodesCount(this.windowNodeCounter.count);
|
||||
break;
|
||||
case "remove_node":
|
||||
this.windowNodeCounter.removeNode(msg.id);
|
||||
this.performanceTrackManager.setCurrentNodesCount(this.windowNodeCounter.count);
|
||||
break;
|
||||
}
|
||||
this.pagesManager.add(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
getLastMessageTime():number {
|
||||
return this.lastMessageTime;
|
||||
}
|
||||
|
||||
getFirstMessageTime():number {
|
||||
return 0; //this.pagesManager.minTime;
|
||||
}
|
||||
|
||||
// TODO: clean managers?
|
||||
clean() {
|
||||
// @ts-ignore
|
||||
super.clean();
|
||||
//if (this._socket) this._socket.close();
|
||||
update(INITIAL_STATE);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
import type { TimedMessage } from './Timed';
|
||||
|
||||
import logger from 'App/logger';
|
||||
import readMessage from './messages';
|
||||
|
||||
function needSkipMessage(data: Uint8Array, p: number, pLast: number): boolean {
|
||||
for (let i = 7; i >= 0; i--) {
|
||||
if (data[ p + i ] !== data[ pLast + i ]) {
|
||||
return data[ p + i ] - data[ pLast + i ] < 0
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export default class MessageGenerator {
|
||||
#data: Uint8Array;
|
||||
#p: number = 0;
|
||||
#pLastMessageID: number = 0;
|
||||
#startTime: number;
|
||||
#currentTime: ?number;
|
||||
|
||||
#error: boolean = false;
|
||||
constructor(data: Uint8Array, startTime: number) {
|
||||
this.#startTime = startTime;
|
||||
this.#data = data;
|
||||
}
|
||||
|
||||
_needSkipMessage():boolean {
|
||||
if (this.#p === 0) return false;
|
||||
for (let i = 7; i >= 0; i--) {
|
||||
if (this.#data[ this.#p + i ] !== this.#data[ this.#pLastMessageID + i ]) {
|
||||
return this.#data[ this.#p + i ] - this.#data[ this.#pLastMessageID + i ] < 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_readMessage(): ?Message {
|
||||
this.#p += 8;
|
||||
try {
|
||||
let msg
|
||||
[ msg, this.#p ] = readMessage(this.#data, this.#p);
|
||||
return msg;
|
||||
} catch (e) {
|
||||
this.#error = true;
|
||||
logger.error("Read message error:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
hasNext():boolean {
|
||||
return !this.#error && this.#data.length > this.#p;
|
||||
}
|
||||
|
||||
next(): ?[ TimedMessage, number] {
|
||||
if (!this.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (this._needSkipMessage()) {
|
||||
this._readMessage();
|
||||
}
|
||||
this.#pLastMessageID = this.#p;
|
||||
|
||||
const msg = this._readMessage();
|
||||
if (!msg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (msg.tp === "timestamp") {
|
||||
// if (this.#startTime == null) {
|
||||
// this.#startTime = msg.timestamp
|
||||
// }
|
||||
this.#currentTime = msg.timestamp - this.#startTime;
|
||||
} else {
|
||||
msg.time = this.#currentTime;
|
||||
msg._index = this.#pLastMessageID;
|
||||
return [msg, this.#pLastMessageID];
|
||||
}
|
||||
}
|
||||
}
|
||||
80
frontend/app/player/MessageDistributor/MessageReader.ts
Normal file
80
frontend/app/player/MessageDistributor/MessageReader.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import type { TimedMessage, Indexed } from './Timed';
|
||||
|
||||
import logger from 'App/logger';
|
||||
import readMessage, { Message } from './messages';
|
||||
import PrimitiveReader from './PrimitiveReader';
|
||||
|
||||
// function needSkipMessage(data: Uint8Array, p: number, pLast: number): boolean {
|
||||
// for (let i = 7; i >= 0; i--) {
|
||||
// if (data[ p + i ] !== data[ pLast + i ]) {
|
||||
// return data[ p + i ] - data[ pLast + i ] < 0
|
||||
// }
|
||||
// }
|
||||
// return true
|
||||
// }
|
||||
|
||||
export default class MessageReader extends PrimitiveReader {
|
||||
private pLastMessageID: number = 0;
|
||||
private currentTime: number = 0;
|
||||
public error: boolean = false;
|
||||
constructor(data: Uint8Array, private readonly startTime: number) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
private needSkipMessage(): boolean {
|
||||
if (this.p === 0) return false;
|
||||
for (let i = 7; i >= 0; i--) {
|
||||
if (this.buf[ this.p + i ] !== this.buf[ this.pLastMessageID + i ]) {
|
||||
return this.buf[ this.p + i ] - this.buf[ this.pLastMessageID + i ] < 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private readMessage(): Message | null {
|
||||
this.skip(8);
|
||||
try {
|
||||
let msg
|
||||
msg = readMessage(this);
|
||||
return msg;
|
||||
} catch (e) {
|
||||
this.error = true;
|
||||
logger.error("Read message error:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
hasNext():boolean {
|
||||
return !this.error && this.buf.length > this.p;
|
||||
}
|
||||
|
||||
next(): [ TimedMessage, number] | null {
|
||||
if (!this.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (this.needSkipMessage()) {
|
||||
this.readMessage();
|
||||
}
|
||||
this.pLastMessageID = this.p;
|
||||
|
||||
const msg = this.readMessage();
|
||||
if (!msg) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (msg.tp === "timestamp") {
|
||||
// if (this.startTime == null) {
|
||||
// this.startTime = msg.timestamp
|
||||
// }
|
||||
this.currentTime = msg.timestamp - this.startTime;
|
||||
} else {
|
||||
const tMsg = Object.assign(msg, {
|
||||
time: this.currentTime,
|
||||
_index: this.pLastMessageID,
|
||||
})
|
||||
return [tMsg, this.pLastMessageID];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
36
frontend/app/player/MessageDistributor/PrimitiveReader.ts
Normal file
36
frontend/app/player/MessageDistributor/PrimitiveReader.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
export default class PrimitiveReader {
|
||||
protected p = 0
|
||||
constructor(protected readonly buf: Uint8Array) {}
|
||||
|
||||
readUint() {
|
||||
var r = 0, s = 1, b;
|
||||
do {
|
||||
b = this.buf[this.p++];
|
||||
r += (b & 0x7F) * s;
|
||||
s *= 128;
|
||||
} while (b >= 0x80)
|
||||
return r;
|
||||
}
|
||||
|
||||
readInt() {
|
||||
let u = this.readUint();
|
||||
if (u % 2) {
|
||||
u = (u + 1) / -2;
|
||||
} else {
|
||||
u = u / 2;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
readString() {
|
||||
var l = this.readUint();
|
||||
return new TextDecoder().decode(this.buf.subarray(this.p, this.p+=l));
|
||||
}
|
||||
|
||||
readBoolean() {
|
||||
return !!this.buf[this.p++];
|
||||
}
|
||||
skip(n: number) {
|
||||
this.p += n;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
.iframe {
|
||||
position: absolute;
|
||||
border: none;
|
||||
background: whilte;
|
||||
}
|
||||
.overlay {
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -12,28 +12,34 @@ export const INITIAL_STATE = {
|
|||
export default class StatedScreen extends Screen {
|
||||
|
||||
setMessagesLoading(messagesLoading) {
|
||||
// @ts-ignore
|
||||
this.display(!messagesLoading);
|
||||
update({ messagesLoading });
|
||||
}
|
||||
|
||||
setCSSLoading(cssLoading) {
|
||||
// @ts-ignore
|
||||
|
||||
this.displayFrame(!cssLoading);
|
||||
update({ cssLoading });
|
||||
}
|
||||
|
||||
setDisconnected(disconnected) {
|
||||
if (!getState().live) return; //?
|
||||
// @ts-ignore
|
||||
this.display(!disconnected);
|
||||
update({ disconnected });
|
||||
}
|
||||
|
||||
setUserPageLoading(userPageLoading) {
|
||||
// @ts-ignore
|
||||
this.display(!userPageLoading);
|
||||
update({ userPageLoading });
|
||||
}
|
||||
|
||||
setSize({ height, width }) {
|
||||
update({ width, height });
|
||||
// @ts-ignore
|
||||
this.scale();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
// @flow
|
||||
import type { Message } from './messages';
|
||||
|
||||
export type Timed = { +time: number };
|
||||
export type TimedMessage = Timed & Message;
|
||||
5
frontend/app/player/MessageDistributor/Timed.ts
Normal file
5
frontend/app/player/MessageDistributor/Timed.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import type { Message } from './messages';
|
||||
|
||||
export interface Timed { readonly time: number };
|
||||
export interface Indexed { readonly _index: number }; // TODO: remove dash (evwrywhere)
|
||||
export type TimedMessage = Timed & Message;
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
//@flow
|
||||
|
||||
import type { Timed } from '../Timed';
|
||||
|
||||
export default class ListWalker<T: Timed> {
|
||||
export default class ListWalker<T extends Timed> {
|
||||
// Optimisation: #prop compiles to method that costs mor than strict property call.
|
||||
_p = 0;
|
||||
_list: Array<T>;
|
||||
|
|
@ -15,7 +13,7 @@ export default class ListWalker<T: Timed> {
|
|||
}
|
||||
|
||||
append(m: T): void {
|
||||
if (this.length > 0 && m.time < this.last.time) {
|
||||
if (this.length > 0 && this.last && m.time < this.last.time) {
|
||||
console.error("Trying to append message with the less time then the list tail: ", m);
|
||||
}
|
||||
this._list.push(m);
|
||||
|
|
@ -26,6 +24,7 @@ export default class ListWalker<T: Timed> {
|
|||
}
|
||||
|
||||
sort(comparator): void {
|
||||
// @ts-ignore
|
||||
this._list.sort((m1,m2) => comparator(m1,m2) || (m1._index - m2._index) ); // indexes for sort stability (TODO: fix types???)
|
||||
}
|
||||
|
||||
|
|
@ -100,10 +99,10 @@ export default class ListWalker<T: Timed> {
|
|||
Assumed that the current message is already handled so
|
||||
if pointer doesn't cahnge <undefined> is returned.
|
||||
*/
|
||||
moveToLast(t: number, index: ?number): ?T {
|
||||
let key = "time"; //TODO
|
||||
moveToLast(t: number, index?: number): T | null {
|
||||
let key: string = "time"; //TODO
|
||||
let val = t;
|
||||
if (index != null) {
|
||||
if (index) {
|
||||
key = "_index";
|
||||
val = index;
|
||||
}
|
||||
|
|
@ -117,7 +116,7 @@ export default class ListWalker<T: Timed> {
|
|||
this._p--;
|
||||
changed = true;
|
||||
}
|
||||
return changed ? this._list[ this._p - 1 ] : undefined;
|
||||
return changed ? this._list[ this._p - 1 ] : null;
|
||||
}
|
||||
|
||||
// moveToLastByIndex(i: number): ?T {
|
||||
|
|
@ -133,7 +132,7 @@ export default class ListWalker<T: Timed> {
|
|||
// return changed ? this._list[ this._p - 1 ] : undefined;
|
||||
// }
|
||||
|
||||
moveApply(t: number, fn: T => void): void {
|
||||
moveApply(t: number, fn: (T) => void): void {
|
||||
// Applying only in increment order for now
|
||||
if (t < this.timeNow) {
|
||||
this.reset();
|
||||
|
|
@ -1,596 +0,0 @@
|
|||
// Auto-generated, do not edit
|
||||
|
||||
import { readUint, readInt, readString, readBoolean } from './readPrimitives'
|
||||
|
||||
|
||||
export type Timestamp = {
|
||||
tp: "timestamp",
|
||||
timestamp: number,
|
||||
}
|
||||
|
||||
export type SessionDisconnect = {
|
||||
tp: "session_disconnect",
|
||||
timestamp: number,
|
||||
}
|
||||
|
||||
export type SetPageLocation = {
|
||||
tp: "set_page_location",
|
||||
url: string,
|
||||
referrer: string,
|
||||
navigationStart: number,
|
||||
}
|
||||
|
||||
export type SetViewportSize = {
|
||||
tp: "set_viewport_size",
|
||||
width: number,
|
||||
height: number,
|
||||
}
|
||||
|
||||
export type SetViewportScroll = {
|
||||
tp: "set_viewport_scroll",
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
export type CreateDocument = {
|
||||
tp: "create_document",
|
||||
|
||||
}
|
||||
|
||||
export type CreateElementNode = {
|
||||
tp: "create_element_node",
|
||||
id: number,
|
||||
parentID: number,
|
||||
index: number,
|
||||
tag: string,
|
||||
svg: boolean,
|
||||
}
|
||||
|
||||
export type CreateTextNode = {
|
||||
tp: "create_text_node",
|
||||
id: number,
|
||||
parentID: number,
|
||||
index: number,
|
||||
}
|
||||
|
||||
export type MoveNode = {
|
||||
tp: "move_node",
|
||||
id: number,
|
||||
parentID: number,
|
||||
index: number,
|
||||
}
|
||||
|
||||
export type RemoveNode = {
|
||||
tp: "remove_node",
|
||||
id: number,
|
||||
}
|
||||
|
||||
export type SetNodeAttribute = {
|
||||
tp: "set_node_attribute",
|
||||
id: number,
|
||||
name: string,
|
||||
value: string,
|
||||
}
|
||||
|
||||
export type RemoveNodeAttribute = {
|
||||
tp: "remove_node_attribute",
|
||||
id: number,
|
||||
name: string,
|
||||
}
|
||||
|
||||
export type SetNodeData = {
|
||||
tp: "set_node_data",
|
||||
id: number,
|
||||
data: string,
|
||||
}
|
||||
|
||||
export type SetCssData = {
|
||||
tp: "set_css_data",
|
||||
id: number,
|
||||
data: string,
|
||||
}
|
||||
|
||||
export type SetNodeScroll = {
|
||||
tp: "set_node_scroll",
|
||||
id: number,
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
export type SetInputValue = {
|
||||
tp: "set_input_value",
|
||||
id: number,
|
||||
value: string,
|
||||
mask: number,
|
||||
}
|
||||
|
||||
export type SetInputChecked = {
|
||||
tp: "set_input_checked",
|
||||
id: number,
|
||||
checked: boolean,
|
||||
}
|
||||
|
||||
export type MouseMove = {
|
||||
tp: "mouse_move",
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
export type ConsoleLog = {
|
||||
tp: "console_log",
|
||||
level: string,
|
||||
value: string,
|
||||
}
|
||||
|
||||
export type PerformanceTrack = {
|
||||
tp: "performance_track",
|
||||
frames: number,
|
||||
ticks: number,
|
||||
totalJSHeapSize: number,
|
||||
usedJSHeapSize: number,
|
||||
}
|
||||
|
||||
export type ConnectionInformation = {
|
||||
tp: "connection_information",
|
||||
downlink: number,
|
||||
type: string,
|
||||
}
|
||||
|
||||
export type SetPageVisibility = {
|
||||
tp: "set_page_visibility",
|
||||
hidden: boolean,
|
||||
}
|
||||
|
||||
export type CssInsertRule = {
|
||||
tp: "css_insert_rule",
|
||||
id: number,
|
||||
rule: string,
|
||||
index: number,
|
||||
}
|
||||
|
||||
export type CssDeleteRule = {
|
||||
tp: "css_delete_rule",
|
||||
id: number,
|
||||
index: number,
|
||||
}
|
||||
|
||||
export type Fetch = {
|
||||
tp: "fetch",
|
||||
method: string,
|
||||
url: string,
|
||||
request: string,
|
||||
response: string,
|
||||
status: number,
|
||||
timestamp: number,
|
||||
duration: number,
|
||||
}
|
||||
|
||||
export type Profiler = {
|
||||
tp: "profiler",
|
||||
name: string,
|
||||
duration: number,
|
||||
args: string,
|
||||
result: string,
|
||||
}
|
||||
|
||||
export type OTable = {
|
||||
tp: "o_table",
|
||||
key: string,
|
||||
value: string,
|
||||
}
|
||||
|
||||
export type Redux = {
|
||||
tp: "redux",
|
||||
action: string,
|
||||
state: string,
|
||||
duration: number,
|
||||
}
|
||||
|
||||
export type Vuex = {
|
||||
tp: "vuex",
|
||||
mutation: string,
|
||||
state: string,
|
||||
}
|
||||
|
||||
export type MobX = {
|
||||
tp: "mob_x",
|
||||
type: string,
|
||||
payload: string,
|
||||
}
|
||||
|
||||
export type NgRx = {
|
||||
tp: "ng_rx",
|
||||
action: string,
|
||||
state: string,
|
||||
duration: number,
|
||||
}
|
||||
|
||||
export type GraphQl = {
|
||||
tp: "graph_ql",
|
||||
operationKind: string,
|
||||
operationName: string,
|
||||
variables: string,
|
||||
response: string,
|
||||
}
|
||||
|
||||
export type LongTask = {
|
||||
tp: "long_task",
|
||||
timestamp: number,
|
||||
duration: number,
|
||||
context: number,
|
||||
containerType: number,
|
||||
containerSrc: string,
|
||||
containerId: string,
|
||||
containerName: string,
|
||||
}
|
||||
|
||||
export type TechnicalInfo = {
|
||||
tp: "technical_info",
|
||||
type: string,
|
||||
value: string,
|
||||
}
|
||||
|
||||
export type IosSessionStart = {
|
||||
tp: "ios_session_start",
|
||||
timestamp: number,
|
||||
projectID: number,
|
||||
trackerVersion: string,
|
||||
revID: string,
|
||||
userUUID: string,
|
||||
userOS: string,
|
||||
userOSVersion: string,
|
||||
userDevice: string,
|
||||
userDeviceType: string,
|
||||
userCountry: string,
|
||||
}
|
||||
|
||||
export type IosCustomEvent = {
|
||||
tp: "ios_custom_event",
|
||||
timestamp: number,
|
||||
length: number,
|
||||
name: string,
|
||||
payload: string,
|
||||
}
|
||||
|
||||
export type IosClickEvent = {
|
||||
tp: "ios_click_event",
|
||||
timestamp: number,
|
||||
length: number,
|
||||
label: string,
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
export type IosPerformanceEvent = {
|
||||
tp: "ios_performance_event",
|
||||
timestamp: number,
|
||||
length: number,
|
||||
name: string,
|
||||
value: number,
|
||||
}
|
||||
|
||||
export type IosLog = {
|
||||
tp: "ios_log",
|
||||
timestamp: number,
|
||||
length: number,
|
||||
severity: string,
|
||||
content: string,
|
||||
}
|
||||
|
||||
export type IosNetworkCall = {
|
||||
tp: "ios_network_call",
|
||||
timestamp: number,
|
||||
length: number,
|
||||
duration: number,
|
||||
headers: string,
|
||||
body: string,
|
||||
url: string,
|
||||
success: boolean,
|
||||
method: string,
|
||||
status: number,
|
||||
}
|
||||
|
||||
|
||||
export type Message = Timestamp | SessionDisconnect | SetPageLocation | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetCssData | SetNodeScroll | SetInputValue | SetInputChecked | MouseMove | ConsoleLog | PerformanceTrack | ConnectionInformation | SetPageVisibility | CssInsertRule | CssDeleteRule | Fetch | Profiler | OTable | Redux | Vuex | MobX | NgRx | GraphQl | LongTask | TechnicalInfo | IosSessionStart | IosCustomEvent | IosClickEvent | IosPerformanceEvent | IosLog | IosNetworkCall;
|
||||
|
||||
export default function (buf: Uint8Array, p: number): [Message, number] {
|
||||
const msg = {};
|
||||
let r;
|
||||
switch (buf[p++]) {
|
||||
|
||||
case 0:
|
||||
(msg:Timestamp).tp = "timestamp";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
(msg:SessionDisconnect).tp = "session_disconnect";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 4:
|
||||
(msg:SetPageLocation).tp = "set_page_location";
|
||||
r = readString(buf, p); msg.url = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.referrer = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.navigationStart = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 5:
|
||||
(msg:SetViewportSize).tp = "set_viewport_size";
|
||||
r = readUint(buf, p); msg.width = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.height = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 6:
|
||||
(msg:SetViewportScroll).tp = "set_viewport_scroll";
|
||||
r = readInt(buf, p); msg.x = r[0]; p = r[1];
|
||||
r = readInt(buf, p); msg.y = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 7:
|
||||
(msg:CreateDocument).tp = "create_document";
|
||||
|
||||
break;
|
||||
|
||||
case 8:
|
||||
(msg:CreateElementNode).tp = "create_element_node";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.parentID = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.index = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.tag = r[0]; p = r[1];
|
||||
r = readBoolean(buf, p); msg.svg = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 9:
|
||||
(msg:CreateTextNode).tp = "create_text_node";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.parentID = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.index = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 10:
|
||||
(msg:MoveNode).tp = "move_node";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.parentID = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.index = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 11:
|
||||
(msg:RemoveNode).tp = "remove_node";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 12:
|
||||
(msg:SetNodeAttribute).tp = "set_node_attribute";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.name = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.value = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 13:
|
||||
(msg:RemoveNodeAttribute).tp = "remove_node_attribute";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.name = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 14:
|
||||
(msg:SetNodeData).tp = "set_node_data";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.data = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 15:
|
||||
(msg:SetCssData).tp = "set_css_data";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.data = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 16:
|
||||
(msg:SetNodeScroll).tp = "set_node_scroll";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readInt(buf, p); msg.x = r[0]; p = r[1];
|
||||
r = readInt(buf, p); msg.y = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 18:
|
||||
(msg:SetInputValue).tp = "set_input_value";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.value = r[0]; p = r[1];
|
||||
r = readInt(buf, p); msg.mask = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 19:
|
||||
(msg:SetInputChecked).tp = "set_input_checked";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readBoolean(buf, p); msg.checked = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 20:
|
||||
(msg:MouseMove).tp = "mouse_move";
|
||||
r = readUint(buf, p); msg.x = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.y = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 22:
|
||||
(msg:ConsoleLog).tp = "console_log";
|
||||
r = readString(buf, p); msg.level = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.value = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 49:
|
||||
(msg:PerformanceTrack).tp = "performance_track";
|
||||
r = readInt(buf, p); msg.frames = r[0]; p = r[1];
|
||||
r = readInt(buf, p); msg.ticks = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.totalJSHeapSize = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.usedJSHeapSize = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 54:
|
||||
(msg:ConnectionInformation).tp = "connection_information";
|
||||
r = readUint(buf, p); msg.downlink = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.type = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 55:
|
||||
(msg:SetPageVisibility).tp = "set_page_visibility";
|
||||
r = readBoolean(buf, p); msg.hidden = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 37:
|
||||
(msg:CssInsertRule).tp = "css_insert_rule";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.rule = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.index = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 38:
|
||||
(msg:CssDeleteRule).tp = "css_delete_rule";
|
||||
r = readUint(buf, p); msg.id = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.index = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 39:
|
||||
(msg:Fetch).tp = "fetch";
|
||||
r = readString(buf, p); msg.method = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.url = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.request = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.response = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.status = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.duration = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 40:
|
||||
(msg:Profiler).tp = "profiler";
|
||||
r = readString(buf, p); msg.name = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.duration = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.args = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.result = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 41:
|
||||
(msg:OTable).tp = "o_table";
|
||||
r = readString(buf, p); msg.key = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.value = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 44:
|
||||
(msg:Redux).tp = "redux";
|
||||
r = readString(buf, p); msg.action = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.state = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.duration = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 45:
|
||||
(msg:Vuex).tp = "vuex";
|
||||
r = readString(buf, p); msg.mutation = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.state = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 46:
|
||||
(msg:MobX).tp = "mob_x";
|
||||
r = readString(buf, p); msg.type = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.payload = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 47:
|
||||
(msg:NgRx).tp = "ng_rx";
|
||||
r = readString(buf, p); msg.action = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.state = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.duration = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 48:
|
||||
(msg:GraphQl).tp = "graph_ql";
|
||||
r = readString(buf, p); msg.operationKind = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.operationName = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.variables = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.response = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 59:
|
||||
(msg:LongTask).tp = "long_task";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.duration = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.context = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.containerType = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.containerSrc = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.containerId = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.containerName = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 63:
|
||||
(msg:TechnicalInfo).tp = "technical_info";
|
||||
r = readString(buf, p); msg.type = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.value = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 90:
|
||||
(msg:IosSessionStart).tp = "ios_session_start";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.projectID = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.trackerVersion = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.revID = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.userUUID = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.userOS = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.userOSVersion = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.userDevice = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.userDeviceType = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.userCountry = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 93:
|
||||
(msg:IosCustomEvent).tp = "ios_custom_event";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.length = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.name = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.payload = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 100:
|
||||
(msg:IosClickEvent).tp = "ios_click_event";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.length = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.label = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.x = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.y = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 102:
|
||||
(msg:IosPerformanceEvent).tp = "ios_performance_event";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.length = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.name = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.value = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 103:
|
||||
(msg:IosLog).tp = "ios_log";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.length = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.severity = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.content = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
case 105:
|
||||
(msg:IosNetworkCall).tp = "ios_network_call";
|
||||
r = readUint(buf, p); msg.timestamp = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.length = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.duration = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.headers = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.body = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.url = r[0]; p = r[1];
|
||||
r = readBoolean(buf, p); msg.success = r[0]; p = r[1];
|
||||
r = readString(buf, p); msg.method = r[0]; p = r[1];
|
||||
r = readUint(buf, p); msg.status = r[0]; p = r[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
let len;
|
||||
[ _, p ] = readUint(buf, p);
|
||||
[ len, p ] = readUint(buf, p);
|
||||
return [null, p + len] // skip
|
||||
//throw `Unknown type (${buf[p-1]})`;
|
||||
}
|
||||
return [msg, p];
|
||||
}
|
||||
543
frontend/app/player/MessageDistributor/messages.ts
Normal file
543
frontend/app/player/MessageDistributor/messages.ts
Normal file
|
|
@ -0,0 +1,543 @@
|
|||
// Auto-generated, do not edit
|
||||
|
||||
import PrimitiveReader from './PrimitiveReader';
|
||||
|
||||
export const ID_TP_MAP = {
|
||||
|
||||
0: "timestamp",
|
||||
4: "set_page_location",
|
||||
5: "set_viewport_size",
|
||||
6: "set_viewport_scroll",
|
||||
7: "create_document",
|
||||
8: "create_element_node",
|
||||
9: "create_text_node",
|
||||
10: "move_node",
|
||||
11: "remove_node",
|
||||
12: "set_node_attribute",
|
||||
13: "remove_node_attribute",
|
||||
14: "set_node_data",
|
||||
15: "set_css_data",
|
||||
16: "set_node_scroll",
|
||||
18: "set_input_value",
|
||||
19: "set_input_checked",
|
||||
20: "mouse_move",
|
||||
22: "console_log",
|
||||
37: "css_insert_rule",
|
||||
38: "css_delete_rule",
|
||||
39: "fetch_depricated",
|
||||
40: "profiler",
|
||||
41: "o_table",
|
||||
44: "redux",
|
||||
45: "vuex",
|
||||
46: "mob_x",
|
||||
47: "ng_rx",
|
||||
48: "graph_ql",
|
||||
49: "performance_track",
|
||||
54: "connection_information",
|
||||
55: "set_page_visibility",
|
||||
59: "long_task",
|
||||
68: "fetch",
|
||||
} as const;
|
||||
|
||||
|
||||
export interface Timestamp {
|
||||
tp: "timestamp",
|
||||
timestamp: number,
|
||||
}
|
||||
|
||||
export interface SetPageLocation {
|
||||
tp: "set_page_location",
|
||||
url: string,
|
||||
referrer: string,
|
||||
navigationStart: number,
|
||||
}
|
||||
|
||||
export interface SetViewportSize {
|
||||
tp: "set_viewport_size",
|
||||
width: number,
|
||||
height: number,
|
||||
}
|
||||
|
||||
export interface SetViewportScroll {
|
||||
tp: "set_viewport_scroll",
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
export interface CreateDocument {
|
||||
tp: "create_document",
|
||||
|
||||
}
|
||||
|
||||
export interface CreateElementNode {
|
||||
tp: "create_element_node",
|
||||
id: number,
|
||||
parentID: number,
|
||||
index: number,
|
||||
tag: string,
|
||||
svg: boolean,
|
||||
}
|
||||
|
||||
export interface CreateTextNode {
|
||||
tp: "create_text_node",
|
||||
id: number,
|
||||
parentID: number,
|
||||
index: number,
|
||||
}
|
||||
|
||||
export interface MoveNode {
|
||||
tp: "move_node",
|
||||
id: number,
|
||||
parentID: number,
|
||||
index: number,
|
||||
}
|
||||
|
||||
export interface RemoveNode {
|
||||
tp: "remove_node",
|
||||
id: number,
|
||||
}
|
||||
|
||||
export interface SetNodeAttribute {
|
||||
tp: "set_node_attribute",
|
||||
id: number,
|
||||
name: string,
|
||||
value: string,
|
||||
}
|
||||
|
||||
export interface RemoveNodeAttribute {
|
||||
tp: "remove_node_attribute",
|
||||
id: number,
|
||||
name: string,
|
||||
}
|
||||
|
||||
export interface SetNodeData {
|
||||
tp: "set_node_data",
|
||||
id: number,
|
||||
data: string,
|
||||
}
|
||||
|
||||
export interface SetCssData {
|
||||
tp: "set_css_data",
|
||||
id: number,
|
||||
data: string,
|
||||
}
|
||||
|
||||
export interface SetNodeScroll {
|
||||
tp: "set_node_scroll",
|
||||
id: number,
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
export interface SetInputValue {
|
||||
tp: "set_input_value",
|
||||
id: number,
|
||||
value: string,
|
||||
mask: number,
|
||||
}
|
||||
|
||||
export interface SetInputChecked {
|
||||
tp: "set_input_checked",
|
||||
id: number,
|
||||
checked: boolean,
|
||||
}
|
||||
|
||||
export interface MouseMove {
|
||||
tp: "mouse_move",
|
||||
x: number,
|
||||
y: number,
|
||||
}
|
||||
|
||||
export interface ConsoleLog {
|
||||
tp: "console_log",
|
||||
level: string,
|
||||
value: string,
|
||||
}
|
||||
|
||||
export interface CssInsertRule {
|
||||
tp: "css_insert_rule",
|
||||
id: number,
|
||||
rule: string,
|
||||
index: number,
|
||||
}
|
||||
|
||||
export interface CssDeleteRule {
|
||||
tp: "css_delete_rule",
|
||||
id: number,
|
||||
index: number,
|
||||
}
|
||||
|
||||
export interface FetchDepricated {
|
||||
tp: "fetch_depricated",
|
||||
method: string,
|
||||
url: string,
|
||||
request: string,
|
||||
response: string,
|
||||
status: number,
|
||||
timestamp: number,
|
||||
duration: number,
|
||||
}
|
||||
|
||||
export interface Profiler {
|
||||
tp: "profiler",
|
||||
name: string,
|
||||
duration: number,
|
||||
args: string,
|
||||
result: string,
|
||||
}
|
||||
|
||||
export interface OTable {
|
||||
tp: "o_table",
|
||||
key: string,
|
||||
value: string,
|
||||
}
|
||||
|
||||
export interface Redux {
|
||||
tp: "redux",
|
||||
action: string,
|
||||
state: string,
|
||||
duration: number,
|
||||
}
|
||||
|
||||
export interface Vuex {
|
||||
tp: "vuex",
|
||||
mutation: string,
|
||||
state: string,
|
||||
}
|
||||
|
||||
export interface MobX {
|
||||
tp: "mob_x",
|
||||
type: string,
|
||||
payload: string,
|
||||
}
|
||||
|
||||
export interface NgRx {
|
||||
tp: "ng_rx",
|
||||
action: string,
|
||||
state: string,
|
||||
duration: number,
|
||||
}
|
||||
|
||||
export interface GraphQl {
|
||||
tp: "graph_ql",
|
||||
operationKind: string,
|
||||
operationName: string,
|
||||
variables: string,
|
||||
response: string,
|
||||
}
|
||||
|
||||
export interface PerformanceTrack {
|
||||
tp: "performance_track",
|
||||
frames: number,
|
||||
ticks: number,
|
||||
totalJSHeapSize: number,
|
||||
usedJSHeapSize: number,
|
||||
}
|
||||
|
||||
export interface ConnectionInformation {
|
||||
tp: "connection_information",
|
||||
downlink: number,
|
||||
type: string,
|
||||
}
|
||||
|
||||
export interface SetPageVisibility {
|
||||
tp: "set_page_visibility",
|
||||
hidden: boolean,
|
||||
}
|
||||
|
||||
export interface LongTask {
|
||||
tp: "long_task",
|
||||
timestamp: number,
|
||||
duration: number,
|
||||
context: number,
|
||||
containerType: number,
|
||||
containerSrc: string,
|
||||
containerId: string,
|
||||
containerName: string,
|
||||
}
|
||||
|
||||
export interface Fetch {
|
||||
tp: "fetch",
|
||||
method: string,
|
||||
url: string,
|
||||
request: string,
|
||||
response: string,
|
||||
status: number,
|
||||
timestamp: number,
|
||||
duration: number,
|
||||
headers: string,
|
||||
}
|
||||
|
||||
|
||||
export type Message = Timestamp | SetPageLocation | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetCssData | SetNodeScroll | SetInputValue | SetInputChecked | MouseMove | ConsoleLog | CssInsertRule | CssDeleteRule | FetchDepricated | Profiler | OTable | Redux | Vuex | MobX | NgRx | GraphQl | PerformanceTrack | ConnectionInformation | SetPageVisibility | LongTask | Fetch;
|
||||
|
||||
export default function (r: PrimitiveReader): Message | null {
|
||||
switch (r.readUint()) {
|
||||
|
||||
case 0:
|
||||
return {
|
||||
tp: ID_TP_MAP[0],
|
||||
timestamp: r.readUint(),
|
||||
};
|
||||
|
||||
case 4:
|
||||
return {
|
||||
tp: ID_TP_MAP[4],
|
||||
url: r.readString(),
|
||||
referrer: r.readString(),
|
||||
navigationStart: r.readUint(),
|
||||
};
|
||||
|
||||
case 5:
|
||||
return {
|
||||
tp: ID_TP_MAP[5],
|
||||
width: r.readUint(),
|
||||
height: r.readUint(),
|
||||
};
|
||||
|
||||
case 6:
|
||||
return {
|
||||
tp: ID_TP_MAP[6],
|
||||
x: r.readInt(),
|
||||
y: r.readInt(),
|
||||
};
|
||||
|
||||
case 7:
|
||||
return {
|
||||
tp: ID_TP_MAP[7],
|
||||
|
||||
};
|
||||
|
||||
case 8:
|
||||
return {
|
||||
tp: ID_TP_MAP[8],
|
||||
id: r.readUint(),
|
||||
parentID: r.readUint(),
|
||||
index: r.readUint(),
|
||||
tag: r.readString(),
|
||||
svg: r.readBoolean(),
|
||||
};
|
||||
|
||||
case 9:
|
||||
return {
|
||||
tp: ID_TP_MAP[9],
|
||||
id: r.readUint(),
|
||||
parentID: r.readUint(),
|
||||
index: r.readUint(),
|
||||
};
|
||||
|
||||
case 10:
|
||||
return {
|
||||
tp: ID_TP_MAP[10],
|
||||
id: r.readUint(),
|
||||
parentID: r.readUint(),
|
||||
index: r.readUint(),
|
||||
};
|
||||
|
||||
case 11:
|
||||
return {
|
||||
tp: ID_TP_MAP[11],
|
||||
id: r.readUint(),
|
||||
};
|
||||
|
||||
case 12:
|
||||
return {
|
||||
tp: ID_TP_MAP[12],
|
||||
id: r.readUint(),
|
||||
name: r.readString(),
|
||||
value: r.readString(),
|
||||
};
|
||||
|
||||
case 13:
|
||||
return {
|
||||
tp: ID_TP_MAP[13],
|
||||
id: r.readUint(),
|
||||
name: r.readString(),
|
||||
};
|
||||
|
||||
case 14:
|
||||
return {
|
||||
tp: ID_TP_MAP[14],
|
||||
id: r.readUint(),
|
||||
data: r.readString(),
|
||||
};
|
||||
|
||||
case 15:
|
||||
return {
|
||||
tp: ID_TP_MAP[15],
|
||||
id: r.readUint(),
|
||||
data: r.readString(),
|
||||
};
|
||||
|
||||
case 16:
|
||||
return {
|
||||
tp: ID_TP_MAP[16],
|
||||
id: r.readUint(),
|
||||
x: r.readInt(),
|
||||
y: r.readInt(),
|
||||
};
|
||||
|
||||
case 18:
|
||||
return {
|
||||
tp: ID_TP_MAP[18],
|
||||
id: r.readUint(),
|
||||
value: r.readString(),
|
||||
mask: r.readInt(),
|
||||
};
|
||||
|
||||
case 19:
|
||||
return {
|
||||
tp: ID_TP_MAP[19],
|
||||
id: r.readUint(),
|
||||
checked: r.readBoolean(),
|
||||
};
|
||||
|
||||
case 20:
|
||||
return {
|
||||
tp: ID_TP_MAP[20],
|
||||
x: r.readUint(),
|
||||
y: r.readUint(),
|
||||
};
|
||||
|
||||
case 22:
|
||||
return {
|
||||
tp: ID_TP_MAP[22],
|
||||
level: r.readString(),
|
||||
value: r.readString(),
|
||||
};
|
||||
|
||||
case 37:
|
||||
return {
|
||||
tp: ID_TP_MAP[37],
|
||||
id: r.readUint(),
|
||||
rule: r.readString(),
|
||||
index: r.readUint(),
|
||||
};
|
||||
|
||||
case 38:
|
||||
return {
|
||||
tp: ID_TP_MAP[38],
|
||||
id: r.readUint(),
|
||||
index: r.readUint(),
|
||||
};
|
||||
|
||||
case 39:
|
||||
return {
|
||||
tp: ID_TP_MAP[39],
|
||||
method: r.readString(),
|
||||
url: r.readString(),
|
||||
request: r.readString(),
|
||||
response: r.readString(),
|
||||
status: r.readUint(),
|
||||
timestamp: r.readUint(),
|
||||
duration: r.readUint(),
|
||||
};
|
||||
|
||||
case 40:
|
||||
return {
|
||||
tp: ID_TP_MAP[40],
|
||||
name: r.readString(),
|
||||
duration: r.readUint(),
|
||||
args: r.readString(),
|
||||
result: r.readString(),
|
||||
};
|
||||
|
||||
case 41:
|
||||
return {
|
||||
tp: ID_TP_MAP[41],
|
||||
key: r.readString(),
|
||||
value: r.readString(),
|
||||
};
|
||||
|
||||
case 44:
|
||||
return {
|
||||
tp: ID_TP_MAP[44],
|
||||
action: r.readString(),
|
||||
state: r.readString(),
|
||||
duration: r.readUint(),
|
||||
};
|
||||
|
||||
case 45:
|
||||
return {
|
||||
tp: ID_TP_MAP[45],
|
||||
mutation: r.readString(),
|
||||
state: r.readString(),
|
||||
};
|
||||
|
||||
case 46:
|
||||
return {
|
||||
tp: ID_TP_MAP[46],
|
||||
type: r.readString(),
|
||||
payload: r.readString(),
|
||||
};
|
||||
|
||||
case 47:
|
||||
return {
|
||||
tp: ID_TP_MAP[47],
|
||||
action: r.readString(),
|
||||
state: r.readString(),
|
||||
duration: r.readUint(),
|
||||
};
|
||||
|
||||
case 48:
|
||||
return {
|
||||
tp: ID_TP_MAP[48],
|
||||
operationKind: r.readString(),
|
||||
operationName: r.readString(),
|
||||
variables: r.readString(),
|
||||
response: r.readString(),
|
||||
};
|
||||
|
||||
case 49:
|
||||
return {
|
||||
tp: ID_TP_MAP[49],
|
||||
frames: r.readInt(),
|
||||
ticks: r.readInt(),
|
||||
totalJSHeapSize: r.readUint(),
|
||||
usedJSHeapSize: r.readUint(),
|
||||
};
|
||||
|
||||
case 54:
|
||||
return {
|
||||
tp: ID_TP_MAP[54],
|
||||
downlink: r.readUint(),
|
||||
type: r.readString(),
|
||||
};
|
||||
|
||||
case 55:
|
||||
return {
|
||||
tp: ID_TP_MAP[55],
|
||||
hidden: r.readBoolean(),
|
||||
};
|
||||
|
||||
case 59:
|
||||
return {
|
||||
tp: ID_TP_MAP[59],
|
||||
timestamp: r.readUint(),
|
||||
duration: r.readUint(),
|
||||
context: r.readUint(),
|
||||
containerType: r.readUint(),
|
||||
containerSrc: r.readString(),
|
||||
containerId: r.readString(),
|
||||
containerName: r.readString(),
|
||||
};
|
||||
|
||||
case 68:
|
||||
return {
|
||||
tp: ID_TP_MAP[68],
|
||||
method: r.readString(),
|
||||
url: r.readString(),
|
||||
request: r.readString(),
|
||||
response: r.readString(),
|
||||
status: r.readUint(),
|
||||
timestamp: r.readUint(),
|
||||
duration: r.readUint(),
|
||||
headers: r.readString(),
|
||||
};
|
||||
|
||||
default:
|
||||
r.readUint(); // IOS skip timestamp
|
||||
r.skip(r.readUint());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
export function readUint(buf, p) {
|
||||
var r = 0, s = 1, b;
|
||||
do {
|
||||
b = buf[p++];
|
||||
r += (b & 0x7F) * s;
|
||||
s *= 128;
|
||||
} while (b >= 0x80)
|
||||
return [r, p];
|
||||
}
|
||||
|
||||
export function readInt(buf, p) {
|
||||
var r = readUint(buf, p);
|
||||
if (r[0] % 2) {
|
||||
r[0] = (r[0] + 1) / -2;
|
||||
} else {
|
||||
r[0] = r[0] / 2;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
export function readString(buf, p) {
|
||||
var r = readUint(buf, p);
|
||||
var f = r[1];
|
||||
r[1] += r[0];
|
||||
r[0] = new TextDecoder().decode(buf.subarray(f, r[1]));
|
||||
return r;
|
||||
}
|
||||
|
||||
export function readBoolean(buf, p) {
|
||||
return [!!buf[p], p+1];
|
||||
}
|
||||
|
|
@ -7,12 +7,16 @@ const performance = window.performance || { now: Date.now.bind(Date) };
|
|||
const requestAnimationFrame =
|
||||
window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
// @ts-ignore
|
||||
window.mozRequestAnimationFrame ||
|
||||
// @ts-ignore
|
||||
window.oRequestAnimationFrame ||
|
||||
// @ts-ignore
|
||||
window.msRequestAnimationFrame ||
|
||||
(callback => window.setTimeout(() => { callback(performance.now()); }, 1000 / fps));
|
||||
const cancelAnimationFrame =
|
||||
window.cancelAnimationFrame ||
|
||||
// @ts-ignore
|
||||
window.mozCancelAnimationFrame ||
|
||||
window.clearTimeout;
|
||||
|
||||
|
|
@ -23,7 +27,7 @@ const SPEED_STORAGE_KEY = "__$player-speed$__";
|
|||
const SKIP_STORAGE_KEY = "__$player-skip$__";
|
||||
const SKIP_TO_ISSUE_STORAGE_KEY = "__$player-skip-to-issue$__";
|
||||
const AUTOPLAY_STORAGE_KEY = "__$player-autoplay$__";
|
||||
const storedSpeed = +localStorage.getItem(SPEED_STORAGE_KEY);
|
||||
const storedSpeed: number = parseInt(localStorage.getItem(SPEED_STORAGE_KEY) || "") ;
|
||||
const initialSpeed = [1,2,3].includes(storedSpeed) ? storedSpeed : 1;
|
||||
const initialSkip = !!localStorage.getItem(SKIP_STORAGE_KEY);
|
||||
const initialSkipToIssue = !!localStorage.getItem(SKIP_TO_ISSUE_STORAGE_KEY);
|
||||
|
|
@ -48,18 +52,18 @@ export const INITIAL_NON_RESETABLE_STATE = {
|
|||
}
|
||||
|
||||
export default class Player extends MessageDistributor {
|
||||
_animationFrameRequestId = null;
|
||||
private _animationFrameRequestId: number = 0;
|
||||
|
||||
_setTime(time, index) {
|
||||
private _setTime(time: number, index?: number) {
|
||||
update({
|
||||
time,
|
||||
completed: false,
|
||||
});
|
||||
this.move(time, index);
|
||||
super.move(time, index);
|
||||
listsGoTo(time, index);
|
||||
}
|
||||
|
||||
_startAnimation() {
|
||||
private _startAnimation() {
|
||||
let prevTime = getState().time;
|
||||
let animationPrevTime = performance.now();
|
||||
|
||||
|
|
@ -86,10 +90,10 @@ export default class Player extends MessageDistributor {
|
|||
const skipInterval = skip && skipIntervals.find(si => si.contains(time)); // TODO: good skip by messages
|
||||
if (skipInterval) time = skipInterval.end;
|
||||
|
||||
const fmt = this.getFirstMessageTime();
|
||||
const fmt = super.getFirstMessageTime();
|
||||
if (time < fmt) time = fmt; // ?
|
||||
|
||||
const lmt = this.getLastMessageTime();
|
||||
const lmt = super.getLastMessageTime();
|
||||
if (livePlay && time < lmt) time = lmt;
|
||||
if (endTime < lmt) {
|
||||
update({
|
||||
|
|
@ -161,7 +165,7 @@ export default class Player extends MessageDistributor {
|
|||
|
||||
toggleSkip() {
|
||||
const skip = !getState().skip;
|
||||
localStorage.setItem(SKIP_STORAGE_KEY, skip);
|
||||
localStorage.setItem(SKIP_STORAGE_KEY, `${skip}`);
|
||||
update({ skip });
|
||||
}
|
||||
|
||||
|
|
@ -174,27 +178,27 @@ export default class Player extends MessageDistributor {
|
|||
if (flag) {
|
||||
this.pause();
|
||||
update({ inspectorMode: true });
|
||||
return this.enableInspector(clickCallback);
|
||||
return super.enableInspector(clickCallback);
|
||||
} else {
|
||||
this.disableInspector();
|
||||
super.disableInspector();
|
||||
update({ inspectorMode: false });
|
||||
}
|
||||
}
|
||||
|
||||
toggleSkipToIssue() {
|
||||
const skipToIssue = !getState().skipToIssue;
|
||||
localStorage.setItem(SKIP_TO_ISSUE_STORAGE_KEY, skipToIssue);
|
||||
localStorage.setItem(SKIP_TO_ISSUE_STORAGE_KEY, `${skipToIssue}`);
|
||||
update({ skipToIssue });
|
||||
}
|
||||
|
||||
toggleAutoplay() {
|
||||
const autoplay = !getState().autoplay;
|
||||
localStorage.setItem(AUTOPLAY_STORAGE_KEY, autoplay);
|
||||
localStorage.setItem(AUTOPLAY_STORAGE_KEY, `${autoplay}`);
|
||||
update({ autoplay });
|
||||
}
|
||||
|
||||
_updateSpeed(speed) {
|
||||
localStorage.setItem(SPEED_STORAGE_KEY, speed);
|
||||
_updateSpeed(speed: number) {
|
||||
localStorage.setItem(SPEED_STORAGE_KEY, `${speed}`);
|
||||
update({ speed });
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +67,7 @@ export const attach = initCheck((...args) => instance.attach(...args));
|
|||
export const markElement = initCheck((...args) => instance.marker && instance.marker.mark(...args));
|
||||
export const scale = initCheck(() => instance.scale());
|
||||
export const toggleInspectorMode = initCheck((...args) => instance.toggleInspectorMode(...args));
|
||||
export const callPeer = initCheck((...args) => instance.callPeer(...args))
|
||||
|
||||
export const Controls = {
|
||||
jump,
|
||||
|
|
|
|||
50
frontend/package-lock.json
generated
50
frontend/package-lock.json
generated
|
|
@ -16089,6 +16089,34 @@
|
|||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"peerjs": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/peerjs/-/peerjs-1.3.2.tgz",
|
||||
"integrity": "sha512-+PHfmsC7QGUU8Ye3OLi6tKQZGPCNy7QatUVNw4JtE8alkguF3+DdO5W0bzepqP2OtE9FqH/ltXt37qyvHw2CqA==",
|
||||
"requires": {
|
||||
"@types/node": "^10.14.33",
|
||||
"eventemitter3": "^3.1.2",
|
||||
"peerjs-js-binarypack": "1.0.1",
|
||||
"webrtc-adapter": "^7.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "10.17.60",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
|
||||
"integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="
|
||||
},
|
||||
"eventemitter3": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
|
||||
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"peerjs-js-binarypack": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/peerjs-js-binarypack/-/peerjs-js-binarypack-1.0.1.tgz",
|
||||
"integrity": "sha512-N6aeia3NhdpV7kiGxJV5xQiZZCVEEVjRz2T2C6UZQiBkHWHzUv/oWA4myQLcwBwO8LUoR1KWW5oStvwVesmfCg=="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
|
|
@ -21695,6 +21723,14 @@
|
|||
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
|
||||
"dev": true
|
||||
},
|
||||
"rtcpeerconnection-shim": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz",
|
||||
"integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==",
|
||||
"requires": {
|
||||
"sdp": "^2.6.0"
|
||||
}
|
||||
},
|
||||
"run-async": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||
|
|
@ -21876,6 +21912,11 @@
|
|||
"ajv-keywords": "^3.5.2"
|
||||
}
|
||||
},
|
||||
"sdp": {
|
||||
"version": "2.12.0",
|
||||
"resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz",
|
||||
"integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw=="
|
||||
},
|
||||
"select": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
|
||||
|
|
@ -25876,6 +25917,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"webrtc-adapter": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz",
|
||||
"integrity": "sha512-TbrbBmiQBL9n0/5bvDdORc6ZfRY/Z7JnEj+EYOD1ghseZdpJ+nF2yx14k3LgQKc7JZnG7HAcL+zHnY25So9d7A==",
|
||||
"requires": {
|
||||
"rtcpeerconnection-shim": "^1.2.15",
|
||||
"sdp": "^2.12.0"
|
||||
}
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
"moment": "^2.27.0",
|
||||
"moment-range": "^4.0.2",
|
||||
"optimal-select": "^4.0.1",
|
||||
"peerjs": "^1.3.2",
|
||||
"rc-time-picker": "^3.7.3",
|
||||
"react": "^16.13.1",
|
||||
"react-circular-progressbar": "^2.0.3",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "es2015",
|
||||
"module": "es2020",
|
||||
"moduleResolution": "node", //?
|
||||
//"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
|
|
@ -13,7 +13,9 @@
|
|||
"incremental": true,
|
||||
"baseUrl": ".",
|
||||
"paths": { // TODO: one-source truth
|
||||
"App": ["./app"],
|
||||
"Appo": ["./app"],
|
||||
"Types": ["./app/types" ],
|
||||
"Types/*": ["./app/types/*"], // Sublime hack
|
||||
"UI": ["./app/components/ui"]
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue