lipre

Stream text files for live (coding) representations
Log | Files | Refs

commit f27feb8f80119a91cee01e9f5a656568d5cfde92
parent e76843a741019a37a7af5c2034d836edb873d87c
Author: Vetle Haflan <vetle@haflan.dev>
Date:   Sun, 24 Jan 2021 00:48:08 +0100

Add predir.py and make server store files sent to it from presenter

predir - present directory: For sharing the contents of a directory.
All files created, deleted or modified will be synced with the viewer.

Diffstat:
Mindex.html | 5++++-
Mlipre.go | 23++++++++++++++++++++---
Apredir.py | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/index.html b/index.html @@ -22,6 +22,7 @@ function connect(roomCode, present, openCallback) { let url = "ws://" + document.location.host + (present ? "/pres/" : "/view/") + roomCode window.ws = new WebSocket(url) + window.files = {} ws.onclose = () => { setStatus("No connection to the given room") } @@ -30,7 +31,9 @@ openCallback() } ws.onmessage = (msg) => { - setCode(msg.data) + let fileReceived = JSON.parse(msg.data) + window.files[fileReceived.name] = fileReceived.contents + setCode(fileReceived.contents) hljs.highlightBlock(document.getElementById("viewer")) } } diff --git a/lipre.go b/lipre.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "fmt" "io/ioutil" "log" @@ -10,13 +11,15 @@ import ( "github.com/gorilla/websocket" ) +// Not used - either read password from config / flag or define the valid rooms in a file on server const temporaryCorrectRoomCode = "tester" type Room struct { code string presenter *websocket.Conn - // TODO: - viewers []*websocket.Conn + viewers []*websocket.Conn + // Store files so that they can be sent to new viewers upon connection + files map[string][]byte } // TODO: Lock on this for concurrency? @@ -32,6 +35,17 @@ func (room *Room) listen() { delete(rooms, room.code) return } + file := struct { + Name string `json:"name"` + Contents string `json:"contents"` + }{} + err = json.Unmarshal(message, &file) + if err != nil { + log.Printf("error: %v", err) + // TODO: Send info to presenter + return + } + room.files[file.Name] = message for _, viewerConn := range room.viewers { if viewerConn == nil { break @@ -68,7 +82,7 @@ func presentHandler(w http.ResponseWriter, r *http.Request) { log.Println(err) return } - room := &Room{code: roomCode, presenter: conn} + room := &Room{code: roomCode, presenter: conn, files: make(map[string][]byte)} rooms[roomCode] = room go room.listen() } @@ -85,6 +99,9 @@ func viewHandler(w http.ResponseWriter, r *http.Request) { return } room.viewers = append(rooms[roomCode].viewers, conn) + for _, filedata := range room.files { + conn.WriteMessage(websocket.TextMessage, filedata) + } } func main() { diff --git a/predir.py b/predir.py @@ -0,0 +1,51 @@ +#!/usr/bin/python3 + +from os import listdir +from os.path import isfile, basename +import pyinotify +import json +import sys +import websocket + +def send_file(filename, contents): + fileobj = { + "name": filename, + "contents": contents + } + print(f'Sending {filename}') + ws.send(json.dumps(fileobj)) + + +program = sys.argv[0] +if len(sys.argv) <= 1: + print(f"Use: {program} <room code>") + exit(1) +room_code = sys.argv[1] + +HOST="localhost:8080" + +ws = websocket.WebSocket() +ws.connect(f"ws://{HOST}/pres/{room_code}") + +# Initial file upload +filenames = [fn for fn in listdir() if isfile(fn)] +for fn in filenames: + send_file(fn, open(fn).read()) + +# Listen for changes +class EventHandler(pyinotify.ProcessEvent): + def process_IN_CREATE(self, event): + fn = basename(event.pathname) + send_file(fn, open(fn).read()) + def process_IN_DELETE(self, event): + fn = basename(event.pathname) + send_file(fn, None) + def process_IN_MODIFY(self, event): + self.process_IN_CREATE(event) + +wm = pyinotify.WatchManager() +handler = EventHandler() +notifier = pyinotify.Notifier(wm, handler) +mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY +wm.add_watch('.', mask) +notifier.loop() + \ No newline at end of file