Newer
Older
import uuidv4 from "uuid/v4"
import yArray from "y-array"
import yMap from "y-map"
import yUnion, { Union } from "./y-union.js"
import yMemory from "y-memory"
import Y from "yjs"
import yP2PMesh from "./y-p2p-mesh.js"
Y.Struct.Union = Union
yUnion(Y)
yP2PMesh(Y)
import { spreadErasureIntervals, flattenErasureIntervals } from "./erasure.js"
Moritz Langenstein
committed
class Room extends EventTarget {
constructor(name) {
super()
this.name = name
this._y = null
this.ownID = null
this.erasureIntervals = {}
disconnect() {
this._y.destroy()
}
this.shared.strokePoints.set(id, Y.Array).push([[x, y, w, colour]])
this.shared.eraseIntervals.set(id, Y.Union)
this.shared.strokePoints.get(id).push([[x, y, w, colour]])
}
extendErasureIntervals(pathID, pointID, newIntervals) {
this.shared.eraseIntervals
.get(pathID)
.merge(flattenErasureIntervals({ [pointID]: newIntervals }))
getPaths() {
for (const id of this.shared.strokePoints.keys()) {
paths.set(id, this._generatePath(id))
}
return paths
}
get shared() {
return this._y.share
}
_generatePath(id) {
const points = this.shared.strokePoints.get(id)
_generateRemovedIntervals(id) {
const intervals = this.shared.eraseIntervals.get(id)
Moritz Langenstein
committed
if (!intervals) return []
Moritz Langenstein
committed
return spreadErasureIntervals(intervals.get())
inviteUser(id) {
this._y.connector.connectToPeer(id)
}
async _initialise(connection) {
this._y = await Y({
db: {
name: "memory",
},
connector: {
name: "p2p-mesh",
connection,
mesh: {
minPeers: 4,
maxPeers: 8,
},
handshake: {
initial: 100,
interval: 500,
},
heartbeat: {
interval: 500,
minimum: 1000,
timeout: 10000,
},
if (event.action == "userConnection") {
const { id, quality } = event
this.dispatchEvent(
new CustomEvent("userConnection", { detail: { id, quality } }),
)
} else if (event.action == "userID") {
this.ownID = id
this.dispatchEvent(new CustomEvent("allocateOwnID", { detail: id }))
} else if (event.action == "userJoined") {
const { user: id } = event
this.dispatchEvent(new CustomEvent("userJoin", { detail: id }))
} else if (event.action == "userLeft") {
const { user: id } = event
this.dispatchEvent(new CustomEvent("userLeave", { detail: id }))
} else if (event.action === "peerSyncedWithUs") {
const { user: id } = event
this.dispatchEvent(
new CustomEvent("peerSyncedWithUs", { detail: id }),
)
} else if (event.action === "waitingForSyncStep") {
const { user: id } = event
this.dispatchEvent(
new CustomEvent("waitingForSyncStep", { detail: id }),
)
} else if (event.action === "weSyncedWithPeer") {
const { user: id } = event
this.dispatchEvent(
new CustomEvent("weSyncedWithPeer", { detail: id }),
)
strokePoints: "Map",
eraseIntervals: "Map",
const dispatchRemovedIntervalsEvent = (lineEvent) => {
const id = lineEvent.name
const intervals = this._generateRemovedIntervals(id)
const points = this._generatePath(id)
const detail = { id, intervals, points }
this.dispatchEvent(
new CustomEvent("removedIntervalsChange", {
detail,
}),
)
}
const dispatchPathUpdateEvent = (lineEvent) => {
const id = lineEvent.name
const points = this._generatePath(id)
const detail = { id, points }
this.dispatchEvent(new CustomEvent("addOrUpdatePath", { detail }))
}
this.shared.strokePoints.observe((lineEvent) => {
dispatchPathUpdateEvent(lineEvent)
lineEvent.value.observe((pointEvent) => {
if (pointEvent.type == "insert") {
}
})
}
})
this.shared.eraseIntervals.observe((lineEvent) => {
if (lineEvent.type == "add") {
dispatchRemovedIntervalsEvent(lineEvent)
lineEvent.value.observe(() => {
dispatchRemovedIntervalsEvent(lineEvent)
})
}
export const connect = async (roomName, connection) => {
await room._initialise(connection)