mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Implement client message IDs
This commit is contained in:
@@ -7,6 +7,7 @@ from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status,
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import inspect, text
|
||||
import uuid
|
||||
import secrets
|
||||
from user_agents import parse as parse_ua
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
|
||||
@@ -28,6 +29,16 @@ _SERVER_INSTANCE_ID: str | None = None
|
||||
_INSTANCE_ID_FILE = Path(__file__).resolve().parent.parent / ".fromchat_instance_id"
|
||||
|
||||
|
||||
def allocate_user_id(db: Session) -> int:
|
||||
"""First registered user gets id 1; subsequent users get random unique ids."""
|
||||
if db.query(User).count() == 0:
|
||||
return 1
|
||||
while True:
|
||||
candidate = secrets.randbelow(2_147_483_646) + 2
|
||||
if db.query(User).filter(User.id == candidate).first() is None:
|
||||
return candidate
|
||||
|
||||
|
||||
def get_server_instance_id() -> str:
|
||||
"""Stable server fingerprint; UUID generated once and persisted next to the main service package."""
|
||||
global _SERVER_INSTANCE_ID
|
||||
@@ -289,6 +300,7 @@ def register(
|
||||
is_owner = not owner_exists and username == OWNER_USERNAME
|
||||
|
||||
new_user = User(
|
||||
id=allocate_user_id(db),
|
||||
username=username,
|
||||
display_name=display_name,
|
||||
password_hash=hashed_password,
|
||||
|
||||
@@ -37,7 +37,7 @@ from ..service_calls import (
|
||||
get_resumable_upload_data_in_storage,
|
||||
delete_resumable_upload_in_storage,
|
||||
)
|
||||
from .messaging import messagingManager, convert_dm_envelope
|
||||
from .messaging import messagingManager, convert_dm_envelope, convert_dm_envelope_for_user
|
||||
from ..push_service import push_service
|
||||
|
||||
logger = logging.getLogger("uvicorn.error")
|
||||
@@ -360,12 +360,17 @@ async def send_encrypted_message(
|
||||
)
|
||||
|
||||
# Send user-specific WebSocket updates (each user gets only their MEK and files metadata)
|
||||
recipient_payload = convert_dm_envelope(db, dm_envelope, dm_envelope.recipient_id)
|
||||
recipient_payload = convert_dm_envelope_for_user(
|
||||
db, dm_envelope, dm_envelope.recipient_id,
|
||||
)
|
||||
await messagingManager.send_update_to_user(dm_envelope.recipient_id, "dmNew", recipient_payload, db)
|
||||
|
||||
sender_payload = convert_dm_envelope(db, dm_envelope, dm_envelope.sender_id)
|
||||
if request.client_message_id:
|
||||
sender_payload["client_message_id"] = request.client_message_id
|
||||
sender_payload = convert_dm_envelope_for_user(
|
||||
db,
|
||||
dm_envelope,
|
||||
dm_envelope.sender_id,
|
||||
sender_client_message_id=request.client_message_id,
|
||||
)
|
||||
await messagingManager.send_update_to_user(dm_envelope.sender_id, "dmNew", sender_payload, db)
|
||||
|
||||
try:
|
||||
|
||||
@@ -314,6 +314,27 @@ def convert_dm_envelope(db: Session, envelope: DMEnvelope, user_id: int | None =
|
||||
return result
|
||||
|
||||
|
||||
def convert_dm_envelope_for_user(
|
||||
db: Session,
|
||||
envelope: DMEnvelope,
|
||||
user_id: int | None,
|
||||
*,
|
||||
sender_client_message_id: str | None = None,
|
||||
) -> dict:
|
||||
"""
|
||||
Per-user DM payload. [sender_client_message_id] is included only for the sender so clients
|
||||
can match optimistic rows to the server ack; never exposed to the recipient.
|
||||
"""
|
||||
payload = convert_dm_envelope(db, envelope, user_id)
|
||||
if (
|
||||
sender_client_message_id
|
||||
and user_id is not None
|
||||
and user_id == envelope.sender_id
|
||||
):
|
||||
payload["client_message_id"] = sender_client_message_id
|
||||
return payload
|
||||
|
||||
|
||||
async def _send_message_internal(
|
||||
message_request: SendMessageRequest,
|
||||
current_user: User,
|
||||
|
||||
Reference in New Issue
Block a user