Привет, друзья!
Дело было вечером, делать было нечего… Разбирая пример чата в Socket.IO, заинтересовала возможности без особых ухищрений сделать чат приватным. Идея не новая, и достаточна простая — выбираешь свой пол и возраст, указываешь желаемый пол и возраст собеседника, и, поехали! Своего рода рулетка.
Итак, начнем с требований:
- Форма входа — указание пола и возраста (как для себя, так и для собеседника);
- Возможность создания приватных комнат (при отсутствии подходящего собеседника);
- Подключение к приватной комнате (при наличии собеседника);
- Анонимность (не будем сохранять никакие данные пользователя).
Что нам потребуется?
Node.JS (на момент написания — 0.6.14) c модулями express, socket.io. Дополнительно используются nib, stylus, i18n и util.
Итак, поехали.
Подключение нового пользователя
Тут все достаточно просто. Создаем объект пользователя, инкриментим счетчики, обновляем цифры у клиентов.
var user = {};
var uid = socket.store.id;
var room_id = uid + "_room";
online++;
total++;
socket.broadcast.emit('online', total, free);
socket.emit('online', total, free);
user.id = socket.store.id;
users[socket.store.id] = user;
Вход пользователя
Под входом имеется ввиду уже вход в сам чат — после выбора требуемых параметров на начальной форме.
Сам механизм выбора собеседника реализован в виде простого цикла (не знаю, насколько это будет быстро работать при большой нагрузке). Проверяем введенные параметры, сравниваем их и при совпадении инициируем подключение к другому пользователю, либо оставляем ждать.
socket.on('nickname', function (nick, m_sex, m_age, c_sex, c_age, fn) {
if (nicknames[socket.user_id]) {
fn(true);
} else {
fn(false);
nicknames[socket.store.id] = socket.nickname = socket.store.id;
socket.user_id = socket.store.id;
socket.gender = m_sex;
var user = users[socket.store.id];
user.m_sex = m_sex;
user.m_age = m_age;
user.c_sex = c_sex;
user.c_age = c_age;
user.active = 0;
free++;
// Check existing rooms
for(var __room in rooms){
if(user.active == 0){
_room = rooms[__room];
if(_room.c_sex == m_sex && _room.c_age == m_age && _room.m_sex == c_sex && _room.m_age == c_age && _room.active == 0){
room_id = _room.id;
_room.active = 1;
_room.nicknames[socket.user_id] = socket.user_id;
user.active = 1
free--;
console.log(' room finded! this - ' + room_id);
}
}
}
// Create own room
if(user.active == 0){
console.log(' no room finded :( create own - ' + room_id);
var room = {};
room.id = room_id;
room.m_sex = m_sex;
room.m_age = m_age;
room.c_sex = c_sex;
room.c_age = c_age;
room.active = 0
room.nicknames = {};
room.nicknames[socket.user_id] = socket.user_id;
rooms[room_id] = room;
socket.emit("user message", "System", i18n.__("waiting"));
}
users[socket.store.id] = user;
socket.join(room_id);
socket.broadcast.to(room_id).emit('announcement', socket.user_id + ' ' + i18n.__('connected'));
socket.broadcast.to(room_id).emit('nicknames', rooms[room_id].nicknames);
socket.emit('nicknames', rooms[room_id].nicknames);
}
});
Осталось дело за малым — собственно позволить пользователям общаться между собой.
Отправка сообщений
socket.on('user message', function (msg) {
msg = sanitize(msg).entityEncode();
console.log(' message from ' + socket.user_id + ' to room ' + room_id + ": " + msg);
socket.broadcast.to(room_id).emit('user message', socket.gender == 1 ? i18n.__("he") : i18n.__("she") , msg);
});
Ну и собственно…
Выход
socket.on('disconnect', function () {
online--;
total--;
socket.broadcast.emit('online', total, free);
if (!socket.user_id) return;
if(free > 0) free--;
socket.broadcast.emit('online', total, free);
console.log(socket.user_id);
socket.leave(room_id);
socket.broadcast.to(room_id).emit('announcement', socket.user_id + ' ' + i18n.__('disconnected'));
if(rooms[room_id]) delete rooms[room_id].nicknames[socket.user_id];
if(rooms[room_id]) socket.broadcast.to(room_id).emit('nicknames', rooms[room_id].nicknames);
delete users[socket.user_id];
delete nicknames[socket.user_id];
delete rooms[room_id];
});
На этом всё. Тестировалось под нагрузкой < 10 человек, проблем не возникало :) Если сообщество заинтересует проект такого чата — сегодня же выложу на github, делалось just for fun.
P.S. Топик начинал писаться давно, и перенесен из черновиков — поэтому версии указанных продуктов могут быть не актуальны.
P.S.S. Посмотреть в живую можно тут — virt.in
Автор: eudj1n