Last active
April 26, 2024 07:29
-
-
Save Tamriel/9447b18c4aa8b8a362d6dd839d00cc22 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import buffer.Buffer | |
import org.scalajs.dom | |
import dom.document | |
import eu.timepit.crjdt.circe.RegNodeConflictResolver.LWW | |
import eu.timepit.crjdt.circe.syntax._ | |
import eu.timepit.crjdt.core.{Operation, Replica} | |
import eu.timepit.crjdt.core.syntax._ | |
import upickle.default._ | |
import scala.scalajs.js | |
import scala.scalajs.js.JSApp | |
import scalatags.JsDom.all._ | |
object Main extends JSApp { | |
val listName = "list" | |
def main(): Unit = { | |
var senderSeqNo = 16 // todo: restore from local crjdt | |
// create text field | |
val box = input( | |
`type` := "text", | |
placeholder := "This text field is synced." | |
).render | |
// init crjdt | |
val p0 = Replica.empty("p") | |
val list = doc.downField(listName) | |
var p1 = p0.applyCmd(list := `[]`) | |
// init server connection | |
// todo: save peer_id | |
val channelID = "a4f512ab6b5c6750bf7ea73486cf76a9" | |
val channelIDHex = Buffer.from(channelID, "hex") | |
val url = "ws://localhost:8080/events?peer_id=651e14bffe377c6d856a27704998da470156605b0c92035aa0cc3917eba5e0f7" | |
val socket = new dom.WebSocket(url) | |
socket.binaryType = "arraybuffer" | |
socket.onopen = { (e: dom.Event) => | |
// connect to server | |
val subscribeToChannel = js.Dictionary( | |
"channelID" -> channelIDHex, | |
"startOffset" -> -1 | |
) | |
val clientToServer = js.Dictionary( | |
"message" -> js.Dictionary( | |
"org.trvedata.trvedb.avro.SubscribeToChannel" -> subscribeToChannel | |
) | |
) | |
val buf = AvroSchemas.clientToServerType.toBuffer(clientToServer) | |
socket.send(buf) | |
// send message when user types | |
box.onkeydown = (e: dom.KeyboardEvent) => { | |
var pos = list.iter | |
for (i <- 1 to box.selectionStart) { | |
pos = pos.next | |
} | |
val opsBefore = p1.generatedOps | |
val cmd = e.key match { | |
case "Delete" => pos.delete | |
case "Backspace" => pos.delete | |
case _ => pos.insert(e.key) // todo: filter out all special keys, like in the ruby editor | |
} | |
p1 = p1.applyCmd(cmd) | |
val newOps = p1.generatedOps.diff(opsBefore) | |
senderSeqNo += 1 | |
val sendMessage = js.Dictionary( | |
"channelID" -> channelIDHex, | |
"senderSeqNo" -> senderSeqNo, | |
"payload" -> Buffer.from(write(newOps)) | |
) | |
val clientToServer = js.Dictionary( | |
"message" -> js.Dictionary( | |
"org.trvedata.trvedb.avro.SendMessage" -> sendMessage | |
) | |
) | |
socket.send(AvroSchemas.clientToServerType.toBuffer(clientToServer)) | |
println(p1.document.toJson) | |
} | |
} | |
// change crjdt on message | |
socket.onmessage = { (e: dom.MessageEvent) => | |
val buf = Buffer.from(e.data) | |
val serverToClientJsDict = AvroSchemas.serverToClientType.fromBuffer(buf) | |
println(serverToClientJsDict) | |
val messageJsDictOption = serverToClientJsDict.get("message") | |
if (messageJsDictOption.isDefined) { | |
val messageJsDict = messageJsDictOption.get | |
val sendMessageErrorDictOption = messageJsDict.get("org.trvedata.trvedb.avro.SendMessageError") | |
val receiveMessageDictOption = messageJsDict.get("org.trvedata.trvedb.avro.ReceiveMessage") | |
if (sendMessageErrorDictOption.isDefined) { | |
println(sendMessageErrorDictOption.get) | |
} else if (receiveMessageDictOption.isDefined) { | |
val payloadOption = receiveMessageDictOption.get.get("payload") | |
if (payloadOption.isDefined) { | |
// todo: maybe I can use types instead of Any | |
val payloadBuffer = payloadOption.get | |
val ops = read[Vector[Operation]](payloadBuffer.toString) | |
p1 = p1.applyRemoteOps(ops) | |
// convert crjdt to string | |
val array = p1.document.toJson.\\(listName)(0).asArray.get | |
var string = "" | |
for (char <- array) { | |
string += char.asString.get | |
} | |
box.value = string | |
// todo: test with fast typing, I guess something gets lost | |
} | |
} | |
} | |
} | |
// build GUI | |
document.body.appendChild( | |
div( | |
box | |
).render | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment