#python #websocket #messaging #quart
#python #websocket #обмен сообщениями #quart
Вопрос:
я отредактировал этот способ:
моя команда curl:
curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://localhost:5000/telepath
я хочу отображать эти опубликованные данные на всех клиентах.
я собрал все, что мог, в документации, но мне это нелегко.
вот мой скрипт:
from quart import Quart, render_template, websocket
from functools import partial, wraps
from quart import request, redirect, url_for, copy_current_websocket_context
import asyncio
app = Quart(__name__)
connected_websockets = set()
def collect_websocket(func):
@wraps(func)
async def wrapper(*args, **kwargs):
global connected_websockets
queue = asyncio.Queue()
connected_websockets.add(queue)
try:
return await func(queue, *args, **kwargs)
finally:
connected_websockets.remove(queue)
return wrapper
async def broadcast(message):
for queue in connected_websockets:
await queue.put(message)
@app.route('/')
async def index():
return await render_template('index.html')
@app.websocket('/ws')
@collect_websocket
async def ws(queue):
print("$ $ $",queue)
while True:
data = await websocket.receive()
print("n {}".format(data))
await websocket.send(f"echo {data}")
@app.route('/telepath', methods=['POST'])
async def telepath():
global connected_websockets
data = await request.get_json()
for queue in connected_websockets:
await queue.put(data["key1"])
return "n Request Processed.n"
if __name__ == '__main__':
app.run(port=5000)
и шаблон:
<!doctype html>
<html>
<head>
<title>My TEST</title>
</head>
<body>
<input type="text" id="message">
<button>Send</button>
<ul></ul>
<script type="text/javascript">
var ws = new WebSocket('ws://' document.domain ':' location.port '/ws');
ws.onmessage = function (event) {
var messages_dom = document.getElementsByTagName('ul')[0];
var message_dom = document.createElement('li');
var content_dom = document.createTextNode('Received: ' event.data);
message_dom.appendChild(content_dom);
messages_dom.appendChild(message_dom);
};
var button = document.getElementsByTagName('button')[0];
button.onclick = function() {
var content = document.getElementsByTagName('input')[0].value;
ws.send(content);
};
document.addEventListener('DOMContentLoaded', function() {
var es = new EventSource('/telepath');
es.onmessage = function (event) {
var messages_dom = document.getElementsByTagName('ul')[0];
var message_dom = document.createElement('li');
var content_dom = document.createTextNode('Received: ' event.data);
message_dom.appendChild(content_dom);
messages_dom.appendChild(message_dom);
};
});
let socket = new WebSocket("ws://localhost:5000/ws");
socket.onmessage = function(event) {
alert(`Data received: ${event.data}`);
};
</script>
</body>
</html>
Моей конечной целью будет аутентификация и нацеливание на то, кто
может получать личные сообщения с сервера.
Невозможно передать опубликованные данные через curl в клиенте Mozilla или Chrome.
Ответ №1:
В вашем collect_websocket
декораторе вы передаете queue
аргумент обработчику websocket ( return await func(queue, *args, **kwargs)
), тогда как ваш обработчик websocket не принимает никаких аргументов ( async def ws()
). Это приводит к ошибке, которую вы видите.
Похоже, что ваш ws_v2
обработчик websocket настроен для работы с collect_websocket
декоратором ( async def ws_v2(queue)
), поэтому я думаю, вы можете просто переключиться на его использование и переписать telepath следующим образом,
@app.route('/telepath', methods=['POST'])
async def telepath():
global connected_websockets
data = await request.get_json()
for queue in connected_websockets:
await queue.put(data["key1"])
return {}
Обратите внимание, что вам не нужно создавать какие-либо очереди в /telepath
маршруте, поскольку это делается вашим collect_websocket
декоратором, а также поскольку вам нужна очередь для каждого соединения с websocket. Вам также не нужно ожидать ws_v2
обработчика, вместо этого он будет вызываться всякий раз, когда будет установлено новое соединение с websocket.
Для аутентификации я рекомендую вам начать с Quart-Auth (я являюсь автором библиотеки).
Редактировать: полный код по запросу,
import asyncio
from functools import partial, wraps
from quart import (
copy_current_websocket_context, Quart, render_template,
request, websocket
)
app = Quart(__name__)
connected_websockets = set()
def collect_websocket(func):
@wraps(func)
async def wrapper(*args, **kwargs):
global connected_websockets
queue = asyncio.Queue()
connected_websockets.add(queue)
try:
return await func(queue, *args, **kwargs)
finally:
connected_websockets.remove(queue)
return wrapper
async def broadcast(message):
global connected_websockets
for queue in connected_websockets:
await queue.put(message)
@app.route('/')
async def index():
return await render_template('index.html')
@app.websocket('/ws')
@collect_websocket
async def ws(queue):
await websocket.accept()
while True:
data = await queue.get()
await websocket.send_json(data)
@app.route('/telepath', methods=['POST'])
async def telepath():
data = await request.get_json()
await broadcast(data)
return {}
if __name__ == '__main__':
app.run(port=5000)
и шаблон,
<!doctype html>
<html>
<head>
<title>My TEST</title>
</head>
<body>
<ul></ul>
<script type="text/javascript">
var ws = new WebSocket('ws://' document.domain ':' location.port '/ws');
ws.onmessage = function (event) {
const messagesDOM = document.getElementsByTagName('ul')[0];
const messageDOM = document.createElement('li');
const message = JSON.parse(event.data).message;
const contentDOM = document.createTextNode('Received: ' message);
messageDOM.appendChild(contentDOM);
messagesDOM.appendChild(messageDOM);
};
</script>
</body>
</html>
Который затем работает с curl,
curl -H "content-type: application/json" -d '{"message": "Hello"}' localhost:5000/telepath
Обратите внимание, что сервер отправит все полученные данные JSON клиенту, но клиент использует только message
ключ.
Комментарии:
1. не могли бы вы привести полный подробный рабочий пример, пожалуйста, я предлагаю награду в 100 баллов 😉
2. Да, я только что добавил полный подробный рабочий пример. Это позволяет вам отправлять сообщения по маршруту / telepath, который затем отправляется подключенным клиентам.