commit e76843a741019a37a7af5c2034d836edb873d87c
Author: Vetle Haflan <vetle@haflan.dev>
Date: Fri, 22 Jan 2021 23:17:58 +0100
Initial commit with proof of concept
Diffstat:
A | index.html | | | 85 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | lipre.go | | | 98 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 183 insertions(+), 0 deletions(-)
diff --git a/index.html b/index.html
@@ -0,0 +1,85 @@
+<html>
+<head>
+ <title>lipre</title>
+</head>
+<body>
+ <div id="roomEntry">
+ <input id="roomCode"/>
+ <button onclick="present(getRoomCode())">Present</button>
+ <button onclick="view(getRoomCode())">View</button>
+ <div id="statusMessage"></div>
+ </div>
+ <textarea id="editor" style="display:none;height:100%; width:100%"></textarea>
+ <pre><code id="viewer" style="display:none;height:100%; width:100%; white-space: pre"></code></pre>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js"></script>
+ <script>
+ let getRoomCode = element => document.getElementById("roomCode").value
+ let setStatus = (message) => document.getElementById("statusMessage").innerText = message
+ let setCode = (message) => document.getElementById("viewer").innerText = message
+ let getCode = (message) => document.getElementById("editor").value
+ let hide = element => document.getElementById(element).style.display = "none"
+ let show = element => document.getElementById(element).style.display = "inline"
+ function connect(roomCode, present, openCallback) {
+ let url = "ws://" + document.location.host + (present ? "/pres/" : "/view/") + roomCode
+ window.ws = new WebSocket(url)
+ ws.onclose = () => {
+ setStatus("No connection to the given room")
+ }
+ ws.onopen = () => {
+ setStatus("Connected")
+ openCallback()
+ }
+ ws.onmessage = (msg) => {
+ setCode(msg.data)
+ hljs.highlightBlock(document.getElementById("viewer"))
+ }
+ }
+ function present(roomCode) {
+ connect(roomCode, true, () => {
+ hide("roomEntry")
+ hide("viewer")
+ show("editor")
+ })
+ }
+ function view(roomCode) {
+ connect(roomCode, false, () => {
+ hide("roomEntry")
+ hide("editor")
+ show("viewer")
+ })
+ }
+ // Allow direct connection with room code
+ let qParams = new URLSearchParams(window.location.search)
+ let roomCode = qParams.get("room")
+ let presentFlag = qParams.get("present")
+ if (roomCode) {
+ if (presentFlag) {
+ present(roomCode)
+ } else {
+ view(roomCode)
+ }
+ }
+ let editor = document.getElementById("editor")
+ editor.addEventListener("keyup", function(e) {
+ if (e.keyCode === 13) {
+ window.ws.send(getCode())
+ }
+ })
+ editor.addEventListener("keydown", function(e) {
+ if (e.keyCode === 9 || e.which === 9) {
+ console.log("arsiontarst")
+ e.preventDefault();
+ var start = this.selectionStart;
+ var end = this.selectionEnd;
+
+ // set textarea value to: text before caret + tab + text after caret
+ this.value = this.value.substring(0, start) + "\t" + this.value.substring(end);
+
+ // put caret at right position again
+ this.selectionStart = this.selectionEnd = start + 1;
+ }
+ })
+
+ </script>
+</body>
+</html>
diff --git a/lipre.go b/lipre.go
@@ -0,0 +1,98 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net/http"
+
+ "github.com/gorilla/mux"
+ "github.com/gorilla/websocket"
+)
+
+const temporaryCorrectRoomCode = "tester"
+
+type Room struct {
+ code string
+ presenter *websocket.Conn
+ // TODO:
+ viewers []*websocket.Conn
+}
+
+// TODO: Lock on this for concurrency?
+var rooms = make(map[string]*Room)
+
+func (room *Room) listen() {
+ for {
+ _, message, err := room.presenter.ReadMessage()
+ if err != nil {
+ if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
+ log.Printf("error: %v", err)
+ }
+ delete(rooms, room.code)
+ return
+ }
+ for _, viewerConn := range room.viewers {
+ if viewerConn == nil {
+ break
+ }
+ viewerConn.WriteMessage(websocket.TextMessage, message)
+ }
+ }
+}
+
+// HTTP
+var wsUpgrader = websocket.Upgrader{
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+}
+
+func indexHandler(w http.ResponseWriter, r *http.Request) {
+ htmlData, err := ioutil.ReadFile("index.html")
+ if err != nil {
+ panic(err)
+ }
+ w.Write(htmlData)
+ return
+}
+
+func presentHandler(w http.ResponseWriter, r *http.Request) {
+ roomCode := mux.Vars(r)["roomCode"]
+ /*if roomCode != temporaryCorrectRoomCode {
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ }*/
+ fmt.Println("Upgrading connection")
+ conn, err := wsUpgrader.Upgrade(w, r, nil)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ room := &Room{code: roomCode, presenter: conn}
+ rooms[roomCode] = room
+ go room.listen()
+}
+
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ roomCode := mux.Vars(r)["roomCode"]
+ room := rooms[roomCode]
+ if room == nil {
+ return
+ }
+ conn, err := wsUpgrader.Upgrade(w, r, nil)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ room.viewers = append(rooms[roomCode].viewers, conn)
+}
+
+func main() {
+ fmt.Println("Server starting")
+ router := mux.NewRouter()
+ router.HandleFunc("/", indexHandler)
+ router.HandleFunc("/pres/{roomCode}", presentHandler)
+ router.HandleFunc("/view/{roomCode}", viewHandler)
+ http.Handle("/", router)
+ log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", 8080), nil))
+}