move stitching calculation to server side
This commit is contained in:
@@ -4,24 +4,6 @@ import { useEffect, useRef, useState } from 'react';
|
||||
import { useMobile } from '@/components/hooks';
|
||||
import 'rrweb-player/dist/style.css';
|
||||
|
||||
function normalizeEvents(events: any[], maxGapMs = 60_000): any[] {
|
||||
if (events.length < 2) return events;
|
||||
|
||||
const sorted = [...events].sort((a, b) => a.timestamp - b.timestamp);
|
||||
let shift = 0;
|
||||
const result: any[] = [sorted[0]];
|
||||
|
||||
for (let i = 1; i < sorted.length; i++) {
|
||||
const gap = sorted[i].timestamp - sorted[i - 1].timestamp;
|
||||
if (gap > maxGapMs) {
|
||||
shift += gap - 1000;
|
||||
}
|
||||
result.push(shift > 0 ? { ...sorted[i], timestamp: sorted[i].timestamp - shift } : sorted[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function ReplayPlayer({ events }: { events: any[] }) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const playerRef = useRef<any>(null);
|
||||
@@ -44,7 +26,7 @@ export function ReplayPlayer({ events }: { events: any[] }) {
|
||||
playerRef.current = new RRWebPlayer({
|
||||
target: containerRef.current,
|
||||
props: {
|
||||
events: normalizeEvents(events),
|
||||
events: events,
|
||||
width: playerWidth,
|
||||
height: playerHeight,
|
||||
autoPlay: false,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { stitchChunkEvents } from '@/lib/replay';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { json, unauthorized } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/permissions';
|
||||
@@ -21,7 +22,7 @@ export async function GET(
|
||||
|
||||
const chunks = await getReplayChunks(websiteId, sessionId);
|
||||
|
||||
const allEvents = chunks.flatMap(chunk => chunk.events);
|
||||
const allEvents = stitchChunkEvents(chunks);
|
||||
const startedAt = chunks.length > 0 ? chunks[0].startedAt : null;
|
||||
const endedAt = chunks.length > 0 ? chunks[chunks.length - 1].endedAt : null;
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { ReplayChunk } from '@/queries/sql';
|
||||
|
||||
export function stitchChunkEvents(chunks: ReplayChunk[]): any[] {
|
||||
if (!chunks.length) return [];
|
||||
const sorted = [...chunks].sort((a, b) => a.startedAt.getTime() - b.startedAt.getTime());
|
||||
const result: any[] = [];
|
||||
let timeOffset = 0;
|
||||
for (const chunk of sorted) {
|
||||
const chunkStartMs = chunk.startedAt.getTime();
|
||||
const events = [...chunk.events].sort((a, b) => a.timestamp - b.timestamp);
|
||||
for (const event of events) {
|
||||
result.push({ ...event, timestamp: timeOffset + (event.timestamp - chunkStartMs) });
|
||||
}
|
||||
timeOffset += chunk.endedAt.getTime() - chunkStartMs + 1000;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
|
||||
count(sr.replay_id) as "chunkCount",
|
||||
min(sr.started_at) as "startedAt",
|
||||
max(sr.ended_at) as "endedAt",
|
||||
(extract(epoch from max(sr.ended_at) - min(sr.started_at)) * 1000)::bigint as "duration",
|
||||
sum(extract(epoch from sr.ended_at - sr.started_at) * 1000)::bigint as "duration",
|
||||
max(sr.created_at) as "createdAt"
|
||||
from session_replay sr
|
||||
join session on session.session_id = sr.session_id
|
||||
@@ -109,7 +109,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters) {
|
||||
count(session_replay.replay_id) as chunkCount,
|
||||
min(session_replay.started_at) as startedAt,
|
||||
max(session_replay.ended_at) as endedAt,
|
||||
toInt64(dateDiff('millisecond', min(session_replay.started_at), max(session_replay.ended_at))) as duration,
|
||||
toInt64(sum(dateDiff('millisecond', session_replay.started_at, session_replay.ended_at))) as duration,
|
||||
max(session_replay.created_at) as createdAt
|
||||
from session_replay
|
||||
join (
|
||||
|
||||
Reference in New Issue
Block a user