Commit Graph

9 Commits

Author SHA1 Message Date
ZhenYi
f2a2ae5d7f fix(room): use WS for message fetching, eliminate duplicate WS connection
- Fix initial room load being skipped: `setup()` called `loadMoreRef.current`
  which was null on first mount (ref assigned in later effect). Call `loadMore`
  directly so the initial fetch always fires. WS message.list used when
  connected, HTTP fallback otherwise.
- Rewrite useRoomWs to use shared RoomWsClient instead of creating its own
  raw WebSocket, eliminating duplicate WS connection per room.
- Remove dead loadMoreRef now that setup calls loadMore directly.
2026-04-17 21:18:56 +08:00
ZhenYi
5a59f56319 fix(room): revert stale edited_at if messageGet fetch fails
onMessageEdited optimistically set edited_at, then fetched the full
message. If the fetch failed the "Edited" indicator persisted even though
the content was stale. Fix by capturing the original edited_at and
reverting it in the catch block — consistent with editMessage rollback.
2026-04-16 19:34:59 +08:00
ZhenYi
beea8854ce fix(room): fix stale room subscribe after async connect
connect() is async/fire-and-forget — if the user switches rooms while
WS is still connecting, the subscribeRoom() call captures the stale
(activeRoomId) closure value and subscribes to the wrong room. Fix by
re-reading activeRoomIdRef.current after the await so we always subscribe
to the room that is active when the connection actually opens.
2026-04-16 19:34:07 +08:00
ZhenYi
7989f7ba4b fix(room): fix StrictMode reconnect loop, add revokeMessage rollback
- useEffect([wsClient]): remove wsClient from deps to prevent
  React StrictMode double-mount from disconnecting the real client.
  First mount connects client-1; StrictMode cleanup disconnects it.
  Second mount connects client-2; first mount's second cleanup would
  then disconnect client-2, leaving WS permanently unconnected.
  Changing to useEffect([]) + optional chaining fixes this.
- revokeMessage: add optimistic removal + rollback on server rejection,
  consistent with editMessage pattern. Previously a failed delete left the
  message visible with no feedback.
2026-04-16 19:33:14 +08:00
ZhenYi
7416f37cec fix(room): prevent double-send, log resubscribe errors, dim pending messages
- sendMessage: guard with sendingRef to prevent concurrent in-flight
  sends (was missing — rapid clicks could create duplicate messages)
- resubscribeAll: log at warn level instead of silently swallowing,
  so operators can observe auth expiry or persistent failure patterns
- RoomMessageBubble: apply opacity-60 when isPending or isFailed,
  and hide action toolbar for pending messages (can't react/act on
  unconfirmed messages)
2026-04-16 19:29:34 +08:00
ZhenYi
677e88980b fix(room): add edit rollback, clean stream channels on room shutdown/idle 2026-04-16 19:28:23 +08:00
ZhenYi
c89f01b718 feat(room): improve robustness — optimistic send, atomic seq, jitter reconnect
Backend:
- Atomic seq assignment via Redis Lua script: INCR + GET run atomically
  inside a Lua script, preventing duplicate seqs under concurrent requests.
  DB reconciliation only triggers on cross-server handoff (rare path).
- Broadcast channel capacity: 10,000 → 100,000 to prevent message drops
  under high-throughput rooms.

Frontend:
- Optimistic sendMessage: adds message to UI immediately (marked
  isOptimistic=true) so user sees it instantly. Replaces with
  server-confirmed message on success, marks as isOptimisticError on
  failure. Fire-and-forget to IndexedDB for persistence.
- Seq-based dedup in onRoomMessage: replaces optimistic message by
  matching seq, preventing duplicates when WS arrives before REST confirm.
- Reconnect jitter: replaced deterministic backoff with full jitter
  (random within backoff window), preventing thundering herd on server
  restart.
- Visual WS status dot in room header: green=connected, amber
  (pulsing)=connecting, red=error/disconnected.
- isPending check extended to cover both old 'temp-' prefix and new
  isOptimistic flag, showing 'Sending...' / 'Failed' badges.
2026-04-16 19:23:06 +08:00
ZhenYi
8b433c9169 feat(repo): return ssh/https clone URLs from backend
Some checks are pending
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
Add ssh_clone_url and https_clone_url to ProjectRepositoryItem,
constructed from config.ssh_domain() and config.git_http_domain().
Update frontend RepoInfo interface and header.tsx to use the
server-provided URLs instead of hardcoded values.
2026-04-16 18:20:48 +08:00
ZhenYi
93cfff9738 init 2026-04-15 09:08:09 +08:00