/**
Socket events
+————————————————————————-+
| |
| Client -> Server: |
| incoming_connection Входящее подключение |
| user_action?action=ACTION_NAME Действие от пользователя |
| room_action?room=ROOM_NAME&action=ACTION_NAME Действие по комнате|
| |
+————————————————————————-+

+————————————————————————-+
| |
| Server -> Client: |
| connection_established Подключение установлено |
| user_action?action=ACTION_NAME Действие к пользователю |
| room_action?room=ROOM_NAME&action=ACTION_NAME Действие по комнате|
| |
+————————————————————————-+

*/

const Observable = require(‘rxjs/Observable’).Observable;
const Rx = require(‘rxjs/Rx’);
const io = require(‘socket.io’);
const GeneralError = require(GLOBAL_PATH + ‘/error/GeneralError.js’);
const SocketError = require(GLOBAL_PATH + ‘/error/SocketError.js’);
const Jwt = require(‘jsonwebtoken’);

// Services
const UserSQLAdapter = require(GLOBAL_PATH + ‘/services/sql_adapter/UserSQLAdapter.js’);

// Input actions
const IncomingConnection = require(GLOBAL_PATH + ‘/input_actions/incoming_connection’);
const UserInputAction = require(GLOBAL_PATH + ‘/input_actions/user_action’);
const RoomInputAction = require(GLOBAL_PATH + ‘/input_actions/room_action’);

// Output actions
const OutputUserAction = require(GLOBAL_PATH + ‘/output_actions/user_action’);
const OutputRoomAction = require(GLOBAL_PATH + ‘/output_actions/room_action’);

/*
Emitted after a connection has been established.
*/

const ConnectionEstablished = (socket, id) => {
socket.emit(‘connection_established’, {
id: id
});
};

/*
Main listen to socket evnets.
*/

const ListenSocketEvents = (server) => {
return Observable.create(observer => {
console.log(‘[Observable (ListenSocketEvents)] Started …’);

const io_connection = io.listen(server);

io_connection.use(async (socket, next) => {
try {
// && socket.handshake.query
let decoded = await new Promise((resolve, reject) => {
let token = socket.handshake.query.token;
// let decoded = Jwt.verify(token, ‘secrete’);
if (token) {
Jwt.verify(token, ‘secrete’, (err, decoded) => {
if (err) {
reject(err);
} else {
resolve(decoded);
}
});
} else {
reject(‘no token’);
}
});
socket.decoded = decoded;
next();
} catch (err) {
let errors = {
status: err.status,
};

if ([‘token expired’, ‘jwt malformed’, ‘invalid token’].indexOf(err.message) > -1) {
errors.status = 401;
errors.message = ‘The token expired. Please sign in again.’;
}

observer.error(new SocketError(errors.message, errors.status));
}
});

io_connection.on(‘connection’, async socket => {
const user_id = socket.decoded._id;
const user_name = socket.decoded.name;

console.log(‘[SocketEvent] User connected (name – ‘ + user_name + ‘, id – ‘ + user_id + ‘)’);

bucket.set(user_id, socket);

ConnectionEstablished(socket, user_id);

/// ————— Input events ————— ///

/*
Simple incoming connection event.
*/
socket.on(‘incoming_connection’, IncomingConnection(socket, user_id));

/*
User input action event.
Emitted for user related actions.
*/
socket.on(‘user_action’, async UserInputAction(socket, user_id));

/*
Room input action event.
Emitted for room related actions.
*/
socket.on(‘room_action’, async RoomInputAction(socket, user_id));

/*
‘disconnect’ event.
*/
socket.on(‘disconnect’, async () => {
bucket.delete(user_id);
console.log(‘[SocketEvent] User disconnected (id – ‘ + user_id + ‘)’);
});

/*
‘error’ event.
*/
socket.on(‘error’, async (err) => {
console.log(‘[SocketEvent] Error (id – ‘ + user_id + ‘): ‘ + err);
observer.next(new GeneralError(err));
});

/// ————— Output events ————— ///

try {
/*
User output action event.
Emitted for user related actions.
*/
socket.on(‘user_action’, OutputUserAction(socket, user_id));

/*
Room output action event.
Emitted for room related actions.
*/
socket.on(‘room_action’, OutputRoomAction(socket, user_id));
} catch (err) {
console.log(‘[Error (ListenSocketEvents)] Error: ‘ + err);
}
});

});

};

module.exports = ListenSocketEvents;