server
#!/usr/bin/env python
import asyncio
import json
import secrets
import websockets
from config import WEBSOCKET_PORT
JOIN = {}
async def error(websocket, message):
"""
Send an error message.
"""
event = {
"type": "error",
"message": message,
}
await websocket.send(json.dumps(event))
async def start(websocket):
key = secrets.token_urlsafe(12)
JOIN[key] = websocket
try:
event = {
"type": "init",
"key": key,
}
await websocket.send(json.dumps(event))
async for message in websocket:
print(message)
finally:
del JOIN[key]
async def progress(websocket, event):
try:
key = event.pop("key")
client_websocket = JOIN[key]
except KeyError:
await error(websocket, "cilent not found.")
return
await client_websocket.send(json.dumps(event))
async def echo(websocket):
async for message in websocket:
event = json.loads(message)
event_type = event["type"]
if event_type == "client":
await start(websocket)
else:
await progress(websocket, event)
async def main():
async with websockets.serve(echo, "0.0.0.0", WEBSOCKET_PORT):
await asyncio.Future() # run forever
asyncio.run(main())
python server.py
python client
#!/usr/bin/env python
import json
import websockets
from config import WEBSOCKET_PORT
async def send_progress(event: dict):
async with websockets.connect(
"ws://localhost:{}".format(WEBSOCKET_PORT)) as websocket:
await websocket.send(json.dumps(event))
import asyncio
from websocket_client import send_progress
asyncio.run(send_progress({"type": "rate", "key": progress_token, "message": line}))
备注: asyncio.run()
可能会报错: RuntimeError: asyncio.run() cannot be called from a running event loop
解决办法参照: https://maxyoung.fun/blog/Python-asyncio.html#runtimeerror-asynciorun-cannot-be-called-from-a-running-event-loop
js client
const websocket = new WebSocket(
"ws://" + window.location.hostname + ":/"
);
websocket.addEventListener("open", () => {
let event = { type: "client" };
websocket.send(JSON.stringify(event));
});
websocket.addEventListener("message", ({ data }) => {
const event = JSON.parse(data);
console.log(event);
switch (event.type) {
case "init":
let token = event.key;
window.progressToken = token;
switch (window.fileType) {
case "simple":
if (
$("#carID").val() &&
$("#caseTime").val() &&
$("#beforeSeconds").val() &&
$("#afterSeconds").val()
) {
$("#play").click();
}
break;
case "complete":
if (
$("#carIDCompleteFile").val() &&
$("#caseTimeCompleteFile").val()
) {
$("#playCompleteFile").click();
}
break;
}
break;
case "progress":
$("#message").append("<span>" + event.message + "<span></br>");
current_type = "progress";
break;
case "rate":
if (current_type == "rate") {
$("#message span").last().text(event.message);
} else {
$("#message").append("<span>" + event.message + "</span></br>");
current_type = "rate";
}
break;
case "play":
$("#download-input").val("rsync -avPz dat102:" + event.data_path + " .");
let playUrl =
window.location.protocol +
"//" +
window.location.hostname +
":" +
event.message;
let iframe =
'<iframe id="dv-play" class="w-100 h-100" src="' +
playUrl +
'"></iframe>';
$("#screen").html(iframe);
break;
case "control":
let shellUrl =
window.location.protocol +
"//" +
window.location.hostname +
":" +
event.message;
$("#shell").attr("src", shellUrl);
$("#shell").focus();
break;
default:
throw new Error(`Unsupported event type: ${event.type}.`);
}
});