nix fmt
All checks were successful
checks-impure / test (pull_request) Successful in 2m19s
checks / test (pull_request) Has been cancelled

This commit is contained in:
2023-11-26 12:47:16 +01:00
parent b034bd11f1
commit 258bf656cf
6 changed files with 216 additions and 211 deletions

View File

@@ -4,8 +4,8 @@ import sys
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from .clan_types import FlakeName
from .errors import ClanError from .errors import ClanError
from .types import FlakeName
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@@ -5,8 +5,8 @@ from typing import Any
from pydantic import AnyUrl, BaseModel, validator from pydantic import AnyUrl, BaseModel, validator
from pydantic.tools import parse_obj_as from pydantic.tools import parse_obj_as
from ..clan_types import validate_path
from ..dirs import clan_data_dir, clan_flakes_dir from ..dirs import clan_data_dir, clan_flakes_dir
from ..types import validate_path
DEFAULT_URL = parse_obj_as(AnyUrl, "http://localhost:8000") DEFAULT_URL = parse_obj_as(AnyUrl, "http://localhost:8000")

View File

@@ -1,16 +1,16 @@
import logging import logging
from contextlib import asynccontextmanager
from typing import Any
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.routing import APIRoute from fastapi.routing import APIRoute
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from contextlib import asynccontextmanager
from typing import Any
from ..errors import ClanError from ..errors import ClanError
from .assets import asset_path from .assets import asset_path
from .error_handlers import clan_error_handler from .error_handlers import clan_error_handler
from .routers import health, root, socket_manager, socket_manager2 from .routers import health, root, socket_manager2
origins = [ origins = [
"http://localhost:3000", "http://localhost:3000",
@@ -38,12 +38,11 @@ def setup_app() -> FastAPI:
app.include_router(health.router) app.include_router(health.router)
app.include_router(socket_manager.router)
app.include_router(socket_manager2.router) app.include_router(socket_manager2.router)
# Needs to be last in register. Because of wildcard route # Needs to be last in register. Because of wildcard route
app.include_router(root.router) app.include_router(root.router)
app.add_exception_handler(ClanError, clan_error_handler) # type: ignore app.add_exception_handler(ClanError, clan_error_handler) # type: ignore
app.mount("/static", StaticFiles(directory=asset_path()), name="static") app.mount("/static", StaticFiles(directory=asset_path()), name="static")

View File

@@ -1,202 +1,205 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js'></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script> <script>
$(document).ready(function(){ $(document).ready(function () {
if (typeof WebSocket != 'undefined') { if (typeof WebSocket != "undefined") {
$('#ask').show(); $("#ask").show();
} else {
$('#error').show();
}
// join on enter
$('#ask input').keydown(function(event) {
if (event.keyCode == 13) {
$('#ask a').click();
}
})
// join on click
$('#ask a').click(function() {
join($('#ask input').val());
$('#ask').hide();
$('#channel').show();
$('input#message').focus();
});
function join(name) {
var host = window.location.host.split(':')[0];
var ws = new WebSocket("ws://localhost:2979/ws2");
var container = $('div#msgs');
ws.onmessage = function(evt) {
var obj = JSON.parse(evt.data);
if (typeof obj != 'object') return;
console.log("Received: " + obj);
var action = obj['action'];
var struct = container.find('li.' + action + ':first');
if (struct.length < 1) {
console.log("Could not handle: " + evt.data);
return;
}
var msg = struct.clone();
msg.find('.time').text((new Date()).toString("HH:mm:ss"));
if (action == 'message') {
var matches;
if (matches = obj['message'].match(/^\s*[\/\\]me\s(.*)/)) {
msg.find('.user').text(obj['user'] + ' ' + matches[1]);
msg.find('.user').css('font-weight', 'bold');
} else { } else {
msg.find('.user').text(obj['user']); $("#error").show();
msg.find('.message').text(': ' + obj['message']);
} }
} else if (action == 'control') {
msg.find('.user').text(obj['user']);
msg.find('.message').text(obj['message']);
msg.addClass('control');
}
if (obj['user'] == name) msg.find('.user').addClass('self'); // join on enter
container.find('ul').append(msg.show()); $("#ask input").keydown(function (event) {
container.scrollTop(container.find('ul').innerHeight()); if (event.keyCode == 13) {
} $("#ask a").click();
}
});
$('#channel form').submit(function(event) { // join on click
event.preventDefault(); $("#ask a").click(function () {
var input = $(this).find(':input'); join($("#ask input").val());
var msg = input.val(); $("#ask").hide();
if (msg) { $("#channel").show();
ws.send(JSON.stringify({ action: 'message', user: name, message: msg })); $("input#message").focus();
});
function join(name) {
var host = window.location.host.split(":")[0];
var ws = new WebSocket("ws://localhost:2979/ws2");
var container = $("div#msgs");
ws.onmessage = function (evt) {
var obj = JSON.parse(evt.data);
if (typeof obj != "object") return;
console.log("Received: " + obj);
var action = obj["action"];
var struct = container.find("li." + action + ":first");
if (struct.length < 1) {
console.log("Could not handle: " + evt.data);
return;
}
var msg = struct.clone();
msg.find(".time").text(new Date().toString("HH:mm:ss"));
if (action == "message") {
var matches;
if ((matches = obj["message"].match(/^\s*[\/\\]me\s(.*)/))) {
msg.find(".user").text(obj["user"] + " " + matches[1]);
msg.find(".user").css("font-weight", "bold");
} else {
msg.find(".user").text(obj["user"]);
msg.find(".message").text(": " + obj["message"]);
}
} else if (action == "control") {
msg.find(".user").text(obj["user"]);
msg.find(".message").text(obj["message"]);
msg.addClass("control");
}
if (obj["user"] == name) msg.find(".user").addClass("self");
container.find("ul").append(msg.show());
container.scrollTop(container.find("ul").innerHeight());
};
$("#channel form").submit(function (event) {
event.preventDefault();
var input = $(this).find(":input");
var msg = input.val();
if (msg) {
ws.send(
JSON.stringify({ action: "message", user: name, message: msg }),
);
}
input.val("");
});
}
});
</script>
<style type="text/css" media="screen">
* {
font-family: Georgia;
} }
input.val(''); a {
}); color: #000;
} text-decoration: none;
}); }
</script> a:hover {
<style type="text/css" media="screen"> text-decoration: underline;
* { }
font-family: Georgia; div.bordered {
} margin: 0 auto;
a { margin-top: 100px;
color: #000; width: 600px;
text-decoration: none; padding: 20px;
} text-align: center;
a:hover { border: 10px solid #ddd;
text-decoration: underline; -webkit-border-radius: 20px;
} }
div.bordered { #error {
margin: 0 auto; background-color: #ba0000;
margin-top: 100px; color: #fff;
width: 600px; font-weight: bold;
padding: 20px; }
text-align: center; #ask {
border: 10px solid #ddd; font-size: 20pt;
-webkit-border-radius: 20px; }
} #ask input {
#error { font-size: 20pt;
background-color: #BA0000; padding: 10px;
color: #fff; margin: 0 10px;
font-weight: bold; }
} #ask span.join {
#ask { padding: 10px;
font-size: 20pt; background-color: #ddd;
} -webkit-border-radius: 10px;
#ask input { }
font-size: 20pt; #channel {
padding: 10px; margin-top: 100px;
margin: 0 10px; height: 480px;
} position: relative;
#ask span.join { }
padding: 10px; #channel div#descr {
background-color: #ddd; position: absolute;
-webkit-border-radius: 10px; left: -10px;
} top: -190px;
#channel { font-size: 13px;
margin-top: 100px; text-align: left;
height: 480px; line-height: 20px;
position: relative; padding: 5px;
} width: 630px;
#channel div#descr { }
position: absolute; div#msgs {
left: -10px; overflow-y: scroll;
top: -190px; height: 400px;
font-size: 13px; }
text-align: left; div#msgs ul {
line-height: 20px; list-style: none;
padding: 5px; padding: 0;
width: 630px; margin: 0;
} text-align: left;
div#msgs { }
overflow-y: scroll; div#msgs li {
height: 400px; line-height: 20px;
} }
div#msgs ul { div#msgs li span.user {
list-style: none; color: #ff9900;
padding: 0; }
margin: 0; div#msgs li span.user.self {
text-align: left; color: #aa2211;
} }
div#msgs li { div#msgs li span.time {
line-height: 20px; float: right;
} margin-right: 5px;
div#msgs li span.user { color: #aaa;
color: #ff9900; font-family: "Courier New";
} font-size: 12px;
div#msgs li span.user.self { }
color: #aa2211; div#msgs li.control {
} text-align: center;
div#msgs li span.time { }
float: right; div#msgs li.control span.message {
margin-right: 5px; color: #aaa;
color: #aaa; }
font-family: "Courier New"; div#input {
font-size: 12px; text-align: left;
} margin-top: 20px;
div#msgs li.control { }
text-align: center; div#input #message {
} width: 600px;
div#msgs li.control span.message { border: 5px solid #bbb;
color: #aaa; -webkit-border-radius: 3px;
} font-size: 30pt;
div#input { }
text-align: left; </style>
margin-top: 20px; </head>
} <body>
div#input #message { <div id="error" class="bordered" style="display: none">
width: 600px; This browser has no native WebSocket support.<br />
border: 5px solid #bbb; Use a WebKit nightly or Google Chrome.
-webkit-border-radius: 3px;
font-size: 30pt;
}
</style>
</head>
<body>
<div id="error" class="bordered" style="display: none;">
This browser has no native WebSocket support.<br/>
Use a WebKit nightly or Google Chrome.
</div>
<div id="ask" class="bordered" style="display: none;">
Name: <input type="text" id="name" /> <a href="#"><span class="join">Join!</span></a>
</div>
<div id="channel" class="bordered" style="display: none;">
<div id="descr" class="bordered">
<strong>Tip:</strong> Open up another browser window to chat.
</div> </div>
<div id="msgs"> <div id="ask" class="bordered" style="display: none">
<ul> Name: <input type="text" id="name" />
<li class="message" style="display: none"> <a href="#"><span class="join">Join!</span></a>
<span class="user"></span><span class="message"></span>
<span class="time"></span>
</li>
</ul>
</div> </div>
<div id="input"> <div id="channel" class="bordered" style="display: none">
<form><input type="text" id="message" /></form> <div id="descr" class="bordered">
<strong>Tip:</strong> Open up another browser window to chat.
</div>
<div id="msgs">
<ul>
<li class="message" style="display: none">
<span class="user"></span><span class="message"></span>
<span class="time"></span>
</li>
</ul>
</div>
<div id="input">
<form><input type="text" id="message" /></form>
</div>
</div> </div>
</div> </body>
</body>
</html> </html>

View File

@@ -1,13 +1,12 @@
# Requires: `starlette`, `uvicorn`, `jinja2` # Requires: `starlette`, `uvicorn`, `jinja2`
# Run with `uvicorn example:app` # Run with `uvicorn example:app`
import logging
import os
import anyio import anyio
from broadcaster import Broadcast from broadcaster import Broadcast
from fastapi import FastAPI, WebSocket, WebSocketDisconnect from fastapi import APIRouter, WebSocket
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from fastapi import APIRouter, Response
import os
import logging
import asyncio
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
router = APIRouter() router = APIRouter()
@@ -18,15 +17,14 @@ brd = Broadcast("memory://")
@router.get("/ws2_example") @router.get("/ws2_example")
async def get() -> HTMLResponse: async def get() -> HTMLResponse:
html = open(f"{os.getcwd()}/webui/routers/messenger.html").read() html = open(f"{os.getcwd()}/webui/routers/messenger.html").read()
return HTMLResponse(html) return HTMLResponse(html)
@router.websocket("/ws2") @router.websocket("/ws2")
async def chatroom_ws(websocket: WebSocket) -> None: async def chatroom_ws(websocket: WebSocket) -> None:
await websocket.accept() await websocket.accept()
async with anyio.create_task_group() as task_group: async with anyio.create_task_group() as task_group:
# run until first is complete # run until first is complete
async def run_chatroom_ws_receiver() -> None: async def run_chatroom_ws_receiver() -> None:
@@ -47,8 +45,8 @@ async def chatroom_ws_receiver(websocket: WebSocket) -> None:
async def chatroom_ws_sender(websocket: WebSocket) -> None: async def chatroom_ws_sender(websocket: WebSocket) -> None:
async with brd.subscribe(channel="chatroom") as subscriber: async with brd.subscribe(channel="chatroom") as subscriber:
log.warning("====>Subscribed to chatroom channel") if subscriber is None:
async for event in subscriber: log.error("Subscriber is None")
log.warning(f"Sending message: {event.message}") return
async for event in subscriber: # type: ignore
await websocket.send_text(event.message) await websocket.send_text(event.message)

View File

@@ -49,6 +49,11 @@ ignore_missing_imports = true
module = "pytest.*" module = "pytest.*"
ignore_missing_imports = true ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "anyio.*"
ignore_missing_imports = true
[[tool.mypy.overrides]] [[tool.mypy.overrides]]
module = "setuptools.*" module = "setuptools.*"
ignore_missing_imports = true ignore_missing_imports = true