Advertisement
Guest User

Untitled

a guest
Jul 12th, 2017
62
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 util = require("../js/util");
  5. var settings = require("./settings");
  6.  
  7. function JSONResponse(database, request, response)
  8. {
  9.     var self = this;
  10.  
  11.     this._user = undefined;
  12.     this._database = database;
  13.     this._request = request;
  14.     this._response = response;
  15.     this._JSONObject = {};
  16.     this._time = new Date();
  17.     this._rawResponse = null;
  18.  
  19.     this._cookie = {};
  20.  
  21.     var rawcookie = request.headers.cookie
  22.             ?request.headers.cookie.split(/;\s*/)
  23.             :[];
  24.     for(var i=0; i<rawcookie.length; i++)
  25.     {
  26.         rawcookie[i] = rawcookie[i].split("=");
  27.         this._cookie[rawcookie[i][0]] = unescape(rawcookie[i][1]);
  28.     }
  29.  
  30.     this._params = request.url.substr(1).split("/");
  31.  
  32.     console.log(request.headers["x-forwarded-for"]+": "
  33.                +this._params.join(" "));
  34.  
  35.     response.writeHead(200,{"Content-Type": "application/json"});
  36.  
  37.     this.getTime = function()
  38.     {
  39.         return self._time;
  40.     }
  41.  
  42.     this.getCookie = function(key)
  43.     {
  44.         return self._cookie[key];
  45.     }
  46.  
  47.     /**
  48.      * Get the currently logged in user. Calls the callback method with the user
  49.      * that is logged in, or with NULL if there is no login.
  50.      * @param cb The callback function.
  51.      */
  52.     this.validateLogin = function(cb)
  53.     {
  54.         if(this._user !== undefined)
  55.         {
  56.             cb(self._user);
  57.             return;
  58.         }
  59.         if(!self.getCookie("login"))
  60.         {
  61.             self._user = null;
  62.             cb(self._user);
  63.             return;
  64.         }
  65.         var loginstr = self.getCookie("login").split(",");
  66.         var userId = parseInt(loginstr[0]);
  67.         var passHash = loginstr[1];
  68.         self._database.getUser(userId, function(user)
  69.         {
  70.             user.checkPassword(passHash, function(isValid)
  71.             {
  72.                 self._user = isValid?user:null;
  73.                 cb(self._user);
  74.             });
  75.         });
  76.     }
  77.  
  78.     this.addError = function(message)
  79.     {
  80.         if(!(self._JSONObject.errors instanceof Array))
  81.             self._JSONObject.errors = new Array();
  82.         self._JSONObject.errors.push(message);
  83.     }
  84.  
  85.     this.getParam = function(i)
  86.     {
  87.         return self._params[i];
  88.     }
  89.  
  90.     this.getParams = function()
  91.     {
  92.         return self._params;
  93.     }
  94.  
  95.     this.getUser = function()
  96.     {
  97.         return self._user;
  98.     }
  99.  
  100.     this.setRawResponse = function(data)
  101.     {
  102.         self._rawResponse = data;
  103.     }
  104.  
  105.     this.getRawResponse = function()
  106.     {
  107.         return JSON.stringify(self._JSONObject);
  108.     }
  109.  
  110.     this.set = function(key, value)
  111.     {
  112.         self._JSONObject[key] = value;
  113.     }
  114.  
  115.     this.get = function(key)
  116.     {
  117.         return self._JSONObject[key];
  118.     }
  119.  
  120.     this.end = function()
  121.     {
  122.         if(self._rawResponse)
  123.             self._response.end(self._rawResponse);
  124.         else
  125.             self._response.end(self.getRawResponse());
  126.     }
  127. }
  128.  
  129. function Database(sqlClient)
  130. {
  131.     var self = this;
  132.  
  133.     /** @var The MySQL Client connection. */
  134.     this._sql = sqlClient;
  135.  
  136.     /** @var A cache with Product-objects. */
  137.     this._products = {};
  138.  
  139.     /** @var A cache with User-objects. */
  140.     this._users = {};
  141.  
  142.     /** @var A cache with Bid-objects. */
  143.     this._bids = {};
  144.  
  145.     /** @var A reference to the last bid. */
  146.     this._lastBid = null;
  147.  
  148.     this._init = function(cb)
  149.     {
  150.         self.getProductsStartingBetween(new Date(0), new Date(), function()
  151.         {
  152.             self._init = undefined;
  153.             setInterval(function()
  154.             {
  155.                 var ids = [];
  156.                 var x = null;
  157.                 ids.clear();
  158.                 for(x in self._products)
  159.                     ids.push(x);
  160.                 console.log("[Cache<Product> "+ids.toString()+"]");
  161.                 ids.clear();
  162.                 for(x in self._users)
  163.                     ids.push(x);
  164.                 console.log("[Cache<User> "+ids.toString()+"]");
  165.                 ids.clear();
  166.                 for(x in self._bids)
  167.                     ids.push(x);
  168.                 console.log("[Cache<Bid> "+ids.toString()+"]");
  169.                 var mem = process.memoryUsage();
  170.                 console.log("[Heap: "+Math.round(mem.heapUsed/1024)+"k used, "
  171.                            +Math.round(mem.heapTotal/1024)+"k reserved]");
  172.             },30000);
  173.             if(cb)cb(self);
  174.         });
  175.     }
  176.  
  177.     /** @var An array with on-bid-placed-event listeners. */
  178.     this._onBidPlacedEventListeners = [];
  179.     this._onProductLoadedEventListeners = [];
  180.  
  181.     /**
  182.      *
  183.      */
  184.     this._triggerOnBidPlacedEventListeners = function(bid)
  185.     {
  186.         for(var i=0; i<self._onBidPlacedEventListeners.length; i++)
  187.             self._onBidPlacedEventListeners[i](bid);
  188.     }
  189.  
  190.     this._triggerOnProductLoadedEventListeners = function(product)
  191.     {
  192.         for(var i=0; i<self._onProductLoadedEventListeners.length; i++)
  193.             self._onProductLoadedEventListeners[i](product);
  194.     }
  195.  
  196.     this.addProductLoadedEventListener = function(cb)
  197.     {
  198.         self._onProductLoadedEventListeners.add(cb);
  199.     }
  200.  
  201.     this.removeProductLoadedEventListener = function(cb)
  202.     {
  203.         self._onProductLoadedEventListeners.remove(cb);
  204.     }
  205.  
  206.     /**
  207.      * Add a on-bid-placed-event-listener. The function will be called everytime
  208.      * a bid is placed on any product. The callback will be given a
  209.      * Bid-object which the bid was placed on as a first parameter.
  210.      * @param cb The event-listener.
  211.      */
  212.     this.addOnBidPlacedEventListener = function(cb)
  213.     {
  214.         self._onBidPlacedEventListeners.add(cb);
  215.     }
  216.  
  217.     this.removeOnBidPlacedEventListener = function(cb)
  218.     {
  219.         self._onBidPlacedEventListeners.remove(cb);
  220.     }
  221.  
  222.     this.query = function(sql, params, cb)
  223.     {
  224.         self._sql.query(sql, params, function(err, results)
  225.         {
  226.             if(err)
  227.             {
  228.                 console.log("ERROR EXECUTING QUERY:");
  229.                 console.log(sql);
  230.                 console.log(self._sql);
  231.                 throw err;
  232.             }
  233.             if(cb)cb(results);
  234.         });
  235.     }
  236.  
  237.     this.uncacheBid = function(bid)
  238.     {
  239.         delete self._bids[bid.getId()];
  240.         var c = 0;
  241.         for(var x in self._bids)
  242.             c++;
  243.         console.log("Purged Bid #"
  244.                    +bid.getId()+" on "
  245.                    +bid.getProduct().getTitle());
  246.     }
  247.  
  248.     this.getLastBid = function()
  249.     {
  250.         return self._lastBid;
  251.     }
  252.  
  253.     this.getProductsStartingBetween = function(start, end, cb)
  254.     {
  255.         self.query("SELECT id FROM products WHERE UNIX_TIMESTAMP(timeStart) "
  256.             +"BETWEEN ? AND ?",
  257.         [start.getTime()/1000, end.getTime()/1000],
  258.         function(results)
  259.         {
  260.             var products = new Array();
  261.             var productsLoadedCallback = function()
  262.             {
  263.                 if(products.length < results.length)
  264.                     return;
  265.                 if(cb)cb(products);
  266.             }
  267.             for(var i=0; i<results.length; i++)
  268.             {
  269.                 self.getProduct(results[i].id, function(product)
  270.                 {
  271.                     products.push(product);
  272.                     productsLoadedCallback();
  273.                 });
  274.             }
  275.         });
  276.     }
  277.  
  278.     this.getLastBidsPlacedAfterBidId = function(bidId, cb)
  279.     {
  280.         self.query("SELECT MAX(id) AS id FROM bids WHERE id > ?"
  281.             +" GROUP BY product",
  282.         [parseInt(bidId)],
  283.         function(results)
  284.         {
  285.             var bids = new Array();
  286.             var bidsLoadedCallback = function()
  287.             {
  288.                 if(bids.length < results.length)
  289.                     return;
  290.                 if(cb)cb(bids);
  291.             }
  292.             for(var i=0; i<results.length; i++)
  293.             {
  294.                 self.getBid(results[i].id, function(bid)
  295.                 {
  296.                     bids.push(bid);
  297.                     bidsLoadedCallback();
  298.                 });
  299.             }
  300.         });
  301.     }
  302.  
  303.     this.getLastBidsPlacedBetween = function(start, end, cb)
  304.     {
  305.         self.query("SELECT bid.id AS id FROM bids AS bid "
  306.             +"JOIN products AS product ON bid.product = product.id "
  307.             +"WHERE UNIX_TIMESTAMP(product.timeStart)+bid.centiTime/100 "
  308.             +"BETWEEN ? AND ? GROUP BY product.id ORDER BY "
  309.             +"bid.id DESC",
  310.         [start.getTime()/1000, end.getTime()/1000],
  311.         function(results)
  312.         {
  313.             var bids = new Array();
  314.             var bidsLoadedCallback = function()
  315.             {
  316.                 if(bids.length < results.length)
  317.                     return;
  318.                 if(cb)cb(bids);
  319.             }
  320.             for(var i=0; i<results.length; i++)
  321.             {
  322.                 self.getBid(results[i].id, function(bid)
  323.                 {
  324.                     bids.push(bid);
  325.                     bidsLoadedCallback();
  326.                 });
  327.             }
  328.         });
  329.     }
  330.  
  331.     /**
  332.      * Get a product from this database. Calls a callback method with the
  333.      * retrieved Product-object on completion, or with NULL if the Product
  334.      * doesn't exist.
  335.      * @param id The id of the product to get.
  336.      * @param cb The callback.
  337.      */
  338.     this.getProduct = function(id, cb)
  339.     {
  340.         id = parseInt(id);
  341.         if(self._products[id] !== undefined)
  342.         {
  343.             if(cb)cb(self._products[id]);
  344.             return;
  345.         }
  346.         self.query("SELECT title, UNIX_TIMESTAMP(timeStart) AS time, thumbnail,"
  347.                 +"value, bidDurationMinimum, bidDurationDecrementInterval, "
  348.                 +"bidDurationDecrementAmount, bidDurationStart, "
  349.                 +"bidValueIncrement FROM products WHERE id = ? LIMIT 1",
  350.         [id],
  351.         function(results)
  352.         {
  353.             if(self._products[id])
  354.             {
  355.                 console.log("Tried to reload "+self._products[id]);
  356.                 if(cb)cb(self._products[id]);
  357.                 return;
  358.             }
  359.             if(results.length == 0)
  360.             {
  361.                 self._products[id] = null;
  362.                 console.log("Loaded "+self._products[id]);
  363.                 if(cb)cb(self._products[id]);
  364.                 return;
  365.             }
  366.             self._products[id]
  367.                     = new Product(self, id,
  368.                                   results[0].title,
  369.                                   results[0].thumbnail,
  370.                                   results[0].value,
  371.                                   new Date(results[0].time*1000),
  372.                                   results[0].bidDurationMinimum,
  373.                                   results[0].bidDurationDecrementInterval,
  374.                                   results[0].bidDurationDecrementAmount,
  375.                                   results[0].bidDurationStart,
  376.                                   results[0].bidValueIncrement);
  377.             self._products[id].addOnBidPlacedEventListener(
  378.                     self._triggerOnBidPlacedEventListeners);
  379.             self._products[id]._init(function(product)
  380.             {
  381.                 console.log("Loaded "+product);
  382.                 self._triggerOnProductLoadedEventListeners(product);
  383.                 if(cb)cb(product);
  384.             });
  385.         });
  386.     }
  387.  
  388.     /**
  389.      * Get a user from this database. Calls a callback method with the retrieved
  390.      * User-object on completion, or with NULL if there is no user with that id.
  391.      * @param id The id of the user.
  392.      * @param cb The callback.
  393.      */
  394.     this.getUser = function(id, cb)
  395.     {
  396.         id = parseInt(id);
  397.         if(self._users[id] !== undefined)
  398.         {
  399.             if(cb)cb(self._users[id]);
  400.             return;
  401.         }
  402.         self.query("SELECT username FROM users WHERE id = ? LIMIT 1",
  403.         [id],
  404.         function(results)
  405.         {
  406.             if(self._users[id])
  407.             {
  408.                 console.log("Tried to reload "+self._users[id]);
  409.                 if(cb)cb(self._users[id]);
  410.                 return;
  411.             }
  412.             self._users[id] = results.length == 0
  413.                     ?null
  414.                     :new User(self, id, results[0].username);
  415.             console.log("Loaded "+self._users[id]);
  416.             if(cb)cb(self._users[id]);
  417.         });
  418.     }
  419.  
  420.     /**
  421.      * Get a bid from this database. Calls a callback method with the retrieved
  422.      * Bid-object on completion, or with NULL if there is no bid with that id.
  423.      * @param id The id of the bid.
  424.      * @param cb The callback.
  425.      */
  426.     this.getBid = function(id, cb)
  427.     {
  428.         id = parseInt(id);
  429.         if(self._bids[id] !== undefined)
  430.         {
  431.             cb(self._bids[id]);
  432.             return;
  433.         }
  434.         self.query("SELECT id, product, centiTime, user "
  435.                 +"FROM bids WHERE id = ? LIMIT 1",
  436.         [id],
  437.         function(results)
  438.         {
  439.             if(self._bids[id])
  440.             {
  441.                 console.log("Tried to reload Bid #"+id+".");
  442.                 if(cb)cb(self._bids[id]);
  443.                 return;
  444.             }
  445.             if(results.length == 0)
  446.             {
  447.                 self._bids[id] = null;
  448.                 console.log("Loaded "+self._bids[id]);
  449.                 if(cb)cb(self._bids[id]);
  450.                 return;
  451.             }
  452.             var bidUser = undefined;
  453.             var bidProduct = undefined;
  454.             var bidAdditionalDataCallback = function()
  455.             {
  456.                 if(bidUser === undefined
  457.                 || bidProduct === undefined)
  458.                     return;
  459.                 if(self._bids[id])
  460.                 {
  461.                     console.log("Tried to reload "+self._bids[id]);
  462.                     if(cb)cb(self._bids[id]);
  463.                     return;
  464.                 }
  465.                 var time = new Date( bidProduct.getStartTime().getTime()
  466.                                    + results[0].centiTime*10);
  467.                 self._bids[id] = new Bid(self, id, bidProduct,
  468.                                          new Date(time), bidUser);
  469.                 self._bids[id]._init(function(bid)
  470.                 {
  471.                     console.log("Loaded "+bid);
  472.                     if(!self._lastBid
  473.                     || self._lastBid.getId() < bid.getId())
  474.                         self._lastBid = bid;
  475.                     if(cb)cb(bid);
  476.                 });
  477.             }
  478.             self.getUser(results[0].user, function(user)
  479.             {
  480.                 bidUser = user;
  481.                 bidAdditionalDataCallback();
  482.             });
  483.             self.getProduct(results[0].product, function(product)
  484.             {
  485.                 bidProduct = product;
  486.                 bidAdditionalDataCallback();
  487.             });
  488.         });
  489.     }
  490. }
  491.  
  492. function User(db, id, username)
  493. {
  494.     var self = this;
  495.  
  496.     this._database = db;
  497.     this._id = id;
  498.     this._username = username;
  499.  
  500.     this.getId = function()
  501.     {
  502.         return self._id;
  503.     }
  504.  
  505.     this.getUsername = function()
  506.     {
  507.         return self._username;
  508.     }
  509.  
  510.     /**
  511.      * Check a user's password. Calls a callback after checking is done. The
  512.      * callback will be called with a boolean as a first parameter, containing
  513.      * TRUE if the given passwordhash did match the password or FALSE otherwise.
  514.      */
  515.     this.checkPassword = function(passhash, cb)
  516.     {
  517.         self._database.query("SELECT COUNT(1) FROM users "
  518.                 +"WHERE id = ? AND password = UNHEX(?) LIMIT 1",
  519.         [self.getId(), passhash],
  520.         function(results)
  521.         {
  522.             if(cb)cb(results.length > 0);
  523.         });
  524.     }
  525.  
  526.     this.toString = function()
  527.     {
  528.         return "[User #"+self.getId()+" "
  529.             +self.getUsername()+"]";
  530.     };
  531.  
  532.     this.toJSON = function()
  533.     {
  534.         return {
  535.             id: self.getId(),
  536.             username: self.getUsername()
  537.         };
  538.     }
  539. }
  540.  
  541. function Product(db, id, title, thumbnail, value, time,
  542.                  bidDurationMinimum,
  543.                  bidDurationDecrementInterval,
  544.                  bidDurationDecrementAmount,
  545.                  bidDurationStart,
  546.                  bidValueIncrement)
  547. {
  548.     var self = this;
  549.    
  550.     this._database = db;
  551.     this._id = id;
  552.     this._thumbnail = thumbnail;
  553.     this._value = value;
  554.     this._title = title;
  555.     this._time = time;
  556.     this._bidDurationMinimum = bidDurationMinimum;
  557.     this._bidDurationDecrementInterval = bidDurationDecrementInterval;
  558.     this._bidDurationDecrementAmount = bidDurationDecrementAmount;
  559.     this._bidDurationStart = bidDurationStart;
  560.     this._bidValueIncrement = bidValueIncrement;
  561.     this._lastBid = undefined;
  562.  
  563.     this._init = function(cb)
  564.     {
  565.         self._database.query("SELECT id FROM bids WHERE product = ? "
  566.             +"ORDER BY centiTime DESC LIMIT 1",
  567.         [self.getId()],
  568.         function(results)
  569.         {
  570.             if(results.length == 0)
  571.             {
  572.                 self._lastBid = null;
  573.                 self._init = undefined;
  574.                 if(cb)cb(self);
  575.                 return;
  576.             }
  577.             db.getBid(results[0].id, function(bid)
  578.             {
  579.                 self._lastBid = bid;
  580.                 self._init = undefined;
  581.                 if(cb)cb(self);
  582.             });
  583.         });
  584.     }
  585.  
  586.     /** @var An array with on-bid-placed-event listeners. */
  587.     this._onBidPlacedEventListeners = [];
  588.  
  589.     /**
  590.      *
  591.      */
  592.     this._triggerOnBidPlacedEventListeners = function(bid)
  593.     {
  594.         for(var i=0; i<self._onBidPlacedEventListeners.length; i++)
  595.             self._onBidPlacedEventListeners[i](bid);
  596.     }
  597.  
  598.     /**
  599.      * Add a on-bid-placed-event-listener. The function will be called everytime
  600.      * a bid is placed on any product. The callback will be given a
  601.      * Bid-object which the bid was placed on as a first parameter.
  602.      * @param cb The event-listener.
  603.      */
  604.     this.addOnBidPlacedEventListener = function(cb)
  605.     {
  606.         self._onBidPlacedEventListeners.add(cb);
  607.     }
  608.  
  609.     this.removeOnBidPlacedEventListener = function(cb)
  610.     {
  611.         self._onBidPlacedEventListeners.remove(cb);
  612.     }
  613.  
  614.     /**
  615.      * Get the id of this product.
  616.      * @type Number
  617.      * @return the id
  618.      */
  619.     this.getId = function()
  620.     {
  621.         return self._id;
  622.     }
  623.  
  624.     this.getTitle = function()
  625.     {
  626.         return self._title;
  627.     }
  628.  
  629.     this.getThumbnail = function()
  630.     {
  631.         return self._thumbnail;
  632.     }
  633.  
  634.     this.getValue = function()
  635.     {
  636.         return self._value;
  637.     }
  638.  
  639.     /**
  640.      * Get the time this Product will start.
  641.      * @type Date
  642.      * @return The time
  643.      */
  644.     this.getStartTime = function()
  645.     {
  646.         return self._time;
  647.     }
  648.  
  649.     this.getLastBid = function()
  650.     {
  651.         return self._lastBid;
  652.     }
  653.  
  654.     this.placeBid = function(time, user, cb)
  655.     {
  656.         var centiTime = (time.getTime() - self.getStartTime().getTime())/10;
  657.         self._database.query(
  658.                 "INSERT INTO bids (product, centiTime, user) VALUES(?,?,?)",
  659.         [self.getId(), centiTime, user.getId()],
  660.         function(results)
  661.         {
  662.             db.getBid(results.insertId, function(bid)
  663.             {
  664.                 if(self._lastBid)
  665.                     self._database.uncacheBid(self._lastBid);
  666.                 self._lastBid = bid;
  667.                 self._triggerOnBidPlacedEventListeners(bid);
  668.                 if(cb)cb(bid);
  669.             });
  670.         });
  671.     }
  672.  
  673.     this.getBidDuration = function()
  674.     {
  675.         return Math.max(self._bidDurationMinimum,
  676.                 self._bidDurationStart
  677.               - self._bidDurationDecrementAmount
  678.                 * Math.floor((new Date().getTime() - self._time.getTime())
  679.                             / (self._bidDurationDecrementInterval*1000)));
  680.     };
  681.  
  682.     this.getBidTimeRemaining = function()
  683.     {
  684.         console.log("getBidDuration: "+self.getBidDuration());
  685.         if(!self._lastBid)
  686.             return self.getBidDuration();
  687.         console.log("getBidTimeRemaining: "+(self.getBidDuration()
  688.                          - ( new Date().getTime()
  689.                            - self._lastBid.getTime().getTime())/1000));
  690.         return Math.max(0, self.getBidDuration()
  691.                          - ( new Date().getTime()
  692.                            - self._lastBid.getTime().getTime())/1000);
  693.     };
  694.  
  695.     this.getBidDurationMinimum = function()
  696.     {
  697.         return self._bidDurationMinimum;
  698.     }
  699.  
  700.     this.getBidDurationDecrementInterval = function()
  701.     {
  702.         return self._bidDurationDecrementInterval;
  703.     }
  704.  
  705.     this.getBidDurationDecrementAmount = function()
  706.     {
  707.         return self._bidDurationDecrementAmount;
  708.     }
  709.  
  710.     this.getBidDurationStart = function()
  711.     {
  712.         return self._bidDurationStart;
  713.     }
  714.  
  715.     this.getBidValueIncrement = function()
  716.     {
  717.         return self._bidValueIncrement;
  718.     }
  719.  
  720.     this.getBidValue = function()
  721.     {
  722.         return self.getLastBid()?self.getLastBid().getValue():0;
  723.     }
  724.  
  725.     this.toString = function()
  726.     {
  727.         return "[Product #"+self.getId()+" "
  728.             +self.getTitle()+" "
  729.             +self.getBidDuration()+"s \u20ac"
  730.             +self.getBidValue().toCurrency()+"]";
  731.     };
  732.  
  733.     this.toJSON = function()
  734.     {
  735.         var bid = self.getLastBid();
  736.         return {
  737.             id: self.getId(),
  738.             title: self.getTitle(),
  739.             time: self.getStartTime().getTime(),
  740.             thumbnail: self.getThumbnail(),
  741.             value: self.getValue(),
  742.             bidDurationMinimum: self.getBidDurationMinimum(),
  743.             bidDurationStart: self.getBidDurationStart(),
  744.             bidDurationDecrementInterval: self.getBidDurationDecrementInterval(),
  745.             bidDurationDecrementAmount: self.getBidDurationDecrementAmount(),
  746.             bidValueIncrement: self.getBidValueIncrement(),
  747.             lastBid: !bid?null:{
  748.                 id: bid.getId(),
  749.                 time: bid.getTime().getTime(),
  750.                 offset: bid.getOffset(),
  751.                 user: bid.getUser().toJSON()
  752.             }
  753.         };
  754.     }
  755. }
  756.  
  757. function Bid(db, id, product, time, user)
  758. {
  759.     var self = this;
  760.    
  761.     this._database = db;
  762.     this._id = id;
  763.     this._product = product;
  764.     this._time = time;
  765.     this._user = user;
  766.     this._offset = undefined;
  767.  
  768.     this._init = function(cb)
  769.     {
  770.         self._database.query("SELECT COUNT(1) AS count FROM bids WHERE "
  771.             +"product = ? AND id < ?",
  772.         [self._product.getId(), self.getId()],
  773.         function(results)
  774.         {
  775.             self._offset = results[0].count+1;
  776.             if(cb)cb(self);
  777.         });
  778.     }
  779.  
  780.     this.getId = function()
  781.     {
  782.         return self._id;
  783.     }
  784.    
  785.     this.getOffset = function()
  786.     {
  787.         return self._offset;
  788.     }
  789.  
  790.     /**
  791.      * Get the time this Bid was placed.
  792.      * @type Date
  793.      * @return The time
  794.      */
  795.     this.getTime = function()
  796.     {
  797.         return self._time;
  798.     }
  799.  
  800.     this.getProduct = function()
  801.     {
  802.         return self._product;
  803.     }
  804.  
  805.     this.getUser = function()
  806.     {
  807.         return self._user;
  808.     }
  809.  
  810.     this.getValue = function()
  811.     {
  812.         return self.getOffset() * self.getProduct().getBidValueIncrement();
  813.     }
  814.  
  815.     this.toString = function()
  816.     {
  817.         return "[Bid #"+self.getId()+" n"
  818.             +self.getOffset()+" \u20ac"
  819.             +self.getValue().toCurrency()+"]";
  820.     };
  821.  
  822.     this.toJSON = function()
  823.     {
  824.         return {
  825.             id: self.getId(),
  826.             time: self.getTime().getTime(),
  827.             user: self.getUser().toJSON(),
  828.             product: self.getProduct().toJSON(),
  829.             offset: self.getOffset()
  830.         };
  831.     }
  832. }
  833.  
  834. function ProductAutoBidBot(product, users)
  835. {
  836.     var self = this;
  837.  
  838.     this._product = product;
  839.     this._users = users;
  840.     this._placeBidTimeout = null;
  841.  
  842.     var placeBidByRandomUser = function()
  843.     {
  844.         var user = self._users.getRandomElement();
  845.         var time = self._product.getLastBid().getTime().getTime()
  846.                  + (self._product.getBidDuration()-1)*1000;
  847.         console.log("AutoBid placed Bid on "+product+" by "+user);
  848.         self._product.placeBid(new Date(time), user);
  849.     }
  850.  
  851.     var bidPlacedListener = function()
  852.     {
  853.         var secs = self._product.getBidTimeRemaining();
  854.         console.log("Scheduling AutoBid on "+product+" in "+secs);
  855.         clearTimeout(self._placeBidTimeout);
  856.         self._placeBidTimeout = setTimeout(placeBidByRandomUser, secs*1000);
  857.     }
  858.    
  859.     this.start = function()
  860.     {
  861.         self._product.addOnBidPlacedEventListener(bidPlacedListener);
  862.         bidPlacedListener();
  863.     }
  864.  
  865.     this.stop = function()
  866.     {
  867.         clearTimeout(self._placeBidTimeout);
  868.         self._product.removeOnBidPlacedEventListener(bidPlacedListener);
  869.     }
  870. }
  871.  
  872. function handleJSONResponse(response)
  873. {
  874.     switch(response.getParam(0))
  875.     {
  876.         case "place-bid":
  877.             var bidProduct = undefined;
  878.             var bidUser = undefined;
  879.             var productAndUserFetchedCallback = function()
  880.             {
  881.                 if(bidProduct === undefined
  882.                 || bidUser === undefined)
  883.                     return;
  884.                 if(!bidUser||!bidProduct)
  885.                 {
  886.                     if(!bidUser)
  887.                         response.addError("Placing a bid requires a login.");
  888.                     if(!bidProduct)
  889.                         response.addError("Product does not exist.");
  890.                     response.end();
  891.                     return;
  892.                 }
  893.                 bidProduct.placeBid(response.getTime(), bidUser,
  894.                 function(bid)
  895.                 {
  896.                     response.set("bid", bid?bid.toJSON():null);
  897.                     response.end();
  898.                 });
  899.             }
  900.             db.getProduct(response.getParam(1), function(product)
  901.             {
  902.                 bidProduct = product;
  903.                 productAndUserFetchedCallback();
  904.             });
  905.             response.validateLogin(function(user)
  906.             {
  907.                 bidUser = user;
  908.                 productAndUserFetchedCallback();
  909.             });
  910.             break;
  911.         case "next-bid-since":
  912.             var sinceBidId = response.getParam(1);
  913.             if(db.getLastBid()
  914.             && db.getLastBid().getId() != sinceBidId)
  915.             {
  916.                 db.getLastBidsPlacedAfterBidId(sinceBidId,
  917.                 function(bids)
  918.                 {
  919.                     var bidData = new Array(bids.length);
  920.                     for(var i=0; i<bidData.length; i++)
  921.                         bidData[i] = bids[i].toJSON();
  922.                     response.set("bids", bidData);
  923.                     response.end();
  924.                 });
  925.             }
  926.             else
  927.             {
  928.                 var rawResponse = null;
  929.                 var onBidPlacedListener = function(bid)
  930.                 {
  931.                     db.removeOnBidPlacedEventListener(onBidPlacedListener);
  932.                     if(!rawResponse)
  933.                     {
  934.                         response.set("bids", [bid]);
  935.                         rawResponse = response.getRawResponse();
  936.                     }
  937.                     response.setRawResponse(rawResponse);
  938.                     response.end();
  939.                 };
  940.                 db.addOnBidPlacedEventListener(onBidPlacedListener);
  941.             }
  942.             break;
  943.         case "active-products":
  944.             db.getProductsStartingBetween(new Date(0), new Date(),
  945.             function(products)
  946.             {
  947.                 var productData = new Array(products.length);
  948.                 for(var i=0; i<productData.length; i++)
  949.                     productData[i] = products[i].toJSON();
  950.                 response.set("activeProducts", productData);
  951.                 response.end();
  952.             });
  953.             break;
  954.         case "product-info":
  955.             db.getProduct(response.getParam(1), function(product)
  956.             {
  957.                 response.set("product", product?product.toJSON():null);
  958.                 response.end();
  959.             });
  960.             break;
  961.         case "bid-info":
  962.             db.getBid(response.getParam(1), function(bid)
  963.             {
  964.                 response.set("bid", bid?bid.toJSON():null);
  965.                 response.end();
  966.             });
  967.             break;
  968.         case "user-info":
  969.             db.getUser(response.getParam(1), function(user)
  970.             {
  971.                 response.set("user", user?user.toJSON():null);
  972.                 response.end();
  973.             });
  974.             break;
  975.         case "time":
  976.             response.set("time", response.getTime().getTime());
  977.             response.end();
  978.             break;
  979.         default:
  980.             response.addError("Unknown Command");
  981.             response.end();
  982.     }
  983. }
  984.  
  985.  
  986. var client = mysql.Client();
  987. client.host = settings.sqlHost;
  988. client.user = settings.sqlUser;
  989. client.password = settings.sqlPass;
  990. client.database = settings.sqlDatabase;
  991.  
  992. client.connect();
  993.  
  994. var db = new Database(client);
  995.  
  996. (function()
  997. {
  998.     var botUsers = new Array();
  999.     var botsLoadedCallbacks = new Array();
  1000.  
  1001.     db.addProductLoadedEventListener(function(product)
  1002.     {
  1003.         var botUsersReadyCallback = function()
  1004.         {
  1005.             var bot = new ProductAutoBidBot(product, botUsers);
  1006.             bot.start();
  1007.         }
  1008.         if(botsLoadedCallbacks !== null)
  1009.             botsLoadedCallbacks.push(botUsersReadyCallback);
  1010.         else
  1011.             botUsersReadyCallback();
  1012.     });
  1013.     db._init(function(db)
  1014.     {
  1015.         var botUserIds = [11, 12];
  1016.         var botsLoadedCallback = function()
  1017.         {
  1018.             if(botUsers.length < botUserIds.length)
  1019.                 return;
  1020.             for(var i=0; i<botsLoadedCallbacks.length; i++)
  1021.                 botsLoadedCallbacks[i]();
  1022.         }
  1023.         for(var i=0; i<botUserIds.length; i++)
  1024.             db.getUser(botUserIds[i], function(user)
  1025.             {
  1026.                 botUsers.push(user);
  1027.                 botsLoadedCallback();
  1028.             });
  1029.         http.createServer(function(request, response)
  1030.         {
  1031.             var jsonresponse = new JSONResponse(db, request, response);
  1032.             handleJSONResponse(jsonresponse);
  1033.         }).listen(settings.httpPort);
  1034.     });
  1035. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement