Advertisement
taufikmas

client.js

Jun 7th, 2017
300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var crypto = require('crypto');
  2. var EventEmitter = require('events').EventEmitter;
  3. var util = require('util');
  4. var pgPass = require('pgpass');
  5. var TypeOverrides = require('./type-overrides');
  6.  
  7. var ConnectionParameters = require('./connection-parameters');
  8. var Query = require('./query');
  9. var defaults = require('./defaults');
  10. var Connection = require('./connection');
  11.  
  12. var Client = function(config) {
  13.   EventEmitter.call(this);
  14.  
  15.   this.connectionParameters = new ConnectionParameters(config);
  16.   this.user = this.connectionParameters.user;
  17.   this.database = this.connectionParameters.database;
  18.   this.port = this.connectionParameters.port;
  19.   this.host = this.connectionParameters.host;
  20.   this.password = this.connectionParameters.password;
  21.  
  22.   var c = config || {};
  23.  
  24.   this._types = new TypeOverrides(c.types);
  25.  
  26.   this.connection = c.connection || new Connection({
  27.     stream: c.stream,
  28.     ssl: this.connectionParameters.ssl
  29.   });
  30.   this.queryQueue = [];
  31.   this.binary = c.binary || defaults.binary;
  32.   this.encoding = 'utf8';
  33.   this.processID = null;
  34.   this.secretKey = null;
  35.   this.ssl = this.connectionParameters.ssl || false;
  36. };
  37.  
  38. util.inherits(Client, EventEmitter);
  39.  
  40. Client.prototype.connect = function(callback) {
  41.   var self = this;
  42.   var con = this.connection;
  43.  
  44.   if(this.host && this.host.indexOf('/') === 0) {
  45.     con.connect(this.host + '/.s.PGSQL.' + this.port);
  46.   } else {
  47.     con.connect(this.port, this.host);
  48.   }
  49.  
  50.  
  51.   //once connection is established send startup message
  52.   con.on('connect', function() {
  53.     if(self.ssl) {
  54.       con.requestSsl();
  55.     } else {
  56.       con.startup(self.getStartupConf());
  57.     }
  58.   });
  59.  
  60.   con.on('sslconnect', function() {
  61.     con.startup(self.getStartupConf());
  62.   });
  63.  
  64.   function checkPgPass(cb) {
  65.     return function(msg) {
  66.       if (null !== self.password) {
  67.         cb(msg);
  68.       } else {
  69.         pgPass(self.connectionParameters, function(pass){
  70.           if (undefined !== pass) {
  71.             self.connectionParameters.password = self.password = pass;
  72.           }
  73.           cb(msg);
  74.         });
  75.       }
  76.     };
  77.   }
  78.  
  79.   //password request handling
  80.   con.on('authenticationCleartextPassword', checkPgPass(function() {
  81.     con.password(self.password);
  82.   }));
  83.  
  84.   //password request handling ori
  85.  /*
  86.  con.on('authenticationMD5Password', checkPgPass(function(msg) {
  87.     var inner = Client.md5(self.password + self.user);
  88.     var outer = Client.md5(Buffer.concat([new Buffer(inner), msg.salt]));
  89.     var md5password = "md5" + outer;
  90.     con.password(md5password);
  91.   }));
  92. */
  93.  
  94.   //revisi fixxx
  95.  
  96.      //password request handling
  97.    con.on('authenticationMD5Password', checkPgPass(function(msg) {
  98.      var inner = Client.md5(self.password + self.user);
  99.      var outer = Client.md5(Buffer.concat([new Buffer(inner), msg.salt]));
  100.      var md5password = "md5" + outer;
  101.      con.password(md5password);
  102.    }));
  103.  
  104.  
  105.   con.once('backendKeyData', function(msg) {
  106.     self.processID = msg.processID;
  107.     self.secretKey = msg.secretKey;
  108.   });
  109.  
  110.   //hook up query handling events to connection
  111.   //after the connection initially becomes ready for queries
  112.   con.once('readyForQuery', function() {
  113.  
  114.     //delegate rowDescription to active query
  115.     con.on('rowDescription', function(msg) {
  116.       self.activeQuery.handleRowDescription(msg);
  117.     });
  118.  
  119.     //delegate dataRow to active query
  120.     con.on('dataRow', function(msg) {
  121.       self.activeQuery.handleDataRow(msg);
  122.     });
  123.  
  124.     //delegate portalSuspended to active query
  125.     con.on('portalSuspended', function(msg) {
  126.       self.activeQuery.handlePortalSuspended(con);
  127.     });
  128.  
  129.     //deletagate emptyQuery to active query
  130.     con.on('emptyQuery', function(msg) {
  131.       self.activeQuery.handleEmptyQuery(con);
  132.     });
  133.  
  134.     //delegate commandComplete to active query
  135.     con.on('commandComplete', function(msg) {
  136.       self.activeQuery.handleCommandComplete(msg, con);
  137.     });
  138.  
  139.     //if a prepared statement has a name and properly parses
  140.     //we track that its already been executed so we don't parse
  141.     //it again on the same client
  142.     con.on('parseComplete', function(msg) {
  143.       if(self.activeQuery.name) {
  144.         con.parsedStatements[self.activeQuery.name] = true;
  145.       }
  146.     });
  147.  
  148.     con.on('copyInResponse', function(msg) {
  149.       self.activeQuery.handleCopyInResponse(self.connection);
  150.     });
  151.  
  152.     con.on('copyData', function (msg) {
  153.       self.activeQuery.handleCopyData(msg, self.connection);
  154.     });
  155.  
  156.     con.on('notification', function(msg) {
  157.       self.emit('notification', msg);
  158.     });
  159.  
  160.     //process possible callback argument to Client#connect
  161.     if (callback) {
  162.       callback(null, self);
  163.       //remove callback for proper error handling
  164.       //after the connect event
  165.       callback = null;
  166.     }
  167.     self.emit('connect');
  168.   });
  169.  
  170.   con.on('readyForQuery', function() {
  171.     var activeQuery = self.activeQuery;
  172.     self.activeQuery = null;
  173.     self.readyForQuery = true;
  174.     self._pulseQueryQueue();
  175.     if(activeQuery) {
  176.       activeQuery.handleReadyForQuery();
  177.     }
  178.   });
  179.  
  180.   con.on('error', function(error) {
  181.     if(self.activeQuery) {
  182.       var activeQuery = self.activeQuery;
  183.       self.activeQuery = null;
  184.       return activeQuery.handleError(error, con);
  185.     }
  186.     if(!callback) {
  187.       return self.emit('error', error);
  188.     }
  189.     callback(error);
  190.     callback = null;
  191.   });
  192.  
  193.   con.once('end', function() {
  194.     if ( callback ) {
  195.       // haven't received a connection message yet !
  196.       var err = new Error('Connection terminated');
  197.       callback(err);
  198.       callback = null;
  199.       return;
  200.     }
  201.     if(self.activeQuery) {
  202.       var disconnectError = new Error('Connection terminated');
  203.       self.activeQuery.handleError(disconnectError, con);
  204.       self.activeQuery = null;
  205.     }
  206.     self.emit('end');
  207.   });
  208.  
  209.  
  210.   con.on('notice', function(msg) {
  211.     self.emit('notice', msg);
  212.   });
  213.  
  214. };
  215.  
  216. Client.prototype.getStartupConf = function() {
  217.   var params = this.connectionParameters;
  218.  
  219.   var data = {
  220.     user: params.user,
  221.     database: params.database
  222.   };
  223.  
  224.   var appName = params.application_name || params.fallback_application_name;
  225.   if (appName) {
  226.     data.application_name = appName;
  227.   }
  228.  
  229.   return data;
  230. };
  231.  
  232. Client.prototype.cancel = function(client, query) {
  233.   if(client.activeQuery == query) {
  234.     var con = this.connection;
  235.  
  236.     if(this.host && this.host.indexOf('/') === 0) {
  237.       con.connect(this.host + '/.s.PGSQL.' + this.port);
  238.     } else {
  239.       con.connect(this.port, this.host);
  240.     }
  241.  
  242.     //once connection is established send cancel message
  243.     con.on('connect', function() {
  244.       con.cancel(client.processID, client.secretKey);
  245.     });
  246.   } else if(client.queryQueue.indexOf(query) != -1) {
  247.     client.queryQueue.splice(client.queryQueue.indexOf(query), 1);
  248.   }
  249. };
  250.  
  251. Client.prototype.setTypeParser = function(oid, format, parseFn) {
  252.   return this._types.setTypeParser(oid, format, parseFn);
  253. };
  254.  
  255. Client.prototype.getTypeParser = function(oid, format) {
  256.   return this._types.getTypeParser(oid, format);
  257. };
  258.  
  259. // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
  260. Client.prototype.escapeIdentifier = function(str) {
  261.  
  262.   var escaped = '"';
  263.  
  264.   for(var i = 0; i < str.length; i++) {
  265.     var c = str[i];
  266.     if(c === '"') {
  267.       escaped += c + c;
  268.     } else {
  269.       escaped += c;
  270.     }
  271.   }
  272.  
  273.   escaped += '"';
  274.  
  275.   return escaped;
  276. };
  277.  
  278. // Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
  279. Client.prototype.escapeLiteral = function(str) {
  280.  
  281.   var hasBackslash = false;
  282.   var escaped = '\'';
  283.  
  284.   for(var i = 0; i < str.length; i++) {
  285.     var c = str[i];
  286.     if(c === '\'') {
  287.       escaped += c + c;
  288.     } else if (c === '\\') {
  289.       escaped += c + c;
  290.       hasBackslash = true;
  291.     } else {
  292.       escaped += c;
  293.     }
  294.   }
  295.  
  296.   escaped += '\'';
  297.  
  298.   if(hasBackslash === true) {
  299.     escaped = ' E' + escaped;
  300.   }
  301.  
  302.   return escaped;
  303. };
  304.  
  305. Client.prototype._pulseQueryQueue = function() {
  306.   if(this.readyForQuery===true) {
  307.     this.activeQuery = this.queryQueue.shift();
  308.     if(this.activeQuery) {
  309.       this.readyForQuery = false;
  310.       this.hasExecuted = true;
  311.       this.activeQuery.submit(this.connection);
  312.     } else if(this.hasExecuted) {
  313.       this.activeQuery = null;
  314.       this.emit('drain');
  315.     }
  316.   }
  317. };
  318.  
  319. Client.prototype.copyFrom = function (text) {
  320.   throw new Error("For PostgreSQL COPY TO/COPY FROM support npm install pg-copy-streams");
  321. };
  322.  
  323. Client.prototype.copyTo = function (text) {
  324.   throw new Error("For PostgreSQL COPY TO/COPY FROM support npm install pg-copy-streams");
  325. };
  326.  
  327. Client.prototype.query = function(config, values, callback) {
  328.   //can take in strings, config object or query object
  329.   var query = (typeof config.submit == 'function') ? config :
  330.      new Query(config, values, callback);
  331.   if(this.binary && !query.binary) {
  332.     query.binary = true;
  333.   }
  334.   if(query._result) {
  335.     query._result._getTypeParser = this._types.getTypeParser.bind(this._types);
  336.   }
  337.  
  338.   this.queryQueue.push(query);
  339.   this._pulseQueryQueue();
  340.   return query;
  341. };
  342.  
  343. Client.prototype.end = function() {
  344.   this.connection.end();
  345. };
  346.  
  347. Client.md5 = function(string) {
  348.   return crypto.createHash('md5').update(string).digest('hex');
  349. };
  350.  
  351. // expose a Query constructor
  352. Client.Query = Query;
  353.  
  354. module.exports = Client;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement