File size: 4,523 Bytes
1d45897
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const path = require('path');

const app = express();
const port = 8080;

// Serve static files (if any)
app.use(express.static('public'));

// Data structures to store client data
const clients = {};

// HTTP server
const server = http.createServer(app);

// WebSocket server
const wss = new WebSocket.Server({ server });

// Handle new WebSocket connections
wss.on('connection', (ws) => {
  let clientId = null;

  ws.on('message', (message) => {
    try {
      const data = JSON.parse(message);

      if (!clientId && data.clientId) {
        clientId = data.clientId;
        clients[clientId] = {
          ws: ws,
          html: '',
          css: '',
          url: ''
        };
        console.log(`Client ${clientId} connected`);
      }

      if (data.type === 'pageContent') {
        clients[clientId].html = data.html;
        clients[clientId].css = data.css;
        clients[clientId].url = data.url;
      } else if (data.type === 'keyboardEvent') {
        // Relay the keyboard event to other clients
        relayKeyboardEvent(data, clientId);
      }
    } catch (e) {
      console.error('Error parsing message:', e);
    }
  });

  ws.on('close', () => {
    console.log(`Client ${clientId} disconnected`);
    delete clients[clientId];
  });
});

// Function to relay keyboard events to other clients
function relayKeyboardEvent(data, senderId) {
  // Send the keyboard event to all connected clients except the sender
  for (const [id, client] of Object.entries(clients)) {
    if (id !== senderId) {
      client.ws.send(JSON.stringify(data));
    }
  }
}

// Route to list all active clients
app.get('/clients', (req, res) => {
  res.json(Object.keys(clients));
});

// Route to render the client's page
app.get('/client/:id', (req, res) => {
  const client = clients[req.params.id];
  if (client) {
    let htmlContent = client.html;

    // Inject the CSS into a style tag in the head
    const cssTag = `<style>${client.css}</style>`;
    htmlContent = htmlContent.replace('</head>', `${cssTag}</head>`);

    // Inject the script to establish WebSocket connection
    const scriptTag = `
      <script>
        (function() {
          const socket = new WebSocket('ws://' + location.host);

          const clientId = '${req.params.id}-page';

          socket.addEventListener('open', () => {
            console.log('WebSocket connection opened from rendered page');
          });

          socket.addEventListener('message', (event) => {
            const data = JSON.parse(event.data);

            // Ignore messages originating from this client
            if (data.clientId === clientId) return;

            if (data.type === 'keyboardEvent') {
              simulateKeyboardEvent(data.event);
            }
          });

          // Send keyboard events to the server
          function sendKeyboardEvent(event) {
            const data = {
              type: 'keyboardEvent',
              event: serializeKeyboardEvent(event),
              clientId: clientId
            };
            socket.send(JSON.stringify(data));
          }

          // Serialize keyboard event properties
          function serializeKeyboardEvent(event) {
            return {
              type: event.type,
              key: event.key,
              code: event.code,
              keyCode: event.keyCode,
              charCode: event.charCode,
              which: event.which,
              altKey: event.altKey,
              ctrlKey: event.ctrlKey,
              metaKey: event.metaKey,
              shiftKey: event.shiftKey,
              repeat: event.repeat,
              isComposing: event.isComposing,
            };
          }

          // Simulate keyboard event
          function simulateKeyboardEvent(eventData) {
            const event = new KeyboardEvent(eventData.type, eventData);
            document.activeElement.dispatchEvent(event);
          }

          // Listen for keyboard events
          ['keydown', 'keypress', 'keyup'].forEach(eventType => {
            document.addEventListener(eventType, sendKeyboardEvent, true);
          });
        })();
      </script>
    `;
    htmlContent = htmlContent.replace('</body>', `${scriptTag}</body>`);

    res.send(htmlContent);
  } else {
    res.status(404).send('Client not found');
  }
});

// Start the server
server.listen(port, () => {
  console.log(`Server is listening on http://localhost:${port}`);
});