return json.dumps({"type": "state", **STATE})\r
\r
\r
-def users_event():\r
- return json.dumps({"type": "users", "count": len(USERS)})\r
-\r
-\r
-async def notify_state():\r
+def notify_state():\r
global STATE\r
if current_slideshow and STATE["connected"] == 1:\r
try:\r
STATE = copy(STATE_DEFAULT)\r
if USERS: # asyncio.wait doesn't accept an empty list\r
message = state_event()\r
- await asyncio.wait([user.send(message) for user in USERS])\r
-\r
-\r
-async def notify_users():\r
- if USERS: # asyncio.wait doesn't accept an empty list\r
- message = users_event()\r
- await asyncio.wait([user.send(message) for user in USERS])\r
-\r
-\r
-async def register(websocket):\r
- USERS.add(websocket)\r
- await notify_users()\r
+ loop.call_soon_threadsafe(ws_queue.put_nowait, state_event())\r
\r
\r
-async def unregister(websocket):\r
- USERS.remove(websocket)\r
- await notify_users()\r
\r
+async def ws_handler(websocket, path):\r
+ logger.debug("Handling WebSocket connection")\r
+ recv_task = asyncio.ensure_future(ws_receive(websocket, path))\r
+ send_task = asyncio.ensure_future(ws_send(websocket, path))\r
+ done, pending = await asyncio.wait(\r
+ [recv_task, send_task],\r
+ return_when=asyncio.FIRST_COMPLETED,\r
+ )\r
+ for task in pending:\r
+ task.cancel()\r
\r
-async def ws_handle(websocket, path):\r
+async def ws_receive(websocket, path):\r
logger.debug("Received websocket request")\r
- global current_slideshow\r
- # register(websocket) sends user_event() to websocket\r
- await register(websocket)\r
+ USERS.add(websocket)\r
try:\r
- await websocket.send(state_event())\r
+ # Send initial state to clients on load\r
+ notify_state()\r
async for message in websocket:\r
+ logger.debug("Received websocket message: " + str(message))\r
data = json.loads(message)\r
if data["action"] == "prev":\r
if current_slideshow:\r
current_slideshow.prev()\r
- await notify_state()\r
+ notify_state()\r
elif data["action"] == "next":\r
if current_slideshow:\r
current_slideshow.next()\r
- await notify_state()\r
+ notify_state()\r
elif data["action"] == "first":\r
if current_slideshow:\r
current_slideshow.first()\r
- await notify_state()\r
+ notify_state()\r
elif data["action"] == "last":\r
if current_slideshow:\r
current_slideshow.last()\r
- await notify_state()\r
+ notify_state()\r
elif data["action"] == "black":\r
if current_slideshow:\r
if current_slideshow.visible() == 3:\r
current_slideshow.normal()\r
else:\r
current_slideshow.black()\r
- await notify_state()\r
+ notify_state()\r
elif data["action"] == "white":\r
if current_slideshow:\r
if current_slideshow.visible() == 4:\r
current_slideshow.normal()\r
else:\r
current_slideshow.white()\r
- await notify_state()\r
+ notify_state()\r
elif data["action"] == "goto":\r
if current_slideshow:\r
current_slideshow.goto(int(data["value"]))\r
- await notify_state()\r
- elif data["action"] == "refresh":\r
- await notify_state()\r
- if current_slideshow:\r
- current_slideshow.export_current_next()\r
- current_slideshow.refresh()\r
+ notify_state()\r
else:\r
- logger.error("unsupported event: {}", data)\r
+ logger.error("Received unnsupported event: {}", data)\r
+ message = ""\r
finally:\r
- await unregister(websocket)\r
+ USERS.remove(websocket)\r
+\r
+async def ws_send(websocket, path):\r
+ while True:\r
+ message = await ws_queue.get()\r
+ await asyncio.wait([user.send(message) for user in USERS])\r
+\r
\r
def run_ws():\r
# https://stackoverflow.com/questions/21141217/how-to-launch-win32-applications-in-separate-threads-in-python/22619084#22619084\r
# https://www.reddit.com/r/learnpython/comments/mwt4qi/pywintypescom_error_2147417842_the_application/\r
pythoncom.CoInitializeEx(pythoncom.COINIT_MULTITHREADED)\r
asyncio.set_event_loop(asyncio.new_event_loop())\r
- #start_server = websockets.serve(ws_handle, "0.0.0.0", 5678, ping_interval=None)\r
- start_server = websockets.serve(ws_handle, "0.0.0.0", 5678)\r
+ global ws_queue\r
+ ws_queue = asyncio.Queue()\r
+ global loop\r
+ loop = asyncio.get_event_loop()\r
+ start_server = websockets.serve(ws_handler, "0.0.0.0", 5678, ping_interval=None)\r
asyncio.get_event_loop().run_until_complete(start_server)\r
asyncio.get_event_loop().run_forever()\r
\r
connect_ppt()\r
\r
def refresh(self):\r
- logger.debug("Refreshing")\r
try:\r
if self.instance is None:\r
raise ValueError("PPT instance cannot be None")\r
pass\r
attempts += 1\r
elif slide == self.total_slides() + 1:\r
- shutil.copyfileobj(open(os.path.dirname(os.path.realpath(__file__)), r'''\static\black.jpg''', 'rb'), open(destination, 'wb'))\r
+ try:\r
+ shutil.copyfileobj(open(os.path.dirname(os.path.realpath(__file__)), r'''\static\black.jpg''', 'rb'), open(destination, 'wb'))\r
+ except Exception as e:\r
+ logger.warning("Failed to copy black slide: " + str(e))\r
else:\r
pass\r
\r
\r
def refresh_interval():\r
while getattr(refresh_daemon, "do_run", True):\r
- logger.debug("Triggering server-side refresh")\r
current_slideshow.refresh()\r
+ notify_state()\r
refresh_status()\r
- time.sleep(1)\r
+ time.sleep(0.5)\r
\r
def refresh_status():\r
if status_label is not None:\r
console_handler.setLevel(log_level)\r
logger.addHandler(console_handler)\r
\r
- logging.getLogger("asyncio").setLevel(logging.ERROR)\r
- logging.getLogger("asyncio.coroutines").setLevel(logging.ERROR)\r
- logging.getLogger("websockets.server").setLevel(logging.ERROR)\r
- logging.getLogger("websockets.protocol").setLevel(logging.ERROR)\r
+ #logging.getLogger("asyncio").setLevel(logging.ERROR)\r
+ #logging.getLogger("asyncio.coroutines").setLevel(logging.ERROR)\r
+ #logging.getLogger("websockets.server").setLevel(logging.ERROR)\r
+ #logging.getLogger("websockets.protocol").setLevel(logging.ERROR)\r
\r
\r
logger.debug("Finished setting up config and logging")\r
users.textContent = "Connection to PowerPoint failed";
}
+function update_current() {
+}
+
+function update_next() {
+}
+
websocket.onmessage = function (event) {
- console.log("Received data");
data = JSON.parse(event.data);
switch (data.type) {
case 'state':
break;
}
var d = new Date;
- switch (data.visible) {
- case 3:
- current_img.src = "/black.jpg";
- break;
- case 4:
- current_img.src = "/white.jpg";
- break;
- default:
- //current_img.src = "/cache/" + data.current + ".jpg?t=" + d.getTime();
- current_img.src = "/cache/" + data.current + ".jpg";
- break;
+ if (show_current.checked) {
+ switch (data.visible) {
+ case 3:
+ current_img.src = "/black.jpg";
+ break;
+ case 4:
+ current_img.src = "/white.jpg";
+ break;
+ default:
+ current_img.src = "/cache/" + data.current + ".jpg?t=" + d.getTime();
+ //current_img.src = "/cache/" + data.current + ".jpg";
+ break;
+ }
}
if (data.current == data.total + 1) {
- //next_img.src = "/cache/" + (data.total + 1) + ".jpg?t=" + d.getTime();
- next_img.src = "/cache/" + (data.total + 1) + ".jpg";
+ next_img.src = "/cache/" + (data.total + 1) + ".jpg?t=" + d.getTime();
+ //next_img.src = "/cache/" + (data.total + 1) + ".jpg";
} else {
- //next_img.src = "/cache/" + (data.current + 1) + ".jpg?t=" + d.getTime();
- next_img.src = "/cache/" + (data.current + 1) + ".jpg";
+ next_img.src = "/cache/" + (data.current + 1) + ".jpg?t=" + d.getTime();
+ //next_img.src = "/cache/" + (data.current + 1) + ".jpg";
}
- if (document.activeElement != current) {
+ if (document.activeElement != current) {
current.value = data.current;
}
total.textContent = data.total;
document.title = data.name;
break;
- case 'users':
- users.textContent = (
- data.count.toString() + " client" +
- (data.count == 1 ? "" : "s"));
- break;
default:
console.error(
- "unsupported event", data);
+ "Unsupported event", data);
}
if (preloaded == false && ! isNaN(total.textContent)) {
image = document.getElementById("preload_img");
}
};
-
-var interval = setInterval(refresh, 1000);
-
-function refresh() {
- console.log("Refreshing")
- websocket.send(JSON.stringify({action: 'refresh'}));
-}
-