snapshot of https://github.com/raimohanska/ourboard.git (master, 2026-09-23; blobs > 131072B omitted)
Some checks failed
build / test (18.x) (push) Failing after 10s
build / lint (18.x) (push) Failing after 0s
build / docker-image (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-23 16:16:17 +05:00
commit d57328655f
233 changed files with 21282 additions and 0 deletions

1
perf-tester/README.md Normal file
View File

@@ -0,0 +1 @@
Ourboard perftester. `yarn dev`. See src/index.ts for supported ENV vars.

42
perf-tester/package.json Normal file
View File

@@ -0,0 +1,42 @@
{
"name": "rboard-perf-tester",
"version": "1.0.0",
"main": "dist/perf-tester/src/index.js",
"license": "MIT",
"dependencies": {
"@types/cookie": "^0.4.0",
"@types/email-validator": "^1.0.6",
"@types/lodash": "^4.14.161",
"@types/md5": "^2.2.1",
"@types/node-fetch": "^2.5.9",
"@types/pretty-ms": "^5.0.1",
"cookie": "^0.4.1",
"email-validator": "^2.0.4",
"harmaja": "^0.24",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.20",
"lonna": "^0.12.2",
"material-design-icons-iconfont": "^6.1.0",
"md5": "^2.3.0",
"node-fetch": "^2.6.1",
"pretty-ms": "^7.0.1",
"uuid": "^8.3.0",
"ws": "^7.4.4"
},
"scripts": {
"watch": "tsc --watch --noEmit",
"build": "tsc",
"start": "node .",
"create-boards": "tsx src/create-boards.ts",
"dev": "tsc-watch --onSuccess \"node .\" --preserveWatchOutput"
},
"devDependencies": {
"@types/jsonwebtoken": "^8.5.0",
"@types/uuid": "^8.3.0",
"cssnano": "^4.1.10",
"nodemon": "^2.0.4",
"npm-run-all": "^4.1.5",
"tsc-watch": "^4.2.9",
"typescript": "^4.0.2"
}
}

View File

@@ -0,0 +1,24 @@
import fetch from "node-fetch"
import _ from "lodash"
const BOARD_COUNT = parseInt(process.env.BOARD_COUNT || "1")
const DOMAIN = process.env.DOMAIN
const API_ROOT = `${DOMAIN ? "https" : "http"}://${DOMAIN ?? "localhost:1337"}`
const CREATE_BOARD_API = `${API_ROOT}/api/v1/board`
async function createBoardAndReturnId(n: number) {
const result = await fetch(CREATE_BOARD_API, {
method: "POST",
body: JSON.stringify({ name: "perftest" + n }),
headers: {
"content-type": "application/json",
},
})
const body = await result.json()
return body.id as string
}
const promises = _.range(1, BOARD_COUNT + 1).map(createBoardAndReturnId)
Promise.all(promises).then((ids) => {
console.log(ids.join(","))
})

170
perf-tester/src/index.ts Normal file
View File

@@ -0,0 +1,170 @@
import dotenv from "dotenv"
dotenv.config({ path: "../backend/.env" })
import _ from "lodash"
import * as L from "lonna"
import WebSocket from "ws"
import { NOTE_COLORS } from "../../common/src/colors"
import {
CrdtEnabled,
Point,
UIEvent,
defaultBoardSize,
isNote,
isPersistableBoardItemEvent,
isText,
newNote,
newText,
} from "../../common/src/domain"
import { CRDTStore } from "../../frontend/src/store/crdt-store"
import { GenericServerConnection } from "../../frontend/src/store/server-connection"
// hack, sue me
// @ts-ignore
global.localStorage = {}
function add(a: Point, b: Point) {
return { x: a.x + b.x, y: a.y + b.y }
}
function createTester(nickname: string, boardId: string) {
let counter = 0
const { width, height } = defaultBoardSize
const center = { x: width / 2 - 30 + Math.random() * 60, y: height / 2 - 20 + Math.random() * 40 }
const radius = 10 + Math.random() * 10
const increment = Math.random() * 4 - 2
const WS_ROOT = `${DOMAIN ? "wss" : "ws"}://${DOMAIN ?? "localhost:1337"}`
const WS_ADDRESS = `${WS_ROOT}/socket/board/${boardId}`
let connection = GenericServerConnection(L.constant(WS_ADDRESS), L.constant(false), (s) => new WebSocket(s) as any)
let sessionId = ""
connection.bufferedServerEvents.forEach((event) => {
if (event.action === "board.join.ack") {
console.log("Got session id", sessionId)
sessionId = event.sessionId
}
})
const localEvents = L.bus<UIEvent>()
localEvents.forEach(connection.send)
class MyWebSocket extends WebSocket {
constructor(url: string | URL, protocols?: string | string[] | undefined) {
console.log("Creating websocket", url, protocols)
super(url as any, protocols, { headers: { Cookie: `sessionId=${sessionId}` } })
}
}
const crdtStore = CRDTStore(
L.constant(boardId),
connection.connected,
localEvents.pipe(L.filter(isPersistableBoardItemEvent)).applyScope(L.globalScope),
L.constant({
status: "anonymous",
sessionId: null,
nickname: nickname,
nicknameSetByUser: true,
loginSupported: false,
}),
() => WS_ROOT,
MyWebSocket as any,
)
crdtStore.getBoardCrdt(boardId)
connection.connected
.pipe(
L.changes,
L.filter((c) => c),
)
.forEach(() => {
localEvents.push({ action: "board.join", boardId })
})
connection.bufferedServerEvents.forEach((event) => {
if (event.action === "board.init" && "board" in event) {
const boardAtInit = event.board
const notes = Object.values(boardAtInit.items).filter(isNote)
const texts = Object.values(boardAtInit.items).filter(isText)
setInterval(() => {
counter += increment
const position = add(center, {
x: radius * Math.sin(counter / 100),
y: radius * Math.cos(counter / 100),
})
localEvents.push({ action: "cursor.move", position, boardId })
if (Math.random() < notesPerInterval) {
const note = newNote("NOTE " + counter, "black", position.x, position.y)
notes.push(note)
localEvents.push({
action: "item.add",
boardId,
items: [note],
connections: [],
})
}
if (Math.random() < textsPerInterval) {
const text = newText(CrdtEnabled, "TEXT " + counter, position.x, position.y, 5, 5)
localEvents.push({
action: "item.add",
boardId,
items: [text],
connections: [],
})
}
// TODO: add crdt edits
if (Math.random() < editsPerInterval && notes.length > 0) {
const target = _.sample(notes)!
if (!target) {
throw Error("Target item not found")
}
const updated = { ...target, text: "EDIT " + counter, color: _.sample(NOTE_COLORS)?.color! }
connection.send({
ackId: "perf",
events: [
{
action: "item.front",
boardId,
itemIds: [updated.id],
},
{
action: "item.update",
boardId,
items: [updated],
},
],
})
}
}, interval)
}
if (event.action === "board.join.ack") {
localEvents.push({ action: "nickname.set", nickname })
}
})
}
// Environment variables.
const USER_COUNT = parseInt(process.env.USER_COUNT ?? "10")
const BOARD_ID = process.env.BOARD_ID
if (!BOARD_ID) {
throw Error("BOARD_ID missing. Please specify one more board ids separated by comma (,)")
}
const BOARD_IDS = BOARD_ID.split(",")
const DOMAIN = process.env.DOMAIN
const NOTES_PER_SEC = parseFloat(process.env.NOTES_PER_SEC ?? "0.1")
const TEXTS_PER_SEC = parseFloat(process.env.TEXTS_PER_SEC ?? "0.0")
const EDITS_PER_SEC = parseFloat(process.env.EDITS_PER_SEC ?? "0")
const CURSOR_MOVES_PER_SEC = parseFloat(process.env.CURSOR_MOVES_PER_SEC ?? "10")
// Calculated vars
const interval = 1000 / CURSOR_MOVES_PER_SEC
const notesPerInterval = (NOTES_PER_SEC / 1000) * interval
const textsPerInterval = (TEXTS_PER_SEC / 1000) * interval
const editsPerInterval = (EDITS_PER_SEC / 1000) * interval
console.log(
`Starting ${USER_COUNT} testers, moving cursors ${CURSOR_MOVES_PER_SEC}/sec, creating notes ${NOTES_PER_SEC}`,
)
console.log(`Total cursor events ${CURSOR_MOVES_PER_SEC * USER_COUNT}/s`)
console.log(`Total creation events ${NOTES_PER_SEC * USER_COUNT}/s`)
for (let i = 0; i < USER_COUNT; i++) {
createTester("perf-tester-" + (i + 1), BOARD_IDS[i % BOARD_IDS.length])
}

View File

@@ -0,0 +1,7 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"module": "commonjs",
"outDir": "dist"
}
}