Initial Commit

This commit is contained in:
ExilProductions
2026-01-14 17:52:35 +01:00
parent 2d3b97c5db
commit cf066ef305
28 changed files with 1922 additions and 0 deletions

110
server/socket.ts Normal file
View File

@@ -0,0 +1,110 @@
import { Server as SocketIOServer, Socket } from 'socket.io';
import { upsertPixels, getAllPixels, db } from './database';
import { Cursor, Pixel } from '../shared/types';
import passport from 'passport';
function generateRandomColor(): string {
const colors = [
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
'#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E2'
];
return colors[Math.floor(Math.random() * colors.length)];
}
interface UserSocket extends Socket {
userId: string;
username: string;
color: string;
user?: any;
}
// Helper function to get user data from db
function getUserById(userId: number) {
try {
const stmt = db.prepare('SELECT * FROM users WHERE id = ?');
return stmt.get(userId);
} catch (error) {
console.error('Error fetching user:', error);
return null;
}
}
export function setupSocketIO(io: SocketIOServer): void {
const connectedUsers = new Map<string, { x: number; y: number; color: string; username: string; userId: number }>();
io.on('connection', (socket: Socket) => {
const userSocket = socket as UserSocket;
socket.on('join-canvas', (token: string) => {
try {
const decoded = JSON.parse(Buffer.from(token, 'base64').toString());
if (Date.now() - decoded.timestamp > 5 * 60 * 1000) {
socket.emit('error', 'Token expired');
socket.disconnect();
return;
}
const userData = getUserById(decoded.userId);
if (userData) {
userSocket.user = userData;
const userId = `auth_${userData.id}`;
const username = userData.username || userData.display_name;
const color = generateRandomColor();
connectedUsers.set(userId, {
x: 0,
y: 0,
color: color,
username: username,
userId: userData.id.toString()
});
socket.emit('canvas-state', getAllPixels());
socket.emit('cursor-update', Array.from(connectedUsers.values()));
socket.emit('auth-success', { user: userData });
socket.broadcast.emit('cursor-update', Array.from(connectedUsers.values()));
socket.on('cursor-move', (cursor: Cursor) => {
const user = connectedUsers.get(userId);
if (user) {
user.x = cursor.x;
user.y = cursor.y;
socket.broadcast.emit('cursor-update', Array.from(connectedUsers.values()));
}
});
socket.on('paint-pixels', async (pixels: Pixel[]) => {
try {
if (!userSocket.user) {
socket.emit('error', 'Authentication required to paint pixels');
return;
}
upsertPixels(pixels);
socket.broadcast.emit('canvas-update', { pixels });
} catch (error) {
console.error('Error saving pixels:', error);
socket.emit('error', 'Failed to save pixels');
}
});
socket.on('disconnect', () => {
connectedUsers.delete(userId);
socket.broadcast.emit('cursor-update', Array.from(connectedUsers.values()));
});
} else {
console.error('User not found for token:', decoded.userId);
socket.emit('error', 'Invalid user');
socket.disconnect();
}
} catch (error) {
console.error('Token verification failed:', error);
socket.emit('error', 'Invalid token');
socket.disconnect();
}
});
});
}