Nojs comment submission, notify for rejected comments
Fix with-user wrapper (wasn't collecting users)
このコミットが含まれているのは:
コミット
694c6a4995
|
@ -14,20 +14,21 @@ async def create_app():
|
|||
|
||||
auth_password = secrets.token_urlsafe(6)
|
||||
auth_pwhash = generate_password_hash(auth_password)
|
||||
print('Broadcaster username:', config['auth_username'])
|
||||
print('Broadcaster username:', config['auth']['username'])
|
||||
print('Broadcaster password:', auth_password)
|
||||
|
||||
app = Quart('anonstream')
|
||||
app.config['SECRET_KEY'] = config['secret_key'].encode()
|
||||
app.config['AUTH_USERNAME'] = config['auth_username']
|
||||
app.config['AUTH_USERNAME'] = config['auth']['username']
|
||||
app.config['AUTH_PWHASH'] = auth_pwhash
|
||||
app.config['AUTH_TOKEN'] = generate_token()
|
||||
app.config['DEFAULT_HOST_NAME'] = config['default_host_name']
|
||||
app.config['DEFAULT_ANON_NAME'] = config['default_anon_name']
|
||||
app.config['DEFAULT_HOST_NAME'] = config['names']['broadcaster']
|
||||
app.config['DEFAULT_ANON_NAME'] = config['names']['anonymous']
|
||||
app.config['LIMIT_NOTICES'] = config['limits']['notices']
|
||||
app.chat = OrderedDict()
|
||||
app.users = {}
|
||||
app.websockets = set()
|
||||
app.segments_directory_cache = DirectoryCache(config['segments_dir'])
|
||||
app.segments_directory_cache = DirectoryCache(config['stream']['segments_dir'])
|
||||
|
||||
async with app.app_context():
|
||||
import anonstream.routes
|
||||
|
|
|
@ -2,9 +2,21 @@ from datetime import datetime
|
|||
|
||||
from quart import escape
|
||||
|
||||
def add_chat_message(chat, message_id, token, text):
|
||||
class Rejected(Exception):
|
||||
pass
|
||||
|
||||
async def broadcast(websockets, payload):
|
||||
for queue in websockets:
|
||||
await queue.put(payload)
|
||||
|
||||
async def add_chat_message(chat, websockets, token, message_id, comment):
|
||||
# check message
|
||||
if len(comment) == 0:
|
||||
raise Rejected('Message was empty')
|
||||
|
||||
# add message
|
||||
dt = datetime.utcnow()
|
||||
markup = escape(text)
|
||||
markup = escape(comment)
|
||||
chat[message_id] = {
|
||||
'id': message_id,
|
||||
'token': token,
|
||||
|
@ -12,6 +24,19 @@ def add_chat_message(chat, message_id, token, text):
|
|||
'date': dt.strftime('%Y-%m-%d'),
|
||||
'time_minutes': dt.strftime('%H:%M'),
|
||||
'time_seconds': dt.strftime('%H:%M:%S'),
|
||||
'nomarkup': text,
|
||||
'nomarkup': comment,
|
||||
'markup': markup,
|
||||
}
|
||||
|
||||
# broadcast message to websockets
|
||||
await broadcast(
|
||||
websockets,
|
||||
payload={
|
||||
'type': 'chat',
|
||||
'color': '#c7007f',
|
||||
'name': 'Anonymous',
|
||||
'markup': markup,
|
||||
}
|
||||
)
|
||||
|
||||
return markup
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import asyncio
|
||||
|
||||
from quart import current_app, request, render_template, make_response, redirect, websocket
|
||||
from quart import current_app, request, render_template, make_response, redirect, websocket, url_for
|
||||
|
||||
from anonstream.stream import get_stream_title
|
||||
from anonstream.segments import CatSegments, Offline
|
||||
from anonstream.users import get_default_name
|
||||
from anonstream.users import get_default_name, add_notice, pop_notice
|
||||
from anonstream.wrappers import with_user_from, auth_required
|
||||
from anonstream.websocket import websocket_outbound, websocket_inbound
|
||||
from anonstream.chat import add_chat_message, Rejected
|
||||
from anonstream.utils.chat import create_message, generate_nonce, NonceReuse
|
||||
|
||||
@current_app.route('/')
|
||||
@with_user_from(request)
|
||||
|
@ -69,8 +71,51 @@ async def nojs_chat(user):
|
|||
@current_app.route('/chat/form.html')
|
||||
@with_user_from(request)
|
||||
async def nojs_form(user):
|
||||
notice_id = request.args.get('notice', type=int)
|
||||
prefer_chat_form = request.args.get('landing') != 'appearance'
|
||||
return await render_template(
|
||||
'nojs_form.html',
|
||||
user=user,
|
||||
notice=pop_notice(user, notice_id),
|
||||
prefer_chat_form=prefer_chat_form,
|
||||
nonce=generate_nonce(),
|
||||
default_name=get_default_name(user),
|
||||
)
|
||||
|
||||
@current_app.post('/chat/message')
|
||||
@with_user_from(request)
|
||||
async def nojs_submit_message(user):
|
||||
form = await request.form
|
||||
comment = form.get('comment', '')
|
||||
nonce = form.get('nonce', '')
|
||||
|
||||
try:
|
||||
message_id, _, _ = create_message(
|
||||
message_ids=current_app.chat.keys(),
|
||||
secret=current_app.config['SECRET_KEY'],
|
||||
nonce=nonce,
|
||||
comment=comment,
|
||||
)
|
||||
except NonceReuse:
|
||||
notice_id = add_notice(user, 'Discarded suspected duplicate message')
|
||||
else:
|
||||
try:
|
||||
await add_chat_message(
|
||||
current_app.chat,
|
||||
current_app.websockets,
|
||||
user['token'],
|
||||
message_id,
|
||||
comment
|
||||
)
|
||||
except Rejected as e:
|
||||
notice, *_ = e.args
|
||||
notice_id = add_notice(user, notice)
|
||||
else:
|
||||
notice_id = None
|
||||
|
||||
return redirect(url_for('nojs_form', token=user['token'], notice=notice_id))
|
||||
|
||||
@current_app.post('/chat/appearance')
|
||||
@with_user_from(request)
|
||||
async def nojs_submit_appearance(user):
|
||||
pass
|
||||
|
|
|
@ -8,7 +8,7 @@ const jsmarkup_chat_messages = '<ul id="chat-messages_js" data-js="true"></ul>';
|
|||
const jsmarkup_chat_form = `\
|
||||
<form id="chat-form_js" data-js="true" action="/chat" method="post">
|
||||
<input id="chat-form_js__nonce" type="hidden" name="nonce" value="">
|
||||
<textarea id="chat-form_js__message" name="message" maxlength="512" required placeholder="Send a message..." rows="1"></textarea>
|
||||
<textarea id="chat-form_js__comment" name="comment" maxlength="512" required placeholder="Send a message..." rows="1"></textarea>
|
||||
<div id="chat-live">
|
||||
<span id="chat-live__ball"></span>
|
||||
<span id="chat-live__status">Not connected to chat</span>
|
||||
|
@ -45,24 +45,24 @@ const on_websocket_message = (event) => {
|
|||
const receipt = JSON.parse(event.data);
|
||||
switch (receipt.type) {
|
||||
case "error":
|
||||
console.log("server sent error via websocket", receipt);
|
||||
console.log("ws error", receipt);
|
||||
break;
|
||||
|
||||
case "init":
|
||||
console.log("init", receipt);
|
||||
console.log("ws init", receipt);
|
||||
chat_form_nonce.value = receipt.nonce;
|
||||
info_title.innerText = receipt.title;
|
||||
break;
|
||||
|
||||
case "title":
|
||||
console.log("title", receipt);
|
||||
console.log("ws title", receipt);
|
||||
info_title.innerText = receipt.title;
|
||||
break;
|
||||
|
||||
case "ack":
|
||||
console.log("ack", receipt);
|
||||
console.log("ws ack", receipt);
|
||||
if (chat_form_nonce.value === receipt.nonce) {
|
||||
chat_form_message.value = "";
|
||||
chat_form_comment.value = "";
|
||||
} else {
|
||||
console.log("nonce does not match ack", chat_form_nonce, receipt);
|
||||
}
|
||||
|
@ -70,7 +70,15 @@ const on_websocket_message = (event) => {
|
|||
chat_form_nonce.value = receipt.next;
|
||||
break;
|
||||
|
||||
case "reject":
|
||||
console.log("ws reject", receipt);
|
||||
alert(`Rejected: ${receipt.notice}`);
|
||||
chat_form_submit.disabled = false;
|
||||
break;
|
||||
|
||||
case "chat":
|
||||
console.log("ws chat", receipt);
|
||||
|
||||
const chat_message = document.createElement("li");
|
||||
chat_message.classList.add("chat-message");
|
||||
|
||||
|
@ -80,13 +88,13 @@ const on_websocket_message = (event) => {
|
|||
//chat_message_name.dataset.color = receipt.color; // not working in any browser
|
||||
chat_message_name.style.color = receipt.color;
|
||||
|
||||
const chat_message_text = document.createElement("span");
|
||||
chat_message_text.classList.add("chat-message__text");
|
||||
chat_message_text.innerText = receipt.text;
|
||||
const chat_message_markup = document.createElement("span");
|
||||
chat_message_markup.classList.add("chat-message__markup");
|
||||
chat_message_markup.innerHTML = receipt.markup;
|
||||
|
||||
chat_message.insertAdjacentElement("beforeend", chat_message_name);
|
||||
chat_message.insertAdjacentHTML("beforeend", ": ");
|
||||
chat_message.insertAdjacentElement("beforeend", chat_message_text);
|
||||
chat_message.insertAdjacentElement("beforeend", chat_message_markup);
|
||||
|
||||
chat_messages.insertAdjacentElement("beforeend", chat_message);
|
||||
chat_messages_parent.scrollTo({
|
||||
|
@ -95,11 +103,10 @@ const on_websocket_message = (event) => {
|
|||
behavior: "smooth",
|
||||
});
|
||||
|
||||
console.log("chat", receipt);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log("incomprehensible websocket message", message);
|
||||
console.log("incomprehensible websocket message", receipt);
|
||||
}
|
||||
};
|
||||
const chat_live_ball = document.getElementById("chat-live__ball");
|
||||
|
@ -145,11 +152,11 @@ connect_websocket();
|
|||
/* override js-only chat form */
|
||||
const chat_form = document.getElementById("chat-form_js");
|
||||
const chat_form_nonce = document.getElementById("chat-form_js__nonce");
|
||||
const chat_form_message = document.getElementById("chat-form_js__message");
|
||||
const chat_form_comment = document.getElementById("chat-form_js__comment");
|
||||
const chat_form_submit = document.getElementById("chat-form_js__submit");
|
||||
chat_form.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
const payload = {message: chat_form_message.value, nonce: chat_form_nonce.value};
|
||||
const payload = {comment: chat_form_comment.value, nonce: chat_form_nonce.value};
|
||||
chat_form_submit.disabled = true;
|
||||
ws.send(JSON.stringify(payload));
|
||||
});
|
||||
|
|
|
@ -95,7 +95,7 @@ noscript {
|
|||
#chat-form_js__submit {
|
||||
grid-column: 2 / span 1;
|
||||
}
|
||||
#chat-form_js__message {
|
||||
#chat-form_js__comment {
|
||||
grid-column: 1 / span 2;
|
||||
background-color: #434347;
|
||||
border-radius: 4px;
|
||||
|
@ -107,10 +107,10 @@ noscript {
|
|||
color: #c3c3c7;
|
||||
resize: vertical;
|
||||
}
|
||||
#chat-form_js__message:not(:focus):hover {
|
||||
#chat-form_js__comment:not(:focus):hover {
|
||||
border-color: #737377;
|
||||
}
|
||||
#chat-form_js__message:focus {
|
||||
#chat-form_js__comment:focus {
|
||||
background-color: black;
|
||||
border-color: #3584e4;
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ noscript {
|
|||
color: attr("data-color");
|
||||
cursor: default;
|
||||
}
|
||||
.chat-message__text {
|
||||
.chat-message__markup {
|
||||
overflow-wrap: anywhere;
|
||||
line-height: 1.3125;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<style>
|
||||
:root {
|
||||
--link-color: #42a5d7;
|
||||
--padding: 1ch;
|
||||
}
|
||||
body {
|
||||
|
@ -12,20 +13,29 @@
|
|||
color: white;
|
||||
}
|
||||
a {
|
||||
color: #42a5d7;
|
||||
color: var(--link-color);
|
||||
}
|
||||
label {
|
||||
.pseudolink {
|
||||
color: var(--link-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
.pseudolink:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.tripcode {
|
||||
padding: 0 4px;
|
||||
border-radius: 7px;
|
||||
font-family: monospace;
|
||||
align-self: center;
|
||||
cursor: default;
|
||||
}
|
||||
#tripcode {
|
||||
cursor: pointer;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#notice {
|
||||
padding: var(--margin);
|
||||
display: grid;
|
||||
padding: var(--padding);
|
||||
text-align: center;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
|
@ -36,6 +46,7 @@
|
|||
#notice h1 {
|
||||
font-size: 18pt;
|
||||
margin: 0;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
#chat-form, #appearance-form {
|
||||
|
@ -49,7 +60,7 @@
|
|||
grid: auto 2rem / auto 8ch;
|
||||
grid-gap: 0.75ch;
|
||||
}
|
||||
#chat-form__message {
|
||||
#chat-form__comment {
|
||||
resize: none;
|
||||
grid-column: 1 / span 2;
|
||||
background-color: #434347;
|
||||
|
@ -59,10 +70,10 @@
|
|||
padding: 1.5ch;
|
||||
color: #c3c3c7;
|
||||
}
|
||||
#chat-form__message:not(:focus):hover {
|
||||
#chat-form__comment:not(:focus):hover {
|
||||
border-color: #737377;
|
||||
}
|
||||
#chat-form__message:focus {
|
||||
#chat-form__comment:focus {
|
||||
background-color: black;
|
||||
border-color: #3584e4;
|
||||
}
|
||||
|
@ -114,38 +125,48 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
#notice, #appearance-form {
|
||||
#appearance-form {
|
||||
display: none;
|
||||
}
|
||||
#anchor:target > #chat-form {
|
||||
display: none;
|
||||
}
|
||||
#anchor:target > #appearance-form {
|
||||
#appearance:target ~ #appearance-form {
|
||||
display: grid;
|
||||
}
|
||||
#notice:target {
|
||||
display: grid;
|
||||
}
|
||||
#notice:target + #chat-form,
|
||||
#notice:target ~ #appearance-form {
|
||||
#appearance:target ~ #chat-form {
|
||||
display: none;
|
||||
}
|
||||
#chat:target ~ #appearance-form {
|
||||
display: none;
|
||||
}
|
||||
{% if notice != none %}
|
||||
#chat-form {
|
||||
display: none;
|
||||
}
|
||||
#chat:target ~ #chat-form {
|
||||
display: grid;
|
||||
}
|
||||
#chat:target ~ #notice,
|
||||
#appearance:target ~ #notice {
|
||||
display: none;
|
||||
}
|
||||
{% endif %}
|
||||
</style>
|
||||
</head>
|
||||
<body id="anchor">
|
||||
<a href="#chat-form" id="notice">
|
||||
<header><h1>No notice</h1></header>
|
||||
<small>Click to dismiss</small>
|
||||
</a>
|
||||
</article>
|
||||
<form id="chat-form" action="/chat/message">
|
||||
<input type="hidden" name="token" value="{{ user.token }}">
|
||||
<textarea id="chat-form__message" name="text" placeholder="Send a message..." required rows="1"></textarea>
|
||||
<div id="chat-form__exit"><a href="#anchor">Settings</a></div>
|
||||
<input id="chat-form__submit" type="submit" value="Chat">
|
||||
<body>
|
||||
<div id="chat"></div>
|
||||
<div id="appearance"></div>
|
||||
{% if notice != none %}
|
||||
<a id="notice" {% if prefer_chat_form %}href="#chat"{% else %}href="#appearance"{% endif %}>
|
||||
<header><h1>{{ notice }}</h1></header>
|
||||
<small>Click to dismiss</small>
|
||||
</a>
|
||||
{% endif %}
|
||||
<form id="chat-form" action="{{ url_for('nojs_submit_message', token=user.token) }}" method="post">
|
||||
<input type="hidden" name="nonce" value="{{ nonce }}">
|
||||
<textarea id="chat-form__comment" name="comment" placeholder="Send a message..." required rows="1" tabindex="1"></textarea>
|
||||
<div id="chat-form__exit"><a href="#appearance">Settings</a></div>
|
||||
<input id="chat-form__submit" type="submit" value="Chat" tabindex="2">
|
||||
</form>
|
||||
<form id="appearance-form" action="/chat/appearance">
|
||||
<input type="hidden" name="token" value="{{ user.token }}">
|
||||
<form id="appearance-form" action="/{{ url_for('nojs_submit_appearance', token=user.token) }}" method="post">
|
||||
<label for="appearance-form__name">Name:</label>
|
||||
<input id="appearance-form__name" name="name" value="{{ user.name or '' }}" placeholder="{{ user.name or default_name }}">
|
||||
<label id="appearance-form__label-password" for="appearance-form__password">Tripcode:</label>
|
||||
|
@ -153,18 +174,19 @@
|
|||
<input id="cleared-toggle" name="clear-tripcode" type="checkbox">
|
||||
<div id="password-column">
|
||||
{% if user.tripcode == none %}
|
||||
<label class="show-password tripcode" for="password-toggle">(no tripcode)</label>
|
||||
<span class="tripcode">(no tripcode)</span>
|
||||
<label for="password-toggle" class="show-password pseudolink" accesskey="s">set</label>
|
||||
{% else %}
|
||||
<label id="tripcode" for="password-toggle" class="show-password tripcode" style="background-color:{{ user.tripcode.background }};color:{{ user.tripcode.foreground }};">{{ user.tripcode.digest }}</label>
|
||||
<label id="show-cleared" for="cleared-toggle">✗</label>
|
||||
<label id="tripcode" for="password-toggle" class="show-password tripcode" style="background-color:{{ user.tripcode.background }};color:{{ user.tripcode.foreground }};" accesskey="s">{{ user.tripcode.digest }}digest</label>
|
||||
<label id="show-cleared" for="cleared-toggle" class="pseudolink" accesskey="c">✗</label>
|
||||
<div id="cleared" class="tripcode">(cleared)</div>
|
||||
<label id="hide-cleared" for="cleared-toggle">undo</label>
|
||||
<label id="hide-cleared" for="cleared-toggle" class="pseudolink" accesskey="c">undo</label>
|
||||
{% endif %}
|
||||
</div>
|
||||
<input id="appearance-form__password" name="password" type="password"></div>
|
||||
<label id="hide-password" for="password-toggle">✗</label>
|
||||
<input id="appearance-form__password" name="password" type="password" placeholder="(tripcode password)">
|
||||
<label id="hide-password" for="password-toggle" class="pseudolink" accesskey="s">✗</label>
|
||||
<div id="appearance-form__buttons">
|
||||
<div><a href="#chat-form">Return to chat</a></div>
|
||||
<div><a href="#chat">Return to chat</a></div>
|
||||
<input type="submit" value="Update">
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import time
|
||||
|
||||
from quart import current_app
|
||||
|
||||
def get_default_name(user):
|
||||
|
@ -7,3 +9,16 @@ def get_default_name(user):
|
|||
current_app.config['DEFAULT_ANON_NAME']
|
||||
)
|
||||
|
||||
def add_notice(user, notice):
|
||||
notice_id = time.time_ns() // 1_000_000
|
||||
user['notices'][notice_id] = notice
|
||||
if len(user['notices']) > current_app.config['LIMIT_NOTICES']:
|
||||
user['notices'].popitem(last=False)
|
||||
return notice_id
|
||||
|
||||
def pop_notice(user, notice_id):
|
||||
try:
|
||||
notice = user['notices'].pop(notice_id)
|
||||
except KeyError:
|
||||
notice = None
|
||||
return notice
|
||||
|
|
|
@ -2,6 +2,9 @@ import base64
|
|||
import hashlib
|
||||
import secrets
|
||||
|
||||
class NonceReuse(Exception):
|
||||
pass
|
||||
|
||||
def generate_nonce():
|
||||
return secrets.token_urlsafe(16)
|
||||
|
||||
|
@ -9,3 +12,9 @@ def generate_message_id(secret, nonce):
|
|||
parts = secret + b'message-id\0' + nonce.encode()
|
||||
digest = hashlib.sha256(parts).digest()
|
||||
return base64.urlsafe_b64encode(digest)[:22].decode()
|
||||
|
||||
def create_message(message_ids, secret, nonce, comment):
|
||||
message_id = generate_message_id(secret, nonce)
|
||||
if message_id in message_ids:
|
||||
raise NonceReuse
|
||||
return message_id, nonce, comment
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import secrets
|
||||
from collections import OrderedDict
|
||||
|
||||
def generate_token():
|
||||
return secrets.token_hex(16)
|
||||
|
@ -9,6 +10,7 @@ def generate_user(token, broadcaster, timestamp):
|
|||
'broadcaster': broadcaster,
|
||||
'name': None,
|
||||
'tripcode': None,
|
||||
'notices': OrderedDict(),
|
||||
'seen': {
|
||||
'first': timestamp,
|
||||
'last': timestamp,
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
from anonstream.utils.chat import generate_message_id
|
||||
from anonstream.utils.chat import create_message, NonceReuse
|
||||
|
||||
def parse(message_ids, secret, receipt):
|
||||
class Malformed(Exception):
|
||||
pass
|
||||
|
||||
def parse_websocket_data(message_ids, secret, receipt):
|
||||
if not isinstance(receipt, dict):
|
||||
return None, 'not a json object'
|
||||
raise Malformed('not a json object')
|
||||
|
||||
message = receipt.get('message')
|
||||
if not isinstance(message, str):
|
||||
return None, 'malformed chat message'
|
||||
comment = receipt.get('comment')
|
||||
if not isinstance(comment, str):
|
||||
raise Malformed('malformed comment')
|
||||
|
||||
nonce = receipt.get('nonce')
|
||||
if not isinstance(nonce, str):
|
||||
return None, 'malformed nonce'
|
||||
raise Malformed('malformed nonce')
|
||||
|
||||
message_id = generate_message_id(secret, nonce)
|
||||
if message_id in message_ids:
|
||||
return None, 'nonce already used'
|
||||
try:
|
||||
message = create_message(message_ids, secret, nonce, comment)
|
||||
except NonceReuse:
|
||||
raise Malformed('nonce already used')
|
||||
|
||||
return (message, nonce, message_id), None
|
||||
return message
|
||||
|
|
|
@ -3,9 +3,9 @@ import asyncio
|
|||
from quart import websocket
|
||||
|
||||
from anonstream.stream import get_stream_title, get_stream_uptime
|
||||
from anonstream.chat import add_chat_message
|
||||
from anonstream.chat import broadcast, add_chat_message, Rejected
|
||||
from anonstream.utils.chat import generate_nonce
|
||||
from anonstream.utils.websocket import parse
|
||||
from anonstream.utils.websocket import parse_websocket_data
|
||||
|
||||
async def websocket_outbound(queue):
|
||||
payload = {
|
||||
|
@ -23,28 +23,33 @@ async def websocket_outbound(queue):
|
|||
async def websocket_inbound(queue, connected_websockets, token, secret, chat):
|
||||
while True:
|
||||
receipt = await websocket.receive_json()
|
||||
receipt, error = parse(chat.keys(), secret, receipt)
|
||||
if error is not None:
|
||||
try:
|
||||
message_id, nonce, comment = parse_websocket_data(chat.keys(), secret, receipt)
|
||||
except Malformed as e:
|
||||
error , *_ = e.args
|
||||
payload = {
|
||||
'type': 'error',
|
||||
'because': error,
|
||||
}
|
||||
else:
|
||||
text, nonce, message_id = receipt
|
||||
add_chat_message(chat, message_id, token, text)
|
||||
payload = {
|
||||
'type': 'ack',
|
||||
'nonce': nonce,
|
||||
'next': generate_nonce(),
|
||||
}
|
||||
try:
|
||||
markup = await add_chat_message(
|
||||
chat,
|
||||
connected_websockets,
|
||||
token,
|
||||
message_id,
|
||||
comment
|
||||
)
|
||||
except Rejected as e:
|
||||
notice, *_ = e.args
|
||||
payload = {
|
||||
'type': 'reject',
|
||||
'notice': notice,
|
||||
}
|
||||
else:
|
||||
payload = {
|
||||
'type': 'ack',
|
||||
'nonce': nonce,
|
||||
'next': generate_nonce(),
|
||||
}
|
||||
await queue.put(payload)
|
||||
|
||||
if error is None:
|
||||
payload = {
|
||||
'type': 'chat',
|
||||
'color': '#c7007f',
|
||||
'name': 'Anonymous',
|
||||
'text': text,
|
||||
}
|
||||
for other_queue in connected_websockets:
|
||||
await other_queue.put(payload)
|
||||
|
|
|
@ -47,6 +47,7 @@ def with_user_from(context):
|
|||
user['seen']['last'] = timestamp
|
||||
else:
|
||||
user = generate_user(token, broadcaster, timestamp)
|
||||
current_app.users[token] = user
|
||||
return await f(user, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
|
15
config.toml
15
config.toml
|
@ -1,5 +1,14 @@
|
|||
secret_key = "test"
|
||||
auth_username = "broadcaster"
|
||||
|
||||
[auth]
|
||||
username = "broadcaster"
|
||||
|
||||
[stream]
|
||||
segments_dir = "stream/"
|
||||
default_host_name = "Broadcaster"
|
||||
default_anon_name = "Anonymous"
|
||||
|
||||
[names]
|
||||
broadcaster = "Broadcaster"
|
||||
anonymous = "Anonymous"
|
||||
|
||||
[limits]
|
||||
notices = 32
|
||||
|
|
読み込み中…
新しいイシューから参照