aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/server/socket.ts
blob: a65ed7efe350c16a2d450bddc597525bc0d704b8 (plain) (blame)
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
107
108
109
110
111
112
113
114
import { Server } from "socket.io";
import { createServer } from "http";
import { prisma } from "./db";

// Function to generate a share token
function generateShareToken(length = 8) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let result = '';
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return result;
}

// Store active connections
const activeUsers = new Map<string, string>();

const httpServer = createServer();
const io = new Server(httpServer, {
  cors: {
    origin: process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000",
    methods: ["GET", "POST"],
  },
});

// Set up Socket.IO event handlers
io.on('connection', (socket) => {
  console.log(`New client connected: ${socket.id}`);
  
  // Handle user login/registration
  socket.on('user:register', (userId: string) => {
    console.log(`User registered: ${userId} (Socket: ${socket.id})`);
    activeUsers.set(userId, socket.id);
    // Broadcast updated user list
    io.emit('users:update', Array.from(activeUsers.keys()));
  });
  
  // Handle location updates
  socket.on('location:update', (data: { 
    userId: string; 
    latitude: number; 
    longitude: number;
    accuracy?: number;
    timestamp?: string; 
  }) => {
    console.log(`Location update from ${data.userId}: ${data.latitude}, ${data.longitude}`);
    // Add timestamp if not provided
    if (!data.timestamp) {
      data.timestamp = new Date().toISOString();
    }
    // Broadcast to all connected clients
    io.emit('location:broadcast', data);
  });
  
  // Handle direct messages or location shares
  socket.on('location:share', (data: { 
    fromUserId: string; 
    toUserId: string; 
    latitude: number; 
    longitude: number;
    accuracy?: number;
  }) => {
    console.log(`Location share from ${data.fromUserId} to ${data.toUserId}`);
    const targetSocketId = activeUsers.get(data.toUserId);
    
    if (targetSocketId) {
      // Send to specific user
      io.to(targetSocketId).emit('location:shared', {
        fromUserId: data.fromUserId,
        latitude: data.latitude,
        longitude: data.longitude,
        accuracy: data.accuracy,
        timestamp: new Date().toISOString()
      });
    }
  });
  
  // Handle location sharing via token
  socket.on('share:join', (shareToken: string) => {
    if (shareToken) {
      socket.join(`share:${shareToken}`);
      console.log(`Client ${socket.id} joined room share:${shareToken}`);
    }
  });
  
  socket.on('share:leave', (shareToken: string) => {
    if (shareToken) {
      socket.leave(`share:${shareToken}`);
      console.log(`Client ${socket.id} left room share:${shareToken}`);
    }
  });
  
  // Handle disconnect
  socket.on('disconnect', () => {
    console.log(`Client disconnected: ${socket.id}`);
    // Remove user from active users
    for (const [userId, socketId] of activeUsers.entries()) {
      if (socketId === socket.id) {
        activeUsers.delete(userId);
        break;
      }
    }
    // Broadcast updated user list
    io.emit('users:update', Array.from(activeUsers.keys()));
  });
});

const PORT = parseInt(process.env.SOCKET_PORT || "3001", 10);

export const startSocketServer = () => {
  httpServer.listen(PORT, () => {
    console.log(`Socket.IO server running on port ${PORT}`);
  });
};