Router.js

Материал из support.qbpro.ru
//////////////////////////
////////router.js/////////
//////////////////////////
///////А.В. Климов////////
//////////////////////////
////////01.11.2012////////

//Используются модули fifo.js, net, socket.io
//////////////////////////

//Предназначен для перенаправления входящего через WebSocket (далее ws) потока 
//в поток с использованием NetSocket (далее ns) для передачи заданий на исполнение.
//Наличие исполнителей (их адреса локальные (127.х.х.х) или в перспективе сетевые) 
//конфигурируется через параметр (массив) workers=[].
//Выбор маршрута определяется исходя из текущей (моментальной) нагрузки workerов.
//Имеет отдельный управляющий канал ns для связи с ядром
//////////////////////////

//Принцип работы:
//При поступлении сообщения от клиента по протоколу ws генерируется стандартное 
//событие 'data' в функции ws.on(). По этому событию из буфера сокета сообщение
//помещается в очередь ws_fifo_ns. Функция ns каждый цикл EventLoop проверяет 
//наличие заданий в очереди (длину массива ws_fifo_ns) и в случае ненулевого 
//значения, первое сообщение отправляется в ns конкретному исполнителю. Выбор 
//исполнителя осуществляется по критерию нагрузки {надо сделать расчет на 
//основе средневзвешенного коэффициента нагрузки, когда каждое задание имеет 
//вес - а)число определяющее степеть предполагаемой (временной) загрузки процесса EventLoop
//по времени исполнения [математическая, чтение/запись в файл, чтение/запись БД]
//б) собирать статистику времени вылонения, используемой памяти и на её основе выставлять вес задания,
//что позволит избежать неправильного веса при увеличении данных в запросе к БД 
//(т.н. автокорретировка)}. http://th-algoritmov.narod.ru/4.htm http://th-algoritmov.narod.ru/5.htm 
//Книга Идеальный код. http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%90%D0%BC%D0%B4%D0%B0%D0%BB%D0%B0
//
//////////////////////////

//Управляющий ns поток
//ns используется для мгновенного обмена информацией с ядром системы. Ядро может 
//собирать статистику и устанавливать конфигурационные пераметры: 
//-добавлять/убирать worker путем

var fifo= require("fifo"), 			//Модуль, организующий очередь FIFO
    websocket = require('socket.io'), 		//Модуль, организующий WebSocket
    netsocket = require('net'),			//Модуль, организующий NetSocket
    json_rpc= require('json_rpc');		//Модуль, организующий анализ и синтез формата json-rpc

var ws_fifo = new fifo(),			//очередь WebSocket->fifo для входящих (от клиента) сообщений перед маршрутизацией
    fifo_ws = new fifo(),			//очередь для исходящих (к клиенту) сообщений fifo->WebSocket 
    fifo_ns = new fifo(),			//очередь fifo->NetSocket для исходящих сообщений после маршрутизации
    ns_fifo = new fifo(),			//очередь для входящих сообщений NetSocket->fifo->WebSocket
    ws = new websocket(),			//создаем новый экземпляр WebSocket
    ns = new netsocket(),			//создаем новый экземпляр NetSocket
    ns_direct = new netsocket();		//создаем новый экземпляр NetSocket (управляющий канал)

//WebSocket

ws.listen(8080);				// Cтавим на прослушивание 8080-порта
ws.set('log level', 1);				// Отключаем вывод полного лога - пригодится в production'е
ws.sockets.on('connection', function (socket) { // Навешиваем обработчик на подключение нового клиента
						// Т.к. чат простой - в качестве ников пока используем первые 5 символов от ID сокета
    //var ID = (socket.id).toString().substr(0, 5);
    
    var ID = (socket.id).toString();		//В качестве ников пока используем ID сокета
    var time = (new Date).toLocaleTimeString();
    socket.json.send({'event': 'connected', 
                      'name': ID, 
					  'time': time});// Посылаем клиенту сообщение о том, что он успешно подключился и его имя
    socket.broadcast.json.send({'event': 'userJoined',
								'name': ID, 
								'time': time});							// Посылаем всем остальным пользователям, что подключился новый клиент и его имя
    socket.on('message', function (msg) { 								// Навешиваем обработчик на входящее сообщение
        var time = (new Date).toLocaleTimeString();
        socket.json.send({'event': 'messageSent',
						  'name': ID, 
						  'text': msg, 
						  'time': time});								// Уведомляем клиента, что его сообщение успешно дошло до сервера
       //socket.broadcast.json.send({'event': 'messageReceived',
	   //							'name': ID, 
	   //							'text': msg, 
	   //							'time': time})						// Отсылаем сообщение остальным участникам чата
        
        
        
        /////////////////////////
        //Здесь обработать авторизацию, занести в БД сессию
        //Если ошибка уведомить клиента (вернуть error в fifo_ws в формате JSON-RPC)
        /////////////////////////
        /////////////////////////
        //Здесь проверить валидность JSON-RPC
        //Если ошибка уведомить клиента (вернуть error в fifo_ws в формате JSON-RPC)
        /////////////////////////
        /////////////////////////
        //Проверить наличие и соответствие команды на выполнение
        //Если ошибка уведомить клиента (вернуть error в fifo_ws в формате JSON-RPC)
        /////////////////////////
        /////////////////////////
        //Здесь записать id задания(из JSON-RPC), id сокета, id клиента, id функции(для статистики), время начала  в буфер.
        //Из номера этой строки, id функции, параметры функции, сформировать в формате JSON-RPC задание для woker
        /////////////////////////
        /////////////////////////
        //Здесь предать JSON-RPC запрос в fifo_ns
        /////////////////////////
    
    
    
    });
    
    socket.on('disconnect', function() { // При отключении клиента - уведомляем остальных
        var time = (new Date).toLocaleTimeString();
        io.sockets.json.send({'event': 'userSplit', 'name': ID, 'time': time});
    });
});