<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://support.qbpro.ru/index.php?action=history&amp;feed=atom&amp;title=Jsonrpc_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80</id>
	<title>Jsonrpc сервер - История изменений</title>
	<link rel="self" type="application/atom+xml" href="https://support.qbpro.ru/index.php?action=history&amp;feed=atom&amp;title=Jsonrpc_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80"/>
	<link rel="alternate" type="text/html" href="https://support.qbpro.ru/index.php?title=Jsonrpc_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80&amp;action=history"/>
	<updated>2026-04-03T17:18:06Z</updated>
	<subtitle>История изменений этой страницы в вики</subtitle>
	<generator>MediaWiki 1.38.1</generator>
	<entry>
		<id>https://support.qbpro.ru/index.php?title=Jsonrpc_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80&amp;diff=327&amp;oldid=prev</id>
		<title>imported&gt;Supportadmin: Новая страница: «==Код модуля сервера==   &lt;nowiki&gt;  var sys = require('sys');  var http = require('http');  //===--------------------------------------------------…»</title>
		<link rel="alternate" type="text/html" href="https://support.qbpro.ru/index.php?title=Jsonrpc_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80&amp;diff=327&amp;oldid=prev"/>
		<updated>2013-08-04T12:42:26Z</updated>

		<summary type="html">&lt;p&gt;Новая страница: «==Код модуля сервера==   &amp;lt;nowiki&amp;gt;  var sys = require(&amp;#039;sys&amp;#039;);  var http = require(&amp;#039;http&amp;#039;);  //===--------------------------------------------------…»&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==Код модуля сервера==&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 var sys = require('sys');&lt;br /&gt;
 var http = require('http');&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// Server Client&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
var Client = function(port, host, user, password) {&lt;br /&gt;
  this.port = port;&lt;br /&gt;
  this.host = host;&lt;br /&gt;
  this.user = user;&lt;br /&gt;
  this.password = password;&lt;br /&gt;
 &lt;br /&gt;
  &lt;br /&gt;
  this.call = function(method, params, callback, errback, path) {&lt;br /&gt;
    var client = http.createClient(port, host);&lt;br /&gt;
    &lt;br /&gt;
    // First we encode the request into JSON&lt;br /&gt;
    var requestJSON = JSON.stringify({&lt;br /&gt;
      'jsonrpc': '2.0',&lt;br /&gt;
      'id': '' + (new Date()).getTime(),&lt;br /&gt;
      'method': method,&lt;br /&gt;
      'params': params&lt;br /&gt;
    });&lt;br /&gt;
    &lt;br /&gt;
    var headers = {};&lt;br /&gt;
&lt;br /&gt;
    if (user &amp;amp;&amp;amp; password) {&lt;br /&gt;
      var buff = new Buffer(this.user + &amp;quot;:&amp;quot; + this.password)&lt;br /&gt;
                           .toString('base64');&lt;br /&gt;
      var auth = 'Basic ' + buff;&lt;br /&gt;
      headers['Authorization'] = auth;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Then we build some basic headers.&lt;br /&gt;
    headers['Host'] = host;&lt;br /&gt;
    headers['Content-Length'] = requestJSON.length;&lt;br /&gt;
&lt;br /&gt;
    // Now we'll make a request to the server&lt;br /&gt;
    var request = client.request('POST', path || '/', headers);&lt;br /&gt;
    request.write(requestJSON);&lt;br /&gt;
    request.on('response', function(response) {&lt;br /&gt;
      // We need to buffer the response chunks in a nonblocking way.&lt;br /&gt;
      var buffer = '';&lt;br /&gt;
      response.on('data', function(chunk) {&lt;br /&gt;
        buffer = buffer + chunk;&lt;br /&gt;
      });&lt;br /&gt;
      // When all the responses are finished, we decode the JSON and&lt;br /&gt;
      // depending on whether it's got a result or an error, we call&lt;br /&gt;
      // emitSuccess or emitError on the promise.&lt;br /&gt;
      response.on('end', function() {&lt;br /&gt;
        var decoded = JSON.parse(buffer); // TODO: Check for invalid response from server&lt;br /&gt;
        if(decoded.hasOwnProperty('result')) {&lt;br /&gt;
          if (callback) &lt;br /&gt;
            callback(null, decoded.result);&lt;br /&gt;
          &lt;br /&gt;
        } else {&lt;br /&gt;
          // Call error handler if it is set, otherwise call callback with error parameters&lt;br /&gt;
          if (errback) {&lt;br /&gt;
          	errback(decoded.error);&lt;br /&gt;
          } else if(callback) {&lt;br /&gt;
          	callback(decoded.error, null);&lt;br /&gt;
          }&lt;br /&gt;
       }&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// Server&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
function Server() {&lt;br /&gt;
  var self = this;&lt;br /&gt;
  this.functions = {};&lt;br /&gt;
  this.scopes = {};&lt;br /&gt;
  this.defaultScope = this;&lt;br /&gt;
  this.server = http.createServer(function(req, res) {&lt;br /&gt;
    Server.trace('&amp;lt;--', 'accepted request');&lt;br /&gt;
    if(req.method === 'POST') {&lt;br /&gt;
      self.handlePOST(req, res);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
      Server.handleNonPOST(req, res);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// exposeModule&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
Server.prototype.exposeModule = function(mod, object, scope) {&lt;br /&gt;
  var funcs = [];&lt;br /&gt;
  for(var funcName in object) {&lt;br /&gt;
    var funcObj = object[funcName];&lt;br /&gt;
    if(typeof(funcObj) == 'function') {&lt;br /&gt;
      this.functions[mod + '.' + funcName] = funcObj;&lt;br /&gt;
      funcs.push(funcName);&lt;br /&gt;
&lt;br /&gt;
      if (scope) {&lt;br /&gt;
        this.scopes[mod + '.' + funcName] = scope;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  Server.trace('***', 'exposing module: ' + mod + ' [funs: ' + funcs.join(', ') &lt;br /&gt;
                + ']');&lt;br /&gt;
  return object;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// expose&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
Server.prototype.expose = function(name, func, scope) {&lt;br /&gt;
  Server.trace('***', 'exposing: ' + name);&lt;br /&gt;
  this.functions[name] = func;&lt;br /&gt;
&lt;br /&gt;
  if (scope) {&lt;br /&gt;
    this.scopes[name] = scope;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// trace&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
Server.trace = function(direction, message) {&lt;br /&gt;
  sys.puts('   ' + direction + '   ' + message);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// listen&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
Server.prototype.listen = function(port, host) { &lt;br /&gt;
  this.server.listen(port, host);&lt;br /&gt;
  Server.trace('***', 'Server listening on http://' + (host || '127.0.0.1') + &lt;br /&gt;
                ':' + port + '/'); &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// handlePOST&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
Server.prototype.handlePOST = function(req, res) {&lt;br /&gt;
  var buffer = '';&lt;br /&gt;
  var self = this;&lt;br /&gt;
  var handle = function (buf) {&lt;br /&gt;
    &lt;br /&gt;
    var decoded = &amp;quot;&amp;quot;;&lt;br /&gt;
    try {&lt;br /&gt;
    	decoded = JSON.parse(buf);&lt;br /&gt;
    } catch (e) {&lt;br /&gt;
    	return Server.handleError(-32700, &amp;quot;Parse Error&amp;quot;, null, req, res);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    // Check for the required fields, and if they aren't there, then&lt;br /&gt;
    // dispatch to the handleError function.    &lt;br /&gt;
    if(!(decoded.method &amp;amp;&amp;amp; decoded.params &amp;amp;&amp;amp; decoded.id)) {&lt;br /&gt;
      &lt;br /&gt;
      if (typeof(id) == &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
   		var id = null;&lt;br /&gt;
   	  } &lt;br /&gt;
   	  &lt;br /&gt;
      return Server.handleError(-32600, &amp;quot;Invalid Request&amp;quot;, decoded.id, req, res);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(!self.functions.hasOwnProperty(decoded.method)) {&lt;br /&gt;
      return Server.handleError(-32601, &amp;quot;Method not found&amp;quot;, decoded.id, req, res);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Build our success handler&lt;br /&gt;
    var onSuccess = function(funcResp) {&lt;br /&gt;
      Server.trace('--&amp;gt;', 'response (id ' + decoded.id + '): ' + &lt;br /&gt;
                    JSON.stringify(funcResp));&lt;br /&gt;
	&lt;br /&gt;
	  var encoded = JSON.stringify({&lt;br /&gt;
        'jsonrpc': '2.0',&lt;br /&gt;
        'result': funcResp,&lt;br /&gt;
        'error': null,&lt;br /&gt;
        'id': decoded.id&lt;br /&gt;
      });&lt;br /&gt;
      &lt;br /&gt;
      res.writeHead(200, {'Content-Type': 'application/json',&lt;br /&gt;
                          'Content-Length': encoded.length});&lt;br /&gt;
      res.write(encoded);&lt;br /&gt;
      res.end();&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Server.trace('&amp;lt;--', 'request (id ' + decoded.id + '): ' + &lt;br /&gt;
                  decoded.method + '(' + decoded.params.join(', ') + ')');&lt;br /&gt;
&lt;br /&gt;
    // Try to call the method, but intercept errors and call our&lt;br /&gt;
    // onFailure handler.&lt;br /&gt;
    var method = self.functions[decoded.method];&lt;br /&gt;
    var callback = function(result, errormessage) {&lt;br /&gt;
      if (errormessage) {&lt;br /&gt;
        Server.handleError(-32602, errormessage, decoded.id, req, res);&lt;br /&gt;
      } else {&lt;br /&gt;
        onSuccess(result);&lt;br /&gt;
      }&lt;br /&gt;
    };&lt;br /&gt;
    var scope = self.scopes[decoded.method] || self.defaultScope;&lt;br /&gt;
&lt;br /&gt;
    // Other various information we want to pass in for the handler to be&lt;br /&gt;
    // able to access.&lt;br /&gt;
    var opt = {&lt;br /&gt;
      req: req,&lt;br /&gt;
      server: self&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
      method.call(scope, decoded.params, opt, callback);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
      return Server.handleError(-32603, err, decoded.id, req, res);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  } // function handle(buf)&lt;br /&gt;
&lt;br /&gt;
  req.addListener('data', function(chunk) {&lt;br /&gt;
    buffer = buffer + chunk;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  req.addListener('end', function() {&lt;br /&gt;
    handle(buffer);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// handleError&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
Server.handleError = function(code, message, id, req, res) {&lt;br /&gt;
  &lt;br /&gt;
  var encoded = JSON.stringify({&lt;br /&gt;
  	'jsonrpc': '2.0',&lt;br /&gt;
    'error': {&lt;br /&gt;
    	'code':code,&lt;br /&gt;
    	'message':message&lt;br /&gt;
    },&lt;br /&gt;
    'id': id&lt;br /&gt;
  });&lt;br /&gt;
  &lt;br /&gt;
  res.writeHead(400, {'Content-Type': 'text/plain',&lt;br /&gt;
                      'Content-Length': encoded.length,&lt;br /&gt;
                      'Allow': 'POST'});&lt;br /&gt;
  &lt;br /&gt;
  res.write(encoded);&lt;br /&gt;
  res.end();&lt;br /&gt;
  &lt;br /&gt;
  Server.trace('--&amp;gt;', 'Failure: ' + code + ': ' + message);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
// handleNonPOST&lt;br /&gt;
//===----------------------------------------------------------------------===//&lt;br /&gt;
Server.handleNonPOST = function(req, res) {&lt;br /&gt;
  &lt;br /&gt;
  var encoded = JSON.stringify({&lt;br /&gt;
  	'jsonrpc': '2.0',&lt;br /&gt;
    'error': {&lt;br /&gt;
    	'code':-32600,&lt;br /&gt;
    	'message':&amp;quot;Only POST is allowed.&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    'id': null&lt;br /&gt;
  });&lt;br /&gt;
  &lt;br /&gt;
  res.writeHead(405, {'Content-Type': 'text/plain',&lt;br /&gt;
                      'Content-Length': encoded.length,&lt;br /&gt;
                      'Allow': 'POST'});&lt;br /&gt;
  res.write(encoded);&lt;br /&gt;
  res.end();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
module.exports.Server = Server;&lt;br /&gt;
module.exports.Client = Client;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Пример использования в качестве сервера==&lt;br /&gt;
&lt;br /&gt;
var rpc = require('../src/jsonrpc');&lt;br /&gt;
&lt;br /&gt;
var server = new rpc.Server();&lt;br /&gt;
&lt;br /&gt;
/* Create two simple functions */&lt;br /&gt;
function add(args, opts, callback) {&lt;br /&gt;
  callback(args[0]+args[1]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function multiply(args, opts, callback) {&lt;br /&gt;
  callback(args[0]*args[1]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Expose those methods */&lt;br /&gt;
server.expose('add', add);&lt;br /&gt;
server.expose('multiply', multiply);&lt;br /&gt;
&lt;br /&gt;
/* We can expose entire modules easily */&lt;br /&gt;
var math = {&lt;br /&gt;
  power: function(args, opts, callback) {&lt;br /&gt;
    callback(Math.pow(args[0], args[1]));&lt;br /&gt;
  },&lt;br /&gt;
  sqrt: function(args, opts, callback) {&lt;br /&gt;
    callback(Math.sqrt(args[0]));&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
server.exposeModule('math', math);&lt;br /&gt;
&lt;br /&gt;
/* Listen on port 8088 */&lt;br /&gt;
server.listen(8088, 'localhost');&lt;br /&gt;
&lt;br /&gt;
/* By using a callback, we can delay our response indefinitely, leaving the&lt;br /&gt;
 request hanging until the callback emits success. */&lt;br /&gt;
var delayed = {&lt;br /&gt;
  echo: function(args, opts, callback) {&lt;br /&gt;
    var data = args[0];&lt;br /&gt;
    var delay = args[1];&lt;br /&gt;
    setTimeout(function() {&lt;br /&gt;
      callback(data);&lt;br /&gt;
    }, delay);&lt;br /&gt;
  },&lt;br /&gt;
&lt;br /&gt;
  add: function(args, opts, callback) {&lt;br /&gt;
    var first = args[0];&lt;br /&gt;
    var second = args[1];&lt;br /&gt;
    var delay = args[2];&lt;br /&gt;
    setTimeout(function() {&lt;br /&gt;
      callback(first + second);&lt;br /&gt;
    }, delay);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server.exposeModule('delayed', delayed);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// We can also add error parameters to our callback&lt;br /&gt;
// if something went wrong&lt;br /&gt;
function wrong(arg, opts, callback) {&lt;br /&gt;
	callback(null, &amp;quot;This will ever go wrong.&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
server.expose('wrong', wrong);&lt;br /&gt;
==Пример использования в качестве клиента==&lt;br /&gt;
var sys = require('sys');&lt;br /&gt;
var rpc = require('../src/jsonrpc');&lt;br /&gt;
&lt;br /&gt;
var client = new rpc.Client(8088, 'localhost');&lt;br /&gt;
&lt;br /&gt;
client.call('add', [1, 2], function (err, result) {&lt;br /&gt;
  sys.puts('  1 + 2 = ' + result);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
client.call('multiply', [199, 2], function (err, result) {&lt;br /&gt;
  sys.puts('199 * 2 = ' + result);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// Accessing modules is as simple as dot-prefixing.&lt;br /&gt;
client.call('math.power', [3, 3], function (err, result) {&lt;br /&gt;
  sys.puts('  3 ^ 3 = ' + result);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// We can handle errors the same way as anywhere else in Node&lt;br /&gt;
client.call('wrong', [1, 1], function (err, result) {&lt;br /&gt;
  if (err) {&lt;br /&gt;
    sys.puts('RPC Error: '+ sys.inspect(err));&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
  sys.puts(result);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
// If you want to seperate the errors from your callback,&lt;br /&gt;
// then define an extra error callback&lt;br /&gt;
client.call('wrong', [1, 1], function (err, result) {&lt;br /&gt;
  sys.puts(result);&lt;br /&gt;
},&lt;br /&gt;
function(err){&lt;br /&gt;
	sys.puts('RPC Error: ' + sys.inspect(err));&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
/* These calls should each take 1.5 seconds to complete. */&lt;br /&gt;
client.call('delayed.add', [1, 1, 1500], function (err, result) {&lt;br /&gt;
  sys.puts(result);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
client.call('delayed.echo', ['Echo.', 1500], function (err, result) {&lt;br /&gt;
  sys.puts(result);&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
==Анализ модуля==&lt;br /&gt;
После анализа работы скрипта jsonrpc.js https://github.com/Philipp15b/node-jsonrpc2 было выявлено следущее:&lt;br /&gt;
&lt;br /&gt;
1. Приложение по сути является http сервером, который анализирует входящие сообщения на предмет их соответствия стандарту jsonrpc 2.0 &lt;br /&gt;
http://www.jsonrpc.org/specification и возвращает клиенту гарантированный jsonrpc ответ, в виде результатов выполненного метода.&lt;br /&gt;
Сервер по протоколу http принимает запрос, проверяет запрос на валидность JSON, проверяет наличие вызываемого метода, выполняет этот &lt;br /&gt;
метод с переданнми параметрами. В случае ошибок возвращает признак ошибки по стандарту jsonrpc 2.0 &lt;br /&gt;
&lt;br /&gt;
2. Приложение является монолитным модулем и не предоставляет возможности унификации кода для использования его как на сервере, так &lt;br /&gt;
и на стороне браузера &lt;br /&gt;
&lt;br /&gt;
3. Приложение подразумевает первоначальную загрузку всех методов (функций) в память.&lt;br /&gt;
&lt;br /&gt;
4. Нет возможности использовать различные этапы проверки jsonrpc, что заставляет выполнять весь код целиком&lt;br /&gt;
&lt;br /&gt;
5. Отсутствует проверка jsonrpc на стороне клиента.&lt;br /&gt;
&lt;br /&gt;
'''Варианты решения:'''&lt;br /&gt;
&lt;br /&gt;
''Вариант 1.''&lt;br /&gt;
&lt;br /&gt;
1. Слелать модуль с возможностью проверки на соответствие jsonrpc на любом этапе. Это приводит к необходимости проверки jsonrpc ответа на возврат ошибки при каждом вызове, но позволяет не загружать весь код.&lt;br /&gt;
&lt;br /&gt;
2. Позволяет вынести проверку наличия методов в отдельный модуль.&lt;br /&gt;
&lt;br /&gt;
3. Позволяет выполнять методы в отдельном модуле.&lt;br /&gt;
&lt;br /&gt;
4. Позволяет подключать модуль к любым серверам и слелать стандарт jsonrpc 2.0 стандартным форматом общения между различными компонентами системы в независимости от протокола обмена данными.&lt;br /&gt;
&lt;br /&gt;
5. Позволит выполнять трассировку отдельных модулей&lt;br /&gt;
&lt;br /&gt;
Недостатки: слишком много преобразований объектов JSON в строку и обратно, что занимает такты, слишком много приходится проверять наличие ошибки в каждом из ответов.&lt;br /&gt;
&lt;br /&gt;
''Вариант 2.''&lt;br /&gt;
&lt;br /&gt;
1. Максимально оставить все как есть.&lt;br /&gt;
&lt;br /&gt;
2. Добавить в exports методы для наполнения, контроля и удаления набора вызываемых методов.&lt;br /&gt;
&lt;br /&gt;
3. Убрать http сервер.&lt;br /&gt;
&lt;br /&gt;
4. Перевести все этапы проверки на callback функции (уменьшает время работы на одном цикле event loop, увеличивает количество циклов event loop, это повышает отзывчивость модуля)&lt;br /&gt;
&lt;br /&gt;
5. scope (переменная задающая область видимости при выполнении метода) привязать к каждому пользователю. Это увеличит расход памяти, но и сразу решит проблему с правами пользователей.&lt;br /&gt;
==Анализ кода==&lt;br /&gt;
===Объявление внешних зависимостей===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
var sys = require('sys');&lt;br /&gt;
var http = require('http');&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
===Функция Client===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
var Client = function(port, host, user, password) {&lt;br /&gt;
  &lt;br /&gt;
//присваиваем параметры запуска &lt;br /&gt;
  this.port = port; &lt;br /&gt;
  this.host = host;&lt;br /&gt;
  this.user = user;&lt;br /&gt;
  this.password = password;&lt;br /&gt;
  &lt;br /&gt;
//this.call - внутренний метод, аналог стандартной функция call&lt;br /&gt;
//Метод call может применяться для вызова функции в контексте нужного объекта&lt;br /&gt;
//подробнее http://javascript.ru/Function/call &lt;br /&gt;
//method&lt;br /&gt;
//params&lt;br /&gt;
//callback - функция обработки результата (ответа сервера) &lt;br /&gt;
//errback - функция обработки ошибки, если отсутствует, то ошибка передается на обработку в callback&lt;br /&gt;
//path - url запроса к серверу, если пустой то по умолчанию запрос на &amp;quot;/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  this.call = function(method, params, callback, errback, path) {&lt;br /&gt;
&lt;br /&gt;
//запуск клиента с параметрами, клиент создается заново каждый раз при вызове функции (это плохо)&lt;br /&gt;
&lt;br /&gt;
    var client = http.createClient(port, host);&lt;br /&gt;
    &lt;br /&gt;
// First we encode the request into JSON &lt;br /&gt;
//Во-первых мы формируем запрос в формате JSON &lt;br /&gt;
&lt;br /&gt;
    var requestJSON = JSON.stringify({&lt;br /&gt;
      'jsonrpc': '2.0',&lt;br /&gt;
      'id': '' + (new Date()).getTime(),&lt;br /&gt;
      'method': method,&lt;br /&gt;
      'params': params&lt;br /&gt;
    });&lt;br /&gt;
    &lt;br /&gt;
//Объявляем объект, для хранения заголовков http запроса&lt;br /&gt;
&lt;br /&gt;
    var headers = {};&lt;br /&gt;
&lt;br /&gt;
//Если заданы user и password в  вызове функции Client, то формируем заголовок Authorization&lt;br /&gt;
&lt;br /&gt;
    if (user &amp;amp;&amp;amp; password) {&lt;br /&gt;
      var buff = new Buffer(this.user + &amp;quot;:&amp;quot; + this.password)&lt;br /&gt;
                           .toString('base64');&lt;br /&gt;
      var auth = 'Basic ' + buff;&lt;br /&gt;
      headers['Authorization'] = auth;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// Then we build some basic headers.&lt;br /&gt;
//Далее формируются некоторые простые заголовки ('Host', 'Content-Length')&lt;br /&gt;
&lt;br /&gt;
    headers['Host'] = host;&lt;br /&gt;
    headers['Content-Length'] = requestJSON.length;&lt;br /&gt;
&lt;br /&gt;
// Now we'll make a request to the server&lt;br /&gt;
// Формируем запрос к серверу&lt;br /&gt;
&lt;br /&gt;
    var request = client.request('POST', path || '/', headers);&lt;br /&gt;
    &lt;br /&gt;
//Отправляем запрос&lt;br /&gt;
    request.write(requestJSON);&lt;br /&gt;
&lt;br /&gt;
//Ожидаем событие ответа&lt;br /&gt;
&lt;br /&gt;
    request.on('response', function(response) {&lt;br /&gt;
&lt;br /&gt;
// We need to buffer the response chunks in a nonblocking way.&lt;br /&gt;
//Объявляем строковый буфер, для сбора частей ответа в неблокирующем стиле&lt;br /&gt;
&lt;br /&gt;
      var buffer = '';&lt;br /&gt;
&lt;br /&gt;
//по событию 'data' - добавляем часть ответа в буфер&lt;br /&gt;
&lt;br /&gt;
      response.on('data', function(chunk) {&lt;br /&gt;
        buffer = buffer + chunk;&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
// When all the responses are finished, we decode the JSON and&lt;br /&gt;
// depending on whether it's got a result or an error, we call&lt;br /&gt;
// emitSuccess or emitError on the promise.&lt;br /&gt;
//Когда все части ответа собраны, происходит событие 'end'&lt;br /&gt;
//мы декодируем ответ из формата JSON и в зависимости от того что в ответе &lt;br /&gt;
//содержится, result или error вызывается обработка события emitSuccess или &lt;br /&gt;
//emitError&lt;br /&gt;
      &lt;br /&gt;
      response.on('end', function() {&lt;br /&gt;
        var decoded = JSON.parse(buffer); // TODO: Check for invalid response from server&lt;br /&gt;
&lt;br /&gt;
//Если есть свойство result&lt;br /&gt;
&lt;br /&gt;
        if(decoded.hasOwnProperty('result')) {&lt;br /&gt;
&lt;br /&gt;
//Если задана функция callback, вызываем её первым параметром передаем null - признак отсутствия ошибки&lt;br /&gt;
//вторым - результаты из декодированного JSON ответа &lt;br /&gt;
&lt;br /&gt;
          if (callback) &lt;br /&gt;
            callback(null, decoded.result);&lt;br /&gt;
&lt;br /&gt;
//Если нет свойства result - то значит ошибка&lt;br /&gt;
          &lt;br /&gt;
        } else {&lt;br /&gt;
&lt;br /&gt;
// Call error handler if it is set, otherwise call callback with error parameters&lt;br /&gt;
//Вызываем заданный обработчик ошибки, если он задан. Иначе переедаем ошибку на обработку &lt;br /&gt;
//в callback первым параметром с аргументами функции равными null&lt;br /&gt;
          if (errback) {&lt;br /&gt;
          	errback(decoded.error);&lt;br /&gt;
          } else if(callback) {&lt;br /&gt;
          	callback(decoded.error, null);&lt;br /&gt;
          }&lt;br /&gt;
       }&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
===Функция (объект) Server===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
function Server() {&lt;br /&gt;
  var self = this;     //непонятная манипуляция с областью видимости (контекстом)&lt;br /&gt;
  this.functions = {}; //объект (именованный массив) для текста вызываемых методов&lt;br /&gt;
  this.scopes = {};    //объект (именованный массив) для областей видимости (контекстов вызываемых методов)&lt;br /&gt;
  this.defaultScope = this; // область видимости (контекстов вызываемых методов) по умолчанию, если не задана специально&lt;br /&gt;
  this.server = http.createServer(function(req, res) { //создаем http сервер, в качестве параметра функция обработки  &lt;br /&gt;
                                                       //запроса и ответа&lt;br /&gt;
    Server.trace('&amp;lt;--', 'accepted request');           //трассировка принятия запроса&lt;br /&gt;
    if(req.method === 'POST') {                        //если запрос пришел по методу POST, то обрабатываем функцией  handlePOST&lt;br /&gt;
      self.handlePOST(req, res);&lt;br /&gt;
    }&lt;br /&gt;
    else {                                             //если не POST, то обрабатываем функцией handleNonPOST &lt;br /&gt;
      Server.handleNonPOST(req, res);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
====Расширение функции Server методом exposeModule====&lt;br /&gt;
'''''Данный метод вызывается только при необходимости (в частности при инициализации), его производительность не критична для приложения в целом.'''''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
//Исходные методы, которые в последствии будут вызываться, можно передавать целыми модулями (в формате JSON)&lt;br /&gt;
//Например:&lt;br /&gt;
// var math = {&lt;br /&gt;
//   power: function(args, opts, callback) {&lt;br /&gt;
//     callback(Math.pow(args[0], args[1]));&lt;br /&gt;
//   },&lt;br /&gt;
//   sqrt: function(args, opts, callback) {&lt;br /&gt;
//     callback(Math.sqrt(args[0]));&lt;br /&gt;
//   }&lt;br /&gt;
//  }&lt;br /&gt;
//&lt;br /&gt;
//server.exposeModule('math', math);&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
//Данный метод добавляет в объект functions свойство из параметра mod (имя модуля), а в mod свойство из параметра&lt;br /&gt;
// funcName (имя фукнкции), а значение funcName присваивает из параметра  funcObj (тело функции)&lt;br /&gt;
// т.е. получается functions[mod.funcName] = funcObj;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Server.prototype.exposeModule = function(mod, object, scope) {&lt;br /&gt;
  var funcs = [];                         //массив, для наполнения названиями обработанных функций из переданного модуля.&lt;br /&gt;
                                          //после разбора выводится в трассировке работы функции&lt;br /&gt;
&lt;br /&gt;
  for(var funcName in object) {           //перебираем все funcName(в примере это power и sqrt) в object (в примере это math)&lt;br /&gt;
&lt;br /&gt;
    var funcObj = object[funcName];       //переменной funcObj присваиваем значение object[funcName]&lt;br /&gt;
                                          //например для object[power] это function(args, opts, callback) {&lt;br /&gt;
                                          //     callback(Math.pow(args[0], args[1]));}&lt;br /&gt;
&lt;br /&gt;
    if(typeof(funcObj) == 'function') {   //если funcObj действительно является функцией&lt;br /&gt;
      this.functions[mod + '.' + funcName] = funcObj;   //добавляем funcObj в объект functions под соответствующим именем&lt;br /&gt;
      funcs.push(funcName);               //добавляем в конец массива funcs имя обработанной функции&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if (scope) {                        //если задан контекст, то его добавляем в объект scopes под соответствующим именем&lt;br /&gt;
        this.scopes[mod + '.' + funcName] = scope;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  Server.trace('***', 'exposing module: ' + mod + ' [funs: ' + funcs.join(', ') //выводим трассировку&lt;br /&gt;
                + ']');&lt;br /&gt;
  return object;                          //возвращаем объект  (не понятно зачем)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Расширение функции Server методом expose====&lt;br /&gt;
'''''Данный метод вызывается только при необходимости (в частности при инициализации), его производительность не критична для приложения в целом.'''''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
//Данный метод добавляет в объект functions метод под именем name, т.е. functions[name] = func&lt;br /&gt;
//если указан контекст. то под тем же именем в объект scopes добавляется контекст scopes[name] = scope&lt;br /&gt;
&lt;br /&gt;
//name - имя заносимого метода&lt;br /&gt;
//func - тело заносимого метода&lt;br /&gt;
//scope - контекст (область видимости) для данного метода&lt;br /&gt;
&lt;br /&gt;
Server.prototype.expose = function(name, func, scope) {&lt;br /&gt;
  Server.trace('***', 'exposing: ' + name);&lt;br /&gt;
  this.functions[name] = func;&lt;br /&gt;
&lt;br /&gt;
  if (scope) {&lt;br /&gt;
    this.scopes[name] = scope;&lt;br /&gt;
  }&lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Расширение функции Server методом trace====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Server.trace = function(direction, message) {&lt;br /&gt;
  sys.puts('   ' + direction + '   ' + message);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
====Расширение функции Server методом listen====&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Server.prototype.listen = function(port, host) { &lt;br /&gt;
  this.server.listen(port, host);&lt;br /&gt;
  Server.trace('***', 'Server listening on http://' + (host || '127.0.0.1') + &lt;br /&gt;
                ':' + port + '/'); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Расширение функции Server методом handlePOST(основная часть Server)====&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Server.prototype.handlePOST = function(req, res) {&lt;br /&gt;
  var buffer = '';&lt;br /&gt;
  var self = this;&lt;br /&gt;
  var handle = function (buf) {&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
//первая проверка: валидность JSON вообще&lt;br /&gt;
//если JSON не валидный генерируем ошибку -32700 и прекращаем функцию &lt;br /&gt;
//если JSON валидный дальше обрабатываем переменную decoded&lt;br /&gt;
    var decoded = &amp;quot;&amp;quot;;&lt;br /&gt;
    try {&lt;br /&gt;
    	decoded = JSON.parse(buf);&lt;br /&gt;
    } catch (e) {&lt;br /&gt;
    	return Server.handleError(-32700, &amp;quot;Parse Error&amp;quot;, null, req, res);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
// Check for the required fields, and if they aren't there, then&lt;br /&gt;
// dispatch to the handleError function.    &lt;br /&gt;
//вторая проверка: формат запроса по стандарту&lt;br /&gt;
//Наличие полей запроса (метод, параметры, id). id задания может отсутствовать в случае уведомления&lt;br /&gt;
//если id отсутствует, подставляем null всесто отсутствующего id&lt;br /&gt;
//При отсутствии полей запроса (метод, параметры) генерируем ошибку -32600&lt;br /&gt;
//Если нет ошибок - просто не останавливаем функцию и идем дальше&lt;br /&gt;
&lt;br /&gt;
    if(!(decoded.method &amp;amp;&amp;amp; decoded.params &amp;amp;&amp;amp; decoded.id)) {&lt;br /&gt;
      &lt;br /&gt;
      if (typeof(id) == &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
   		var id = null;&lt;br /&gt;
   	  } &lt;br /&gt;
   	  &lt;br /&gt;
      return Server.handleError(-32600, &amp;quot;Invalid Request&amp;quot;, decoded.id, req, res);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
//третья проверка на наличие в functions указанного в запросе метода	&lt;br /&gt;
//в случае ошибки  генерируем ошибку -32601.&lt;br /&gt;
&lt;br /&gt;
    if(!self.functions.hasOwnProperty(decoded.method)) {&lt;br /&gt;
      return Server.handleError(-32601, &amp;quot;Method not found&amp;quot;, decoded.id, req, res);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// Build our success handler&lt;br /&gt;
//&lt;br /&gt;
    var onSuccess = function(funcResp) {&lt;br /&gt;
        Server.trace('--&amp;gt;', 'response (id ' + decoded.id + '): '+ JSON.stringify(funcResp));&lt;br /&gt;
	var encoded = JSON.stringify({&lt;br /&gt;
            'jsonrpc': '2.0',&lt;br /&gt;
            'result': funcResp,&lt;br /&gt;
            'error': null,&lt;br /&gt;
            'id': decoded.id&lt;br /&gt;
            });&lt;br /&gt;
      &lt;br /&gt;
      res.writeHead(200, {'Content-Type': 'application/json',&lt;br /&gt;
                          'Content-Length': encoded.length});&lt;br /&gt;
      res.write(encoded);&lt;br /&gt;
      res.end();&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Server.trace('&amp;lt;--', 'request (id ' + decoded.id + '): ' + &lt;br /&gt;
                  decoded.method + '(' + decoded.params.join(', ') + ')');&lt;br /&gt;
&lt;br /&gt;
    // Try to call the method, but intercept errors and call our&lt;br /&gt;
    // onFailure handler.&lt;br /&gt;
    var method = self.functions[decoded.method];&lt;br /&gt;
    var callback = function(result, errormessage) {&lt;br /&gt;
      if (errormessage) {&lt;br /&gt;
        Server.handleError(-32602, errormessage, decoded.id, req, res);&lt;br /&gt;
      } else {&lt;br /&gt;
        onSuccess(result);&lt;br /&gt;
      }&lt;br /&gt;
    };&lt;br /&gt;
    var scope = self.scopes[decoded.method] || self.defaultScope;&lt;br /&gt;
&lt;br /&gt;
    // Other various information we want to pass in for the handler to be&lt;br /&gt;
    // able to access.&lt;br /&gt;
    var opt = {&lt;br /&gt;
      req: req,&lt;br /&gt;
      server: self&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
      method.call(scope, decoded.params, opt, callback);&lt;br /&gt;
    } catch (err) {&lt;br /&gt;
      return Server.handleError(-32603, err, decoded.id, req, res);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
  } // function handle(buf)&lt;br /&gt;
&lt;br /&gt;
  req.addListener('data', function(chunk) {&lt;br /&gt;
    buffer = buffer + chunk;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  req.addListener('end', function() {&lt;br /&gt;
    handle(buffer);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Расширение функции Server методом handleError====&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Server.handleError = function(code, message, id, req, res) {&lt;br /&gt;
  &lt;br /&gt;
  var encoded = JSON.stringify({&lt;br /&gt;
  	'jsonrpc': '2.0',&lt;br /&gt;
    'error': {&lt;br /&gt;
    	'code':code,&lt;br /&gt;
    	'message':message&lt;br /&gt;
    },&lt;br /&gt;
    'id': id&lt;br /&gt;
  });&lt;br /&gt;
  &lt;br /&gt;
  res.writeHead(400, {'Content-Type': 'text/plain',&lt;br /&gt;
                      'Content-Length': encoded.length,&lt;br /&gt;
                      'Allow': 'POST'});&lt;br /&gt;
  &lt;br /&gt;
  res.write(encoded);&lt;br /&gt;
  res.end();&lt;br /&gt;
  &lt;br /&gt;
  Server.trace('--&amp;gt;', 'Failure: ' + code + ': ' + message);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Расширение функции Server методом handleNonPOST====&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Server.handleNonPOST = function(req, res) {&lt;br /&gt;
  &lt;br /&gt;
  var encoded = JSON.stringify({&lt;br /&gt;
  	'jsonrpc': '2.0',&lt;br /&gt;
    'error': {&lt;br /&gt;
    	'code':-32600,&lt;br /&gt;
    	'message':&amp;quot;Only POST is allowed.&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    'id': null&lt;br /&gt;
  });&lt;br /&gt;
  &lt;br /&gt;
  res.writeHead(405, {'Content-Type': 'text/plain',&lt;br /&gt;
                      'Content-Length': encoded.length,&lt;br /&gt;
                      'Allow': 'POST'});&lt;br /&gt;
  res.write(encoded);&lt;br /&gt;
  res.end();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Активный экспорт переменных===&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
module.exports.Server = Server;&lt;br /&gt;
module.exports.Client = Client;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>imported&gt;Supportadmin</name></author>
	</entry>
</feed>