Some more project structure
このコミットが含まれているのは:
コミット
1e6563c4a2
|
@ -42,9 +42,10 @@ async def create_app():
|
||||||
assert app.config['MAX_CHAT_MESSAGES'] >= app.config['MAX_CHAT_SCROLLBACK']
|
assert app.config['MAX_CHAT_MESSAGES'] >= app.config['MAX_CHAT_SCROLLBACK']
|
||||||
assert app.config['THRESHOLD_ABSENT'] >= app.config['THRESHOLD_IDLE']
|
assert app.config['THRESHOLD_ABSENT'] >= app.config['THRESHOLD_IDLE']
|
||||||
|
|
||||||
app.chat = {'messages': OrderedDict(), 'nonce_hashes': set()}
|
app.messages_by_id = OrderedDict()
|
||||||
app.users = {}
|
app.users_by_token = {}
|
||||||
app.websockets = set()
|
app.messages = app.messages_by_id.values()
|
||||||
|
app.users = app.users_by_token.values()
|
||||||
app.segments_directory_cache = DirectoryCache(config['stream']['segments_dir'])
|
app.segments_directory_cache = DirectoryCache(config['stream']['segments_dir'])
|
||||||
|
|
||||||
async with app.app_context():
|
async with app.app_context():
|
||||||
|
|
|
@ -1,22 +1,37 @@
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from quart import escape
|
from quart import current_app, escape
|
||||||
|
|
||||||
from anonstream.user import users_for_websocket
|
|
||||||
from anonstream.helpers.chat import generate_nonce_hash
|
from anonstream.helpers.chat import generate_nonce_hash
|
||||||
|
from anonstream.utils.chat import message_for_websocket
|
||||||
|
|
||||||
|
MESSAGES_BY_ID = current_app.messages_by_id
|
||||||
|
MESSAGES = current_app.messages
|
||||||
|
USERS_BY_TOKEN = current_app.users_by_token
|
||||||
|
USERS = current_app.users
|
||||||
|
|
||||||
class Rejected(Exception):
|
class Rejected(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def broadcast(websockets, payload):
|
async def broadcast(users, payload):
|
||||||
for queue in websockets:
|
for user in users:
|
||||||
await queue.put(payload)
|
for queue in user['websockets']:
|
||||||
|
await queue.put(payload)
|
||||||
|
|
||||||
async def add_chat_message(chat, users, websockets, user, nonce, comment):
|
def messages_for_websocket():
|
||||||
|
return list(map(
|
||||||
|
lambda message: message_for_websocket(
|
||||||
|
user=USERS_BY_TOKEN[message['token']],
|
||||||
|
message=message,
|
||||||
|
),
|
||||||
|
MESSAGES,
|
||||||
|
))
|
||||||
|
|
||||||
|
async def add_chat_message(user, nonce, comment):
|
||||||
# check message
|
# check message
|
||||||
nonce_hash = generate_nonce_hash(nonce)
|
message_id = generate_nonce_hash(nonce)
|
||||||
if nonce_hash in chat['nonce_hashes']:
|
if message_id in MESSAGES_BY_ID:
|
||||||
raise Rejected('Discarded suspected duplicate message')
|
raise Rejected('Discarded suspected duplicate message')
|
||||||
if len(comment) == 0:
|
if len(comment) == 0:
|
||||||
raise Rejected('Message was empty')
|
raise Rejected('Message was empty')
|
||||||
|
@ -25,17 +40,19 @@ async def add_chat_message(chat, users, websockets, user, nonce, comment):
|
||||||
timestamp_ms = time.time_ns() // 1_000_000
|
timestamp_ms = time.time_ns() // 1_000_000
|
||||||
timestamp = timestamp_ms // 1000
|
timestamp = timestamp_ms // 1000
|
||||||
try:
|
try:
|
||||||
last_message = next(reversed(chat['messages'].values()))
|
last_message = next(reversed(MESSAGES))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
message_id = timestamp_ms
|
seq = timestamp_ms
|
||||||
else:
|
else:
|
||||||
if timestamp <= last_message['id']:
|
if timestamp_ms > last_message['seq']:
|
||||||
message_id = last_message['id'] + 1
|
seq = timestamp_ms
|
||||||
|
else:
|
||||||
|
seq = last_message['seq'] + 1
|
||||||
dt = datetime.utcfromtimestamp(timestamp)
|
dt = datetime.utcfromtimestamp(timestamp)
|
||||||
markup = escape(comment)
|
markup = escape(comment)
|
||||||
chat['messages'][message_id] = {
|
MESSAGES_BY_ID[message_id] = {
|
||||||
'id': message_id,
|
'id': message_id,
|
||||||
'nonce_hash': nonce_hash,
|
'seq': seq,
|
||||||
'token': user['token'],
|
'token': user['token'],
|
||||||
'timestamp': timestamp,
|
'timestamp': timestamp,
|
||||||
'date': dt.strftime('%Y-%m-%d'),
|
'date': dt.strftime('%Y-%m-%d'),
|
||||||
|
@ -45,15 +62,12 @@ async def add_chat_message(chat, users, websockets, user, nonce, comment):
|
||||||
'markup': markup,
|
'markup': markup,
|
||||||
}
|
}
|
||||||
|
|
||||||
# collect nonce hash
|
|
||||||
chat['nonce_hashes'].add(nonce_hash)
|
|
||||||
|
|
||||||
# broadcast message to websockets
|
# broadcast message to websockets
|
||||||
await broadcast(
|
await broadcast(
|
||||||
websockets,
|
USERS,
|
||||||
payload={
|
payload={
|
||||||
'type': 'chat',
|
'type': 'chat',
|
||||||
'id': message_id,
|
'seq': seq,
|
||||||
'token_hash': user['token_hash'],
|
'token_hash': user['token_hash'],
|
||||||
'markup': markup,
|
'markup': markup,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ def generate_token_hash(token):
|
||||||
digest = hashlib.sha256(parts).digest()
|
digest = hashlib.sha256(parts).digest()
|
||||||
return base64.b32encode(digest)[:26].lower().decode()
|
return base64.b32encode(digest)[:26].lower().decode()
|
||||||
|
|
||||||
def generate_user(token, broadcaster, timestamp):
|
def generate_user(timestamp, token, broadcaster):
|
||||||
colour = generate_colour(
|
colour = generate_colour(
|
||||||
seed='name\0' + token,
|
seed='name\0' + token,
|
||||||
bg=CONFIG['CHAT_BACKGROUND_COLOUR'],
|
bg=CONFIG['CHAT_BACKGROUND_COLOUR'],
|
||||||
|
@ -23,6 +23,7 @@ def generate_user(token, broadcaster, timestamp):
|
||||||
return {
|
return {
|
||||||
'token': token,
|
'token': token,
|
||||||
'token_hash': generate_token_hash(token),
|
'token_hash': generate_token_hash(token),
|
||||||
|
'websockets': set(),
|
||||||
'broadcaster': broadcaster,
|
'broadcaster': broadcaster,
|
||||||
'name': None,
|
'name': None,
|
||||||
'color': colour_to_color(colour),
|
'color': colour_to_color(colour),
|
||||||
|
@ -49,7 +50,10 @@ def is_idle(timestamp, user):
|
||||||
return is_present(timestamp, user) and not is_watching(timestamp, user)
|
return is_present(timestamp, user) and not is_watching(timestamp, user)
|
||||||
|
|
||||||
def is_present(timestamp, user):
|
def is_present(timestamp, user):
|
||||||
return user['seen']['last'] >= timestamp - CONFIG['THRESHOLD_ABSENT']
|
return (
|
||||||
|
user['seen']['last'] >= timestamp - CONFIG['THRESHOLD_ABSENT']
|
||||||
|
or len(user['websockets']) > 0
|
||||||
|
)
|
||||||
|
|
||||||
def is_absent(timestamp, user):
|
def is_absent(timestamp, user):
|
||||||
return not is_present(timestamp, user)
|
return not is_present(timestamp, user)
|
||||||
|
|
|
@ -24,8 +24,8 @@ async def nojs_chat(user):
|
||||||
return await render_template(
|
return await render_template(
|
||||||
'nojs_chat.html',
|
'nojs_chat.html',
|
||||||
user=user,
|
user=user,
|
||||||
users=current_app.users,
|
users_by_token=current_app.users_by_token,
|
||||||
messages=current_app.chat['messages'].values(),
|
messages=current_app.messages,
|
||||||
get_default_name=get_default_name,
|
get_default_name=get_default_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,14 +53,7 @@ async def nojs_submit_message(user):
|
||||||
nonce = form.get('nonce', '')
|
nonce = form.get('nonce', '')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await add_chat_message(
|
await add_chat_message(user, nonce, comment)
|
||||||
chat=current_app.chat,
|
|
||||||
users=current_app.users,
|
|
||||||
websockets=current_app.websockets,
|
|
||||||
user=user,
|
|
||||||
nonce=nonce,
|
|
||||||
comment=comment,
|
|
||||||
)
|
|
||||||
except Rejected as e:
|
except Rejected as e:
|
||||||
notice, *_ = e.args
|
notice, *_ = e.args
|
||||||
notice_id = add_notice(user, notice)
|
notice_id = add_notice(user, notice)
|
||||||
|
|
|
@ -9,21 +9,11 @@ from anonstream.routes.wrappers import with_user_from
|
||||||
@with_user_from(websocket)
|
@with_user_from(websocket)
|
||||||
async def live(user):
|
async def live(user):
|
||||||
queue = asyncio.Queue()
|
queue = asyncio.Queue()
|
||||||
current_app.websockets.add(queue)
|
user['websockets'].add(queue)
|
||||||
|
|
||||||
producer = websocket_outbound(
|
producer = websocket_outbound(queue)
|
||||||
queue=queue,
|
consumer = websocket_inbound(queue, user)
|
||||||
messages=current_app.chat['messages'].values(),
|
|
||||||
users=current_app.users,
|
|
||||||
)
|
|
||||||
consumer = websocket_inbound(
|
|
||||||
queue=queue,
|
|
||||||
chat=current_app.chat,
|
|
||||||
users=current_app.users,
|
|
||||||
connected_websockets=current_app.websockets,
|
|
||||||
user=user,
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
await asyncio.gather(producer, consumer)
|
await asyncio.gather(producer, consumer)
|
||||||
finally:
|
finally:
|
||||||
current_app.websockets.remove(queue)
|
user['websockets'].remove(queue)
|
||||||
|
|
|
@ -5,17 +5,22 @@ from quart import current_app, request, abort, make_response
|
||||||
from werkzeug.security import check_password_hash
|
from werkzeug.security import check_password_hash
|
||||||
|
|
||||||
from anonstream.user import sunset, user_for_websocket
|
from anonstream.user import sunset, user_for_websocket
|
||||||
from anonstream.websocket import broadcast
|
from anonstream.chat import broadcast
|
||||||
from anonstream.helpers.user import generate_user
|
from anonstream.helpers.user import generate_user
|
||||||
from anonstream.utils.user import generate_token
|
from anonstream.utils.user import generate_token
|
||||||
|
|
||||||
|
CONFIG = current_app.config
|
||||||
|
MESSAGES = current_app.messages
|
||||||
|
USERS_BY_TOKEN = current_app.users_by_token
|
||||||
|
USERS = current_app.users
|
||||||
|
|
||||||
def check_auth(context):
|
def check_auth(context):
|
||||||
auth = context.authorization
|
auth = context.authorization
|
||||||
return (
|
return (
|
||||||
auth is not None
|
auth is not None
|
||||||
and auth.type == "basic"
|
and auth.type == "basic"
|
||||||
and auth.username == current_app.config["AUTH_USERNAME"]
|
and auth.username == CONFIG["AUTH_USERNAME"]
|
||||||
and check_password_hash(current_app.config["AUTH_PWHASH"], auth.password)
|
and check_password_hash(CONFIG["AUTH_PWHASH"], auth.password)
|
||||||
)
|
)
|
||||||
|
|
||||||
def auth_required(f):
|
def auth_required(f):
|
||||||
|
@ -44,40 +49,40 @@ def with_user_from(context):
|
||||||
# Check if broadcaster
|
# Check if broadcaster
|
||||||
broadcaster = check_auth(context)
|
broadcaster = check_auth(context)
|
||||||
if broadcaster:
|
if broadcaster:
|
||||||
token = current_app.config['AUTH_TOKEN']
|
token = CONFIG['AUTH_TOKEN']
|
||||||
else:
|
else:
|
||||||
token = context.args.get('token') or context.cookies.get('token') or generate_token()
|
token = context.args.get('token') or context.cookies.get('token') or generate_token()
|
||||||
|
|
||||||
# Remove non-visible absent users
|
# Remove non-visible absent users
|
||||||
token_hashes = sunset(
|
sunsetted_token_hashes = sunset(
|
||||||
messages=current_app.chat['messages'].values(),
|
messages=MESSAGES,
|
||||||
users=current_app.users,
|
users_by_token=USERS_BY_TOKEN,
|
||||||
)
|
)
|
||||||
if len(token_hashes) > 0:
|
if sunsetted_token_hashes:
|
||||||
await broadcast(
|
await broadcast(
|
||||||
current_app.websockets,
|
users=USERS,
|
||||||
payload={
|
payload={
|
||||||
'type': 'rem-users',
|
'type': 'rem-users',
|
||||||
'token_hashes': token_hashes,
|
'token_hashes': sunsetted_token_hashes,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update / create user
|
# Update / create user
|
||||||
user = current_app.users.get(token)
|
user = USERS_BY_TOKEN.get(token)
|
||||||
if user is not None:
|
if user is not None:
|
||||||
user['seen']['last'] = timestamp
|
user['seen']['last'] = timestamp
|
||||||
else:
|
else:
|
||||||
user = generate_user(
|
user = generate_user(
|
||||||
secret=current_app.config['SECRET_KEY'],
|
timestamp=timestamp,
|
||||||
token=token,
|
token=token,
|
||||||
broadcaster=broadcaster,
|
broadcaster=broadcaster,
|
||||||
timestamp=timestamp,
|
|
||||||
)
|
)
|
||||||
current_app.users[token] = user
|
USERS_BY_TOKEN[token] = user
|
||||||
await broadcast(
|
await broadcast(
|
||||||
current_app.websockets,
|
USERS,
|
||||||
payload={
|
payload={
|
||||||
'type': 'add-user',
|
'type': 'add-user',
|
||||||
|
'token_hash': user['token_hash'],
|
||||||
'user': user_for_websocket(user),
|
'user': user_for_websocket(user),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -52,7 +52,7 @@ const create_chat_message = (object) => {
|
||||||
|
|
||||||
const chat_message = document.createElement("li");
|
const chat_message = document.createElement("li");
|
||||||
chat_message.classList.add("chat-message");
|
chat_message.classList.add("chat-message");
|
||||||
chat_message.dataset.id = object.id;
|
chat_message.dataset.seq = object.seq;
|
||||||
chat_message.dataset.tokenHash = object.token_hash;
|
chat_message.dataset.tokenHash = object.token_hash;
|
||||||
|
|
||||||
const chat_message_name = document.createElement("span");
|
const chat_message_name = document.createElement("span");
|
||||||
|
@ -126,11 +126,11 @@ const on_websocket_message = (event) => {
|
||||||
users = receipt.users;
|
users = receipt.users;
|
||||||
update_user_styles();
|
update_user_styles();
|
||||||
|
|
||||||
const ids = new Set(receipt.chat.map((message) => {return message.id;}));
|
const seqs = new Set(receipt.messages.map((message) => {return message.seq;}));
|
||||||
const to_delete = [];
|
const to_delete = [];
|
||||||
for (const chat_message of chat_messages.children) {
|
for (const chat_message of chat_messages.children) {
|
||||||
const chat_message_id = parseInt(chat_message.dataset.id);
|
const chat_message_seq = parseInt(chat_message.dataset.seq);
|
||||||
if (!ids.has(chat_message_id)) {
|
if (!seqs.has(chat_message_seq)) {
|
||||||
to_delete.push(chat_message);
|
to_delete.push(chat_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,9 +138,10 @@ const on_websocket_message = (event) => {
|
||||||
chat_message.remove();
|
chat_message.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
const last_id = Math.max(...[...chat_messages.children].map((element) => parseInt(element.dataset.id)));
|
const last = chat_messages.children.length == 0 ? null : chat_messages.children[chat_messages.children.length - 1];
|
||||||
for (const message of receipt.chat) {
|
const last_seq = last === null ? null : parseInt(last.dataset.seq);
|
||||||
if (message.id > last_id) {
|
for (const message of receipt.messages) {
|
||||||
|
if (message.seq > last_seq) {
|
||||||
const chat_message = create_chat_message(message);
|
const chat_message = create_chat_message(message);
|
||||||
chat_messages.insertAdjacentElement("beforeend", chat_message);
|
chat_messages.insertAdjacentElement("beforeend", chat_message);
|
||||||
}
|
}
|
||||||
|
@ -184,7 +185,7 @@ const on_websocket_message = (event) => {
|
||||||
|
|
||||||
case "add-user":
|
case "add-user":
|
||||||
console.log("ws add-user", receipt);
|
console.log("ws add-user", receipt);
|
||||||
users[receipt.user.token_hash] = receipt.user;
|
users[receipt.token_hash] = receipt.user;
|
||||||
update_user_styles();
|
update_user_styles();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
<ul id="chat-messages">
|
<ul id="chat-messages">
|
||||||
{% for message in messages | reverse %}
|
{% for message in messages | reverse %}
|
||||||
<li class="chat-message">
|
<li class="chat-message">
|
||||||
{% with user = users[message.token] %}
|
{% with user = users_by_token[message.token] %}
|
||||||
<span class="chat-message__name" style="color:{{ user.color }};" data-id="{{ message.id }}">{{ user.name or get_default_name(user) }}</span>: <span class="chat-message__markup">{{ message.markup }}</span>
|
<span class="chat-message__name" style="color:{{ user.color }};" data-id="{{ message.id }}">{{ user.name or get_default_name(user) }}</span>: <span class="chat-message__markup">{{ message.markup }}</span>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -10,6 +10,8 @@ from anonstream.utils.colour import color_to_colour, get_contrast, NotAColor
|
||||||
from anonstream.utils.user import user_for_websocket
|
from anonstream.utils.user import user_for_websocket
|
||||||
|
|
||||||
CONFIG = current_app.config
|
CONFIG = current_app.config
|
||||||
|
MESSAGES = current_app.messages
|
||||||
|
USERS = current_app.users
|
||||||
|
|
||||||
class BadAppearance(Exception):
|
class BadAppearance(Exception):
|
||||||
pass
|
pass
|
||||||
|
@ -71,19 +73,19 @@ def see(user):
|
||||||
user['seen']['last'] = int(time.time())
|
user['seen']['last'] = int(time.time())
|
||||||
|
|
||||||
@with_timestamp
|
@with_timestamp
|
||||||
def users_for_websocket(timestamp, messages, users):
|
def users_for_websocket(timestamp):
|
||||||
visible_users = filter(
|
visible_users = filter(
|
||||||
lambda user: is_visible(timestamp, messages, user),
|
lambda user: is_visible(timestamp, MESSAGES, user),
|
||||||
users.values(),
|
USERS,
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
user['token_hash']: user_for_websocket(user, include_token_hash=False)
|
user['token_hash']: user_for_websocket(user)
|
||||||
for user in visible_users
|
for user in visible_users
|
||||||
}
|
}
|
||||||
|
|
||||||
last_checkup = -inf
|
last_checkup = -inf
|
||||||
|
|
||||||
def sunset(messages, users):
|
def sunset(messages, users_by_token):
|
||||||
global last_checkup
|
global last_checkup
|
||||||
|
|
||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
|
@ -91,13 +93,13 @@ def sunset(messages, users):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
to_delete = []
|
to_delete = []
|
||||||
for token in users:
|
for token in users_by_token:
|
||||||
user = users[token]
|
user = users_by_token[token]
|
||||||
if not is_visible(timestamp, messages, user):
|
if not is_visible(timestamp, messages, user):
|
||||||
to_delete.append(token)
|
to_delete.append(token)
|
||||||
|
|
||||||
for index, token in enumerate(to_delete):
|
for index, token in enumerate(to_delete):
|
||||||
to_delete[index] = users.pop(token)['token_hash']
|
to_delete[index] = users_by_token.pop(token)['token_hash']
|
||||||
|
|
||||||
last_checkup = timestamp
|
last_checkup = timestamp
|
||||||
return to_delete
|
return to_delete
|
||||||
|
|
|
@ -8,11 +8,9 @@ class NonceReuse(Exception):
|
||||||
def generate_nonce():
|
def generate_nonce():
|
||||||
return secrets.token_urlsafe(16)
|
return secrets.token_urlsafe(16)
|
||||||
|
|
||||||
def message_for_websocket(users, message):
|
def message_for_websocket(user, message):
|
||||||
message_keys = ('id', 'date', 'time_minutes', 'time_seconds', 'markup')
|
message_keys = ('seq', 'date', 'time_minutes', 'time_seconds', 'markup')
|
||||||
user_keys = ('token_hash',)
|
user_keys = ('token_hash',)
|
||||||
|
|
||||||
user = users[message['token']]
|
|
||||||
return {
|
return {
|
||||||
**{key: message[key] for key in message_keys},
|
**{key: message[key] for key in message_keys},
|
||||||
**{key: user[key] for key in user_keys},
|
**{key: user[key] for key in user_keys},
|
||||||
|
|
|
@ -9,10 +9,8 @@ from quart import escape, Markup
|
||||||
def generate_token():
|
def generate_token():
|
||||||
return secrets.token_hex(16)
|
return secrets.token_hex(16)
|
||||||
|
|
||||||
def user_for_websocket(user, include_token_hash=True):
|
def user_for_websocket(user):
|
||||||
keys = ['broadcaster', 'name', 'color', 'tripcode']
|
keys = ['broadcaster', 'name', 'color', 'tripcode']
|
||||||
if include_token_hash:
|
|
||||||
keys.append('token_hash')
|
|
||||||
return {key: user[key] for key in keys}
|
return {key: user[key] for key in keys}
|
||||||
|
|
||||||
def concatenate_for_notice(string, *tuples):
|
def concatenate_for_notice(string, *tuples):
|
||||||
|
|
|
@ -3,26 +3,23 @@ import asyncio
|
||||||
from quart import current_app, websocket
|
from quart import current_app, websocket
|
||||||
|
|
||||||
from anonstream.stream import get_stream_title, get_stream_uptime
|
from anonstream.stream import get_stream_title, get_stream_uptime
|
||||||
from anonstream.chat import broadcast, add_chat_message, Rejected
|
from anonstream.chat import messages_for_websocket, add_chat_message, Rejected
|
||||||
from anonstream.user import users_for_websocket, see
|
from anonstream.user import users_for_websocket, see
|
||||||
from anonstream.wrappers import with_first_argument
|
from anonstream.wrappers import with_first_argument
|
||||||
from anonstream.helpers.user import is_present
|
from anonstream.helpers.user import is_present
|
||||||
from anonstream.utils.chat import generate_nonce, message_for_websocket
|
from anonstream.utils.chat import generate_nonce
|
||||||
from anonstream.utils.websocket import parse_websocket_data, Malformed
|
from anonstream.utils.websocket import parse_websocket_data, Malformed
|
||||||
|
|
||||||
CONFIG = current_app.config
|
CONFIG = current_app.config
|
||||||
|
|
||||||
async def websocket_outbound(queue, messages, users):
|
async def websocket_outbound(queue):
|
||||||
payload = {
|
payload = {
|
||||||
'type': 'init',
|
'type': 'init',
|
||||||
'nonce': generate_nonce(),
|
'nonce': generate_nonce(),
|
||||||
'title': get_stream_title(),
|
'title': get_stream_title(),
|
||||||
'uptime': get_stream_uptime(),
|
'uptime': get_stream_uptime(),
|
||||||
'chat': list(map(
|
'messages': messages_for_websocket(),
|
||||||
with_first_argument(users)(message_for_websocket),
|
'users': users_for_websocket(),
|
||||||
messages,
|
|
||||||
)),
|
|
||||||
'users': users_for_websocket(messages, users),
|
|
||||||
'default': {
|
'default': {
|
||||||
True: CONFIG['DEFAULT_HOST_NAME'],
|
True: CONFIG['DEFAULT_HOST_NAME'],
|
||||||
False: CONFIG['DEFAULT_ANON_NAME'],
|
False: CONFIG['DEFAULT_ANON_NAME'],
|
||||||
|
@ -33,7 +30,7 @@ async def websocket_outbound(queue, messages, users):
|
||||||
payload = await queue.get()
|
payload = await queue.get()
|
||||||
await websocket.send_json(payload)
|
await websocket.send_json(payload)
|
||||||
|
|
||||||
async def websocket_inbound(queue, chat, users, connected_websockets, user):
|
async def websocket_inbound(queue, user):
|
||||||
while True:
|
while True:
|
||||||
receipt = await websocket.receive_json()
|
receipt = await websocket.receive_json()
|
||||||
see(user)
|
see(user)
|
||||||
|
@ -47,14 +44,7 @@ async def websocket_inbound(queue, chat, users, connected_websockets, user):
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
markup = await add_chat_message(
|
markup = await add_chat_message(user, nonce, comment)
|
||||||
chat,
|
|
||||||
users,
|
|
||||||
connected_websockets,
|
|
||||||
user,
|
|
||||||
nonce,
|
|
||||||
comment,
|
|
||||||
)
|
|
||||||
except Rejected as e:
|
except Rejected as e:
|
||||||
notice, *_ = e.args
|
notice, *_ = e.args
|
||||||
payload = {
|
payload = {
|
||||||
|
|
読み込み中…
新しいイシューから参照