-
Moritz Langenstein authoredMoritz Langenstein authored
room.js 2.81 KiB
import { spreadErasureIntervals, flattenErasureIntervals } from "./erasure.js"
class Room extends EventTarget {
constructor(name) {
super()
this.name = name
this.crdt = null
this.undoStack = []
}
disconnect() {
this.crdt.destroy()
this.crdt = null
}
getUserID() {
return this.crdt.getUserID()
}
addPath([x, y, w, colour]) {
const pathID = this.crdt.addPath([x, y, w, colour])
this.undoStack.push([pathID, 0, 0])
this.dispatchEvent(new CustomEvent("undoEnabled"))
return pathID
}
extendPath(pathID, [x, y, w, colour]) {
const pathLength = this.crdt.extendPath(pathID, [x, y, w, colour])
if (pathLength == 2) {
this.undoStack[this.undoStack.length - 1] = [pathID, 0, 1]
} else {
this.undoStack.push([pathID, pathLength - 2, pathLength - 1])
}
this.dispatchEvent(new CustomEvent("undoEnabled"))
}
endPath(pathID) {
this.crdt.endPath(pathID)
}
extendErasureIntervals(pathID, pointID, newIntervals) {
this.crdt.extendErasureIntervals(
pathID,
flattenErasureIntervals({ [pointID]: newIntervals }),
)
}
replacePath(pathID, newPoints) {
this.fastUndo(true)
newPoints.forEach((point) => this.extendPath(pathID, point))
this.undoStack.splice(this.undoStack.length - newPoints.length, 1)
}
getPaths() {
const paths = new Map()
for (const pathID of this.crdt.getPathIDs()) {
paths.set(pathID, this.crdt.getPathPoints(pathID))
}
return paths
}
getPathPoints(pathID) {
return this.crdt.getPathPoints(pathID)
}
getErasureIntervals(pathID) {
return spreadErasureIntervals(this.crdt.getErasureIntervals(pathID))
}
canUndo() {
return this.undoStack.length > 0
}
undo() {
const operation = this.undoStack.pop()
if (!operation) return
const [pathID, ...interval] = operation
this.crdt.extendErasureIntervals(pathID, [interval])
}
fastUndo(forReplacing = false) {
let from = this.undoStack.length - 1
if (from < 0) return
// eslint-disable-next-line no-unused-vars
const [pathID, _, end] = this.undoStack[from]
const endErasing = forReplacing ? end + 1 : end
for (; from >= 0; from--) {
if (this.undoStack[from][0] != pathID) {
from++
break
}
}
this.undoStack = this.undoStack.slice(0, Math.max(0, from))
this.crdt.extendErasureIntervals(pathID, [[0, endErasing]])
}
}
export const connect = async (roomName, CRDT, connection) => {
const room = new Room(roomName)
await CRDT.initialise(room, {
connection,
url: "/",
room: room.name,
mesh: {
minPeers: 4,
maxPeers: 8,
},
handshake: {
initial: 100,
interval: 500,
},
heartbeat: {
interval: 500,
minimum: 1000,
timeout: 10000,
},
})
return room
}