Advertisement
Guest User

Untitled

a guest
Jul 8th, 2017
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var sha1 = require("./sha1").hex;
  2. var http = require("http");
  3. var mysql = require('./mysql');
  4. var settings = require("./settings");
  5.  
  6. if(Array.prototype.clear === undefined)
  7. Array.prototype.clear = function()
  8. {
  9.     for(var i=this.length; i>=0; i--)
  10.         delete this[i];
  11.     this.length = 0;
  12.     return this;
  13. }
  14.  
  15. if(Array.prototype.contains === undefined)
  16. Array.prototype.contains = function(element)
  17. {
  18.     return this.indexOf(element)!=-1;
  19. }
  20.  
  21. if(Array.prototype.add === undefined)
  22. Array.prototype.add = function(element)
  23. {
  24.     if(!this.contains(element))
  25.         this.push(element);
  26. }
  27.  
  28. if(Array.prototype.remove === undefined)
  29. Array.prototype.remove = function(value)
  30. {
  31.  
  32.     for(var i=0; i<this.length; i++)
  33.         if(this[i] === value)
  34.             this.splice(i--, 1);
  35.     return this;
  36. }
  37.  
  38. if(Array.prototype.clean === undefined)
  39. Array.prototype.clean = function()
  40. {
  41.     for(var i=0; i<this.length; i++)
  42.         if(this[i] === undefined
  43.         || this[i] === null)
  44.             this.splice(i--, 1);
  45.     return this;
  46. }
  47.  
  48. if(Array.prototype.clear === undefined)
  49. Array.prototype.clear = function()
  50. {
  51.     for(var i=this.length; i>=0; i--)
  52.         delete this[i];
  53.     this.length = 0;
  54.     return this;
  55. }
  56.  
  57. function JSONResponse(database, request, response)
  58. {
  59.     var self = this;
  60.  
  61.     this._user = undefined;
  62.     this._database = database;
  63.     this._request = request;
  64.     this._response = response;
  65.     this._JSONObject = {
  66.         errors:[]
  67.     };
  68.     this._time = new Date();
  69.  
  70.     this._cookie = {};
  71.  
  72.     var rawcookie = request.headers.cookie
  73.             ?request.headers.cookie.split(/;\s*/)
  74.             :[];
  75.     for(var i=0; i<rawcookie.length; i++)
  76.     {
  77.         rawcookie[i] = rawcookie[i].split("=");
  78.         this._cookie[rawcookie[i][0]] = unescape(rawcookie[i][1]);
  79.     }
  80.  
  81.     this._params = request.url.substr(1).split("/");
  82.  
  83.     console.log(this._params);
  84.  
  85.     response.writeHead(200,{"Content-Type": "application/json"});
  86.  
  87.     this.getTime = function()
  88.     {
  89.         return self._time;
  90.     }
  91.  
  92.     this.getCookie = function(key)
  93.     {
  94.         return self._cookie[key];
  95.     }
  96.  
  97.     /**
  98.      * Get the currently logged in user. Calls the callback method with the user
  99.      * that is logged in, or with NULL if there is no login.
  100.      * @param cb The callback function.
  101.      */
  102.     this.validateLogin = function(cb)
  103.     {
  104.         if(this._user !== undefined)
  105.         {
  106.             cb(self._user);
  107.             return;
  108.         }
  109.         if(!self.getCookie("login"))
  110.         {
  111.             self._user = null;
  112.             cb(self._user);
  113.             return;
  114.         }
  115.         var loginstr = self.getCookie("login").split(",");
  116.         var userId = parseInt(loginstr[0]);
  117.         var passHash = loginstr[1];
  118.         self._database.getUser(userId, function(user)
  119.         {
  120.             user.checkPassword(passHash, function(isValid)
  121.             {
  122.                 self._user = isValid?user:null;
  123.                 cb(self._user);
  124.             });
  125.         });
  126.     }
  127.  
  128.     this.addError = function(message)
  129.     {
  130.         self._JSONObject.errors.push(message);
  131.     }
  132.  
  133.     this.getParam = function(i)
  134.     {
  135.         return self._params[i];
  136.     }
  137.  
  138.     this.getParams = function()
  139.     {
  140.         return self._params;
  141.     }
  142.  
  143.     this.getUser = function()
  144.     {
  145.         return self._user;
  146.     }
  147.  
  148.     this.set = function(key, value)
  149.     {
  150.         self._JSONObject[key] = value;
  151.     }
  152.  
  153.     this.get = function(key)
  154.     {
  155.         return self._JSONObject[key];
  156.     }
  157.  
  158.     this.end = function()
  159.     {
  160.         self._response.end(JSON.stringify(self._JSONObject));
  161.     }
  162. }
  163.  
  164. function Database(sqlClient)
  165. {
  166.     var self = this;
  167.  
  168.     /** @var The MySQL Client connection. */
  169.     this._sql = sqlClient;
  170.  
  171.     /** @var A cache with Product-objects. */
  172.     this._products = {};
  173.  
  174.     /** @var A cache with User-objects. */
  175.     this._users = {};
  176.  
  177.     /** @var A cache with Bid-objects. */
  178.     this._bids = {};
  179.  
  180.     /** @var An array with on-bid-placed-event listeners. */
  181.     this._onBidPlacedEventListeners = [];
  182.  
  183.     /**
  184.      *
  185.      */
  186.     this._triggerOnBidPlacedEventListeners = function(bid)
  187.     {
  188.         for(var i=0; i<self._onBidPlacedEventListeners.length; i++)
  189.             self._onBidPlacedEventListeners[i](bid);
  190.     }
  191.  
  192.     /**
  193.      * Add a on-bid-placed-event-listener. The function will be called everytime
  194.      * a bid is placed on any product. The callback will be given a
  195.      * Bid-object which the bid was placed on as a first parameter.
  196.      * @param cb The event-listener.
  197.      */
  198.     this.addOnBidPlacedEventListener = function(cb)
  199.     {
  200.         self._onBidPlacedEventListeners.add(cb);
  201.     }
  202.  
  203.     this.removeOnBidPlacedEventListener = function(cb)
  204.     {
  205.         self._onBidPlacedEventListeners.remove(cb);
  206.     }
  207.  
  208.     /**
  209.      * Get a product from this database. Calls a callback method with the
  210.      * retrieved Product-object on completion, or with NULL if the Product
  211.      * doesn't exist.
  212.      * @param id The id of the product to get.
  213.      * @param cb The callback.
  214.      */
  215.     this.getProduct = function(id, cb)
  216.     {
  217.         id = parseInt(id);
  218.         if(self._products[id] !== undefined)
  219.         {
  220.             cb(self._products[id]);
  221.             return;
  222.         }
  223.         self._sql.query("SELECT title, UNIX_TIMESTAMP(timeStart) as time "
  224.                 +"FROM products WHERE id = ? LIMIT 1",
  225.         [id],
  226.         function(err, results, fields)
  227.         {
  228.             if(err)
  229.                 throw err;
  230.             self._products[id] = results.length == 0
  231.                     ?null
  232.                     :new Product(self, id,
  233.                                  results[0].title,
  234.                                  new Date(results[0].time*1000));
  235.             if(self._products[id])
  236.                 self._products[id].addOnBidPlacedEventListener(
  237.                         self._triggerOnBidPlacedEventListeners);
  238.             cb(self._products[id]);
  239.         });
  240.     }
  241.  
  242.     /**
  243.      * Get a user from this database. Calls a callback method with the retrieved
  244.      * User-object on completion, or with NULL if there is no user with that id.
  245.      * @param id The id of the user.
  246.      * @param cb The callback.
  247.      */
  248.     this.getUser = function(id, cb)
  249.     {
  250.         id = parseInt(id);
  251.         if(self._users[id] !== undefined)
  252.         {
  253.             cb(self._users[id]);
  254.             return;
  255.         }
  256.         self._sql.query("SELECT username FROM users WHERE id = ? LIMIT 1",
  257.         [id],
  258.         function(err, results, fields)
  259.         {
  260.             if(err)
  261.                 throw err;
  262.             self._users[id] = results.length == 0
  263.                     ?null
  264.                     :new User(self, id, results[0].username);
  265.             cb(self._users[id]);
  266.         });
  267.     }
  268.  
  269.     /**
  270.      * Get a bid from this database. Calls a callback method with the retrieved
  271.      * Bid-object on completion, or with NULL if there is no bid with that id.
  272.      * @param id The id of the bid.
  273.      * @param cb The callback.
  274.      */
  275.     this.getBid = function(id, cb)
  276.     {
  277.         id = parseInt(id);
  278.         if(self._bids[id] !== undefined)
  279.         {
  280.             cb(self._bids[id]);
  281.             return;
  282.         }
  283.         self._sql.query("SELECT id, product, centiTime, user "
  284.                 +"FROM bids WHERE id = ? LIMIT 1",
  285.         [id],
  286.         function(err, results, fields)
  287.         {
  288.             if(err)
  289.                 throw err;
  290.             if(results.length == 0)
  291.             {
  292.                 self._bids[id] = null;
  293.                 cb(self._bids[id]);
  294.                 return;
  295.             }
  296.             var bidUser = undefined;
  297.             var bidProduct = undefined;
  298.             var bidAdditionalDataCallback = function()
  299.             {
  300.                 if(bidUser === undefined
  301.                 || bidProduct === undefined)
  302.                     return;
  303.                 var time = new Date( bidProduct.getStartTime().getTime()
  304.                                    + results[0].centiTime*10);
  305.                 self._bids[id] = new Bid(self, id, bidProduct,
  306.                                          new Date(time), bidUser);
  307.                 cb(self._bids[id]);
  308.             }
  309.             self.getUser(results[0].user, function(user)
  310.             {
  311.                 bidUser = user;
  312.                 bidAdditionalDataCallback();
  313.             });
  314.             self.getProduct(results[0].product, function(product)
  315.             {
  316.                 bidProduct = product;
  317.                 bidAdditionalDataCallback();
  318.             });
  319.         });
  320.     }
  321. }
  322.  
  323. function User(db, id, username)
  324. {
  325.     var self = this;
  326.  
  327.     this._database = db;
  328.     this._id = id;
  329.     this._username = username;
  330.  
  331.     this.getId = function()
  332.     {
  333.         return self._id;
  334.     }
  335.  
  336.     this.getUsername = function()
  337.     {
  338.         return self._username;
  339.     }
  340.  
  341.     /**
  342.      * Check a user's password. Calls a callback after checking is done. The
  343.      * callback will be called with a boolean as a first parameter, containing
  344.      * TRUE if the given passwordhash did match the password or FALSE otherwise.
  345.      */
  346.     this.checkPassword = function(passhash, cb)
  347.     {
  348.         this._database._sql.query("SELECT COUNT(1) FROM users "
  349.                 +"WHERE id = ? AND password = UNHEX(?) LIMIT 1",
  350.         [this.getId(), passhash],
  351.         function(err, results, fields)
  352.         {
  353.             if(err)
  354.                 throw err;
  355.             cb(results.length > 0);
  356.         });
  357.     }
  358. }
  359.  
  360. function Product(db, id, title, time)
  361. {
  362.     var self = this;
  363.    
  364.     this._database = db;
  365.     this._id = id;
  366.     this._title = title;
  367.     this._time = time;
  368.     this._lastBid = null;
  369.     this._secondLastBid = null;
  370.  
  371.     /** @var An array with on-bid-placed-event listeners. */
  372.     this._onBidPlacedEventListeners = [];
  373.  
  374.     /**
  375.      *
  376.      */
  377.     this._triggerOnBidPlacedEventListeners = function(bid)
  378.     {
  379.         for(var i=0; i<self._onBidPlacedEventListeners.length; i++)
  380.             self._onBidPlacedEventListeners[i](bid);
  381.     }
  382.  
  383.     /**
  384.      * Add a on-bid-placed-event-listener. The function will be called everytime
  385.      * a bid is placed on any product. The callback will be given a
  386.      * Bid-object which the bid was placed on as a first parameter.
  387.      * @param cb The event-listener.
  388.      */
  389.     this.addOnBidPlacedEventListener = function(cb)
  390.     {
  391.         self._onBidPlacedEventListeners.add(cb);
  392.     }
  393.  
  394.     this.removeOnBidPlacedEventListener = function(cb)
  395.     {
  396.         self._onBidPlacedEventListeners.remove(cb);
  397.     }
  398.  
  399.     /**
  400.      * Get the id of this product.
  401.      * @type Number
  402.      * @return the id
  403.      */
  404.     this.getId = function()
  405.     {
  406.         return self._id;
  407.     }
  408.  
  409.     this.getTitle = function()
  410.     {
  411.         return self._title;
  412.     }
  413.  
  414.     /**
  415.      * Get the time this Product will start.
  416.      * @type Date
  417.      * @return The time
  418.      */
  419.     this.getStartTime = function()
  420.     {
  421.         return self._time;
  422.     }
  423.  
  424.     this.placeBid = function(time, user, cb)
  425.     {
  426.         var centiTime = (time.getTime() - self.getStartTime().getTime())/10;
  427.         self._database._sql.query(
  428.                 "INSERT INTO bids (product, centiTime, user) VALUES(?,?,?)",
  429.         [self.getId(), centiTime, user.getId()],
  430.         function(err, results, fields)
  431.         {
  432.             if(err)
  433.                 throw err;
  434.             db.getBid(results.insertId, function(bid)
  435.             {
  436.                 self._triggerOnBidPlacedEventListeners(bid);
  437.                 cb(bid);
  438.             });
  439.         });
  440.     }
  441. }
  442.  
  443. function Bid(db, id, product, time, user)
  444. {
  445.     var self = this;
  446.    
  447.     this._database = db;
  448.     this._id = id;
  449.     this._product = product;
  450.     this._time = time;
  451.     this._user = user;
  452.  
  453.     this.getId = function()
  454.     {
  455.         return self._id;
  456.     }
  457.  
  458.     /**
  459.      * Get the time this Bid was placed.
  460.      * @type Date
  461.      * @return The time
  462.      */
  463.     this.getTime = function()
  464.     {
  465.         return self._time;
  466.     }
  467.  
  468.     this.getProduct = function()
  469.     {
  470.         return self._product;
  471.     }
  472.  
  473.     this.getUser = function()
  474.     {
  475.         return self._user;
  476.     }
  477. }
  478.  
  479. function handleJSONResponse(response)
  480. {
  481.     switch(response.getParam(0))
  482.     {
  483.         case "place-bid":
  484.             var bidProduct = undefined;
  485.             var bidUser = undefined;
  486.             var productAndUserFetchedCallback = function()
  487.             {
  488.                 if(bidProduct === undefined
  489.                 || bidUser === undefined)
  490.                     return;
  491.                 if(!bidUser||!bidProduct)
  492.                 {
  493.                     if(!bidUser)
  494.                         response.addError("Placing a bid requires a login.");
  495.                     if(!bidProduct)
  496.                         response.addError("Product does not exist.");
  497.                     response.end();
  498.                     return;
  499.                 }
  500.                 bidProduct.placeBid(response.getTime(), bidUser,
  501.                 function(bid)
  502.                 {
  503.                     response.set("bid", {
  504.                         id: bid.getId(),
  505.                         time: bid.getTime().getTime(),
  506.                         user: {
  507.                             id: bid.getUser().getId(),
  508.                             username: bid.getUser().getUsername()
  509.                         },
  510.                         product: {
  511.                             id: bid.getProduct().getId(),
  512.                             title: bid.getProduct().getTitle(),
  513.                             time: bid.getProduct().getStartTime().getTime()
  514.                         }
  515.                     });
  516.                     response.end();
  517.                 });
  518.             }
  519.             db.getProduct(response.getParam(1), function(product)
  520.             {
  521.                 bidProduct = product;
  522.                 productAndUserFetchedCallback();
  523.             });
  524.             response.validateLogin(function(user)
  525.             {
  526.                 bidUser = user;
  527.                 productAndUserFetchedCallback();
  528.             });
  529.             break;
  530.         case "next-bid":
  531.             db.addOnBidPlacedEventListener(function(bid)
  532.             {
  533.                 response.set("bid", {
  534.                     id: bid.getId(),
  535.                     time: bid.getTime().getTime(),
  536.                     user: {
  537.                         id: bid.getUser().getId(),
  538.                         username: bid.getUser().getUsername()
  539.                     },
  540.                     product: {
  541.                         id: bid.getProduct().getId(),
  542.                         title: bid.getProduct().getTitle(),
  543.                         time: bid.getProduct().getStartTime().getTime()
  544.                     }
  545.                 });
  546.                 response.end();
  547.             });
  548.             break;
  549.         case "product-info":
  550.             db.getProduct(response.getParam(1), function(product)
  551.             {
  552.                 response.set("product", {
  553.                     id: product.getId(),
  554.                     title: product.getTitle(),
  555.                     time: product.getStartTime().getTime()
  556.                 });
  557.                 response.end();
  558.             });
  559.             break;
  560.         case "ping":
  561.             response.end();
  562.             break;
  563.         default:
  564.             response.addError("Unknown Command");
  565.             response.end();
  566.     }
  567. }
  568.  
  569. var client = mysql.Client();
  570. client.host = settings.sqlHost;
  571. client.user = settings.sqlUser;
  572. client.password = settings.sqlPass;
  573.  
  574. client.connect();
  575.  
  576. client.useDatabase(settings.sqlDatabase);
  577.  
  578. var db = new Database(client);
  579.  
  580. http.createServer(function(request, response)
  581. {
  582.     var jsonresponse = new JSONResponse(db, request, response);
  583.     handleJSONResponse(jsonresponse);
  584. }).listen(settings.httpPort);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement