File size: 3,782 Bytes
87cb242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import WebSocket from 'ws';
import { ClientMessage, safeSend } from '../utils/protocol';
import {
  sendFriendRequest,
  acceptFriendRequest,
  rejectFriendRequest,
  removeFriend,
  getFriendList,
  areFriends,
} from '../services/friendService';
import { isOnline } from '../redis/presenceClient';
import { registry } from '../services/connectionRegistry';
import { logger } from '../utils/logger';

/**
 * Routes friend-related WS actions.
 * Called from connectionHandler's routeMessage for type: 'friend'
 *
 * Payload shape: { action, targetUid, ...extras }
 * Actions: send-request | accept | reject | remove | list | status
 */
export async function handleFriend(
  ws: WebSocket,
  uid: string,
  msg: ClientMessage
): Promise<void> {
  const { action, targetUid } = msg.payload as { action?: string; targetUid?: string };

  if (!action) {
    safeSend(ws, 'error', { message: 'action is required' }, msg.requestId);
    return;
  }

  switch (action) {
    case 'send-request': {
      if (!targetUid) { safeSend(ws, 'error', { message: 'targetUid required' }, msg.requestId); return; }
      if (targetUid === uid) { safeSend(ws, 'error', { message: 'Cannot friend yourself' }, msg.requestId); return; }
      await sendFriendRequest(uid, targetUid);
      safeSend(ws, 'message', { ack: true, action: 'send-request', targetUid }, msg.requestId);

      // Notify the target if online
      const targetMeta = registry.getByUid(targetUid);
      if (targetMeta) {
        safeSend(targetMeta.ws, 'message', { type: 'friend-request', fromUid: uid });
      }
      break;
    }

    case 'accept': {
      if (!targetUid) { safeSend(ws, 'error', { message: 'targetUid required' }, msg.requestId); return; }
      const ok = await acceptFriendRequest(targetUid, uid); // targetUid sent the request
      safeSend(ws, 'message', { ack: true, action: 'accept', success: ok }, msg.requestId);

      if (ok) {
        const targetMeta = registry.getByUid(targetUid);
        if (targetMeta) {
          safeSend(targetMeta.ws, 'message', { type: 'friend-accepted', fromUid: uid });
        }
      }
      break;
    }

    case 'reject': {
      if (!targetUid) { safeSend(ws, 'error', { message: 'targetUid required' }, msg.requestId); return; }
      await rejectFriendRequest(targetUid, uid);
      safeSend(ws, 'message', { ack: true, action: 'reject' }, msg.requestId);
      break;
    }

    case 'remove': {
      if (!targetUid) { safeSend(ws, 'error', { message: 'targetUid required' }, msg.requestId); return; }
      await removeFriend(uid, targetUid);
      safeSend(ws, 'message', { ack: true, action: 'remove' }, msg.requestId);
      break;
    }

    case 'list': {
      const friends = await getFriendList(uid);
      // Bulk check online status from Redis
      const statusChecks = await Promise.allSettled(friends.map(f => isOnline(f)));
      const withStatus = friends.map((f, i) => ({
        uid: f,
        online: statusChecks[i].status === 'fulfilled' && statusChecks[i].value === true,
      }));
      safeSend(ws, 'message', { action: 'list', friends: withStatus }, msg.requestId);
      break;
    }

    case 'status': {
      if (!targetUid) { safeSend(ws, 'error', { message: 'targetUid required' }, msg.requestId); return; }
      // Only allow checking status of friends
      const isFriend = await areFriends(uid, targetUid);
      if (!isFriend) {
        safeSend(ws, 'error', { message: 'Not friends with this user' }, msg.requestId);
        return;
      }
      const online = await isOnline(targetUid);
      safeSend(ws, 'message', { action: 'status', uid: targetUid, online }, msg.requestId);
      break;
    }

    default:
      safeSend(ws, 'error', { message: `Unknown friend action: ${action}` }, msg.requestId);
  }
}