|
4 | 4 | This module includes the `Show` class and the main functionalities of `auditorium`.
|
5 | 5 | """
|
6 | 6 |
|
| 7 | +import asyncio |
7 | 8 | import base64
|
8 | 9 | import io
|
| 10 | +import json |
9 | 11 | import runpy
|
10 | 12 | import warnings
|
11 | 13 | import webbrowser
|
12 | 14 | from collections import OrderedDict
|
| 15 | +from typing import Union |
13 | 16 |
|
| 17 | +import websockets |
| 18 | +from fastapi import FastAPI |
14 | 19 | from jinja2 import Template
|
15 | 20 | from markdown import markdown
|
| 21 | +from pydantic import BaseModel |
16 | 22 | from pygments import highlight
|
17 | 23 | from pygments.formatters.html import HtmlFormatter
|
18 | 24 | from pygments.lexers import get_lexer_by_name
|
19 | 25 | from pygments.styles import get_style_by_name
|
20 |
| - |
21 |
| -from fastapi import FastAPI |
22 |
| -from starlette.staticfiles import StaticFiles |
23 | 26 | from starlette.responses import HTMLResponse
|
24 |
| -from pydantic import BaseModel |
25 |
| -from typing import Union |
| 27 | +from starlette.staticfiles import StaticFiles |
26 | 28 |
|
27 | 29 | from .components import Animation, Block, Column, Fragment, ShowMode
|
28 | 30 | from .utils import fix_indent, path
|
@@ -64,22 +66,58 @@ def __init__(self, title="", theme="white", code_style="monokai"):
|
64 | 66 |
|
65 | 67 | ## Show functions
|
66 | 68 |
|
67 |
| - def run(self, host: str, port: int, launch: bool, *args, **kwargs) -> None: |
| 69 | + def run(self, *, host: str, port: int, debug: bool = False) -> None: |
68 | 70 | self._content = self._render_content()
|
69 | 71 |
|
70 |
| - # if launch: |
71 |
| - # def launch_server(): |
72 |
| - # webbrowser.open_new_tab(f"http://{host}:{port}") |
73 |
| - |
74 |
| - # self.app.add_task(launch_server) |
75 |
| - |
76 | 72 | try:
|
77 | 73 | import uvicorn
|
78 | 74 |
|
79 |
| - uvicorn.run(self.app, host=host, port=port, *args, **kwargs) |
| 75 | + uvicorn.run(self.app, host=host, port=port, debug=debug) |
80 | 76 | except ImportError:
|
81 |
| - warnings.warn("In order to call `run` you need `uvicorn` installed.") |
| 77 | + warnings.warn("(!) You need `uvicorn` installed in order to call `run`.") |
| 78 | + exit(1) |
| 79 | + |
| 80 | + def publish(self, server: str, name: str): |
| 81 | + url = "{}/ws".format(server) |
| 82 | + asyncio.get_event_loop().run_until_complete(self._ws(url, name)) |
| 83 | + |
| 84 | + async def _ws(self, url: str, name: str): |
| 85 | + try: |
| 86 | + async with websockets.connect(url) as websocket: |
| 87 | + print("Connected to server") |
| 88 | + await websocket.send(name) |
| 89 | + print("Starting command loop.") |
| 90 | + |
| 91 | + while True: |
| 92 | + command = await websocket.recv() |
| 93 | + command = json.loads(command) |
| 94 | + |
| 95 | + response = self._do_ws_command(command) |
| 96 | + response = json.dumps(response) |
| 97 | + await websocket.send(response) |
| 98 | + except ConnectionRefusedError: |
| 99 | + print("(!) Could not connect to %s. Make sure server is up." % url) |
82 | 100 | exit(1)
|
| 101 | + except websockets.exceptions.ConnectionClosedError: |
| 102 | + print("(!) Connection to %s closed by server." % url) |
| 103 | + exit(1) |
| 104 | + |
| 105 | + |
| 106 | + def _do_ws_command(self, command): |
| 107 | + if command["type"] == "render": |
| 108 | + print("Rendering content") |
| 109 | + return dict(content=self.render()) |
| 110 | + elif command["type"] == "error": |
| 111 | + print("(!) %s" % command['msg']) |
| 112 | + raise websockets.exceptions.ConnectionClosedError(1006, command['msg']) |
| 113 | + else: |
| 114 | + print("Executing slide %s" % command["slide"]) |
| 115 | + values = {} |
| 116 | + values[command["id"]] = command["value"] |
| 117 | + update = self.do_code(command["slide"], values) |
| 118 | + return update |
| 119 | + |
| 120 | + raise ValueError("Unknown command: %s", command["type"]) |
83 | 121 |
|
84 | 122 | @property
|
85 | 123 | def show_title(self) -> str:
|
|
0 commit comments