anonstream/anonstream/chat.py

89 行
2.6 KiB
Python

# SPDX-FileCopyrightText: 2022 n9k [https://git.076.ne.jp/ninya9k]
# SPDX-License-Identifier: AGPL-3.0-or-later
import time
from datetime import datetime
from quart import current_app, escape
from anonstream.broadcast import broadcast, broadcast_users_update
from anonstream.helpers.chat import generate_nonce_hash, get_scrollback
from anonstream.utils.chat import get_message_for_websocket
CONFIG = current_app.config
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(ValueError):
pass
def get_all_messages_for_websocket():
return list(map(
lambda message: get_message_for_websocket(
user=USERS_BY_TOKEN[message['token']],
message=message,
),
get_scrollback(MESSAGES),
))
def add_chat_message(user, nonce, comment, ignore_empty=False):
# Special case: if the comment is empty, do nothing and return
if ignore_empty and len(comment) == 0:
return False
# Check message
message_id = generate_nonce_hash(nonce)
if message_id in MESSAGES_BY_ID:
raise Rejected('Discarded suspected duplicate message')
if len(comment) == 0:
raise Rejected('Message was empty')
if len(comment) > 512:
raise Rejected('Message exceeded 512 chars')
# Create and add message
timestamp_ms = time.time_ns() // 1_000_000
timestamp = timestamp_ms // 1000
try:
last_message = next(reversed(MESSAGES))
except StopIteration:
seq = timestamp_ms
else:
if timestamp_ms > last_message['seq']:
seq = timestamp_ms
else:
seq = last_message['seq'] + 1
dt = datetime.utcfromtimestamp(timestamp)
markup = escape(comment)
message = {
'id': message_id,
'seq': seq,
'token': user['token'],
'timestamp': timestamp,
'date': dt.strftime('%Y-%m-%d'),
'time_minutes': dt.strftime('%H:%M'),
'time_seconds': dt.strftime('%H:%M:%S'),
'nomarkup': comment,
'markup': markup,
}
MESSAGES_BY_ID[message_id] = message
while len(MESSAGES_BY_ID) > CONFIG['MAX_CHAT_MESSAGES']:
MESSAGES_BY_ID.pop(last=False)
# Broadcast a users update to all websockets,
# in case this message is from a new user
broadcast_users_update()
# Broadcast message to websockets
broadcast(
USERS,
payload={
'type': 'message',
'message': get_message_for_websocket(user, message),
},
)
return True