// M4 on a live server F: how large the shared document of the largest example // is, and how many updates dragging a device makes. Mia drags a device in a // real browser for two seconds at 60 pointer moves a second (as a finger or // a mouse does); a second person, watching through /sync, counts the updates // that arrive and their bytes. Then the document's size as F holds it: fresh, // after the drags, and as one update (what a new person loads). // // npx vite-node tools/live/m4.ts import * as Y from 'yjs'; import { chromium } from '@playwright/test'; import { onDevice } from '../../packages/editor/browser/editorPage.js'; import { cleanUp, joinDoc, seededProject, signIn, signInAddress } from './lib.js'; const EXAMPLE = 'java-examples/Internet_Komplett_mit_eMail_Webserver_Intranet_Portforwarding_Firewall_DHCP_DE.fls'; const MOVES_PER_SECOND = 60; const SECONDS = 2; const browser = await chromium.launch(); try { const { project, example } = await seededProject(EXAMPLE); const watcher = await joinDoc(project, await signIn(project, { name: 'Zuschauer' })); console.log(`fresh document: ${Y.encodeStateAsUpdate(watcher.doc).length} bytes, ${example.graph.nodes.length} devices, ${example.graph.links.length} cables`); const page = await (await browser.newContext({ viewport: { width: 1400, height: 900 } })).newPage(); await page.goto(signInAddress(project, { name: 'Mia' })); await page.waitForSelector('svg.filius-canvas'); const arrivals: { at: number; bytes: number }[] = []; watcher.doc.on('update', (update: Uint8Array, origin: unknown) => { if (origin !== null && typeof origin === 'object') arrivals.push({ at: performance.now(), bytes: update.length }); }); for (const name of ['Heimrouter', 'webserver.de (120.130.140.80)', 'iPad 1']) { arrivals.length = 0; const from = await onDevice(page, example.graph.nodes.find((node) => node.displayName === name)!.id); await page.mouse.move(from.x, from.y); await page.mouse.down(); const start = performance.now(); const moves = MOVES_PER_SECOND * SECONDS; for (let step = 1; step <= moves; step++) { await page.mouse.move(from.x + 150 * Math.sin((step / moves) * Math.PI), from.y + 80 * (step / moves)); const due = start + (step * 1000) / MOVES_PER_SECOND; await new Promise((resolve) => setTimeout(resolve, Math.max(0, due - performance.now()))); } await page.mouse.up(); const dragged = (performance.now() - start) / 1000; await new Promise((resolve) => setTimeout(resolve, 1500)); const bytes = arrivals.reduce((sum, each) => sum + each.bytes, 0); console.log( `drag ${name.padEnd(30)} ${dragged.toFixed(1)} s: ${arrivals.length} updates (${(arrivals.length / dragged).toFixed(0)}/s), ${bytes} bytes, ${(bytes / Math.max(1, arrivals.length)).toFixed(0)} per update`, ); } console.log(`after the drags: ${Y.encodeStateAsUpdate(watcher.doc).length} bytes as one update`); const fresh = await joinDoc(project, await signIn(project, { name: 'Neu' })); console.log(`a new person loads: ${Y.encodeStateAsUpdate(fresh.doc).length} bytes`); fresh.close(); watcher.close(); } finally { await browser.close(); await cleanUp(); }