Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- var sha1 = require("./sha1").hex;
- var http = require("http");
- var mysql = require('./mysql');
- var settings = require("./settings");
- if(Array.prototype.clear === undefined)
- Array.prototype.clear = function()
- {
- for(var i=this.length; i>=0; i--)
- delete this[i];
- this.length = 0;
- return this;
- }
- if(Array.prototype.contains === undefined)
- Array.prototype.contains = function(element)
- {
- return this.indexOf(element)!=-1;
- }
- if(Array.prototype.add === undefined)
- Array.prototype.add = function(element)
- {
- if(!this.contains(element))
- this.push(element);
- }
- if(Array.prototype.remove === undefined)
- Array.prototype.remove = function(value)
- {
- for(var i=0; i<this.length; i++)
- if(this[i] === value)
- this.splice(i--, 1);
- return this;
- }
- if(Array.prototype.clean === undefined)
- Array.prototype.clean = function()
- {
- for(var i=0; i<this.length; i++)
- if(this[i] === undefined
- || this[i] === null)
- this.splice(i--, 1);
- return this;
- }
- if(Array.prototype.clear === undefined)
- Array.prototype.clear = function()
- {
- for(var i=this.length; i>=0; i--)
- delete this[i];
- this.length = 0;
- return this;
- }
- function JSONResponse(database, request, response)
- {
- var self = this;
- this._user = undefined;
- this._database = database;
- this._request = request;
- this._response = response;
- this._JSONObject = {};
- this._time = new Date();
- this._cookie = {};
- var rawcookie = request.headers.cookie
- ?request.headers.cookie.split(/;\s*/)
- :[];
- for(var i=0; i<rawcookie.length; i++)
- {
- rawcookie[i] = rawcookie[i].split("=");
- this._cookie[rawcookie[i][0]] = unescape(rawcookie[i][1]);
- }
- this._params = request.url.substr(1).split("/");
- console.log(this._params);
- response.writeHead(200,{"Content-Type": "application/json"});
- this.getTime = function()
- {
- return self._time;
- }
- this.getCookie = function(key)
- {
- return self._cookie[key];
- }
- /**
- * Get the currently logged in user. Calls the callback method with the user
- * that is logged in, or with NULL if there is no login.
- * @param cb The callback function.
- */
- this.validateLogin = function(cb)
- {
- if(this._user !== undefined)
- {
- cb(self._user);
- return;
- }
- if(!self.getCookie("login"))
- {
- self._user = null;
- cb(self._user);
- return;
- }
- var loginstr = self.getCookie("login").split(",");
- var userId = parseInt(loginstr[0]);
- var passHash = loginstr[1];
- self._database.getUser(userId, function(user)
- {
- user.checkPassword(passHash, function(isValid)
- {
- self._user = isValid?user:null;
- cb(self._user);
- });
- });
- }
- this.addError = function(message)
- {
- if(!(self._JSONObject.errors instanceof Array))
- self._JSONObject.errors = new Array();
- self._JSONObject.errors.push(message);
- }
- this.getParam = function(i)
- {
- return self._params[i];
- }
- this.getParams = function()
- {
- return self._params;
- }
- this.getUser = function()
- {
- return self._user;
- }
- this.set = function(key, value)
- {
- self._JSONObject[key] = value;
- }
- this.get = function(key)
- {
- return self._JSONObject[key];
- }
- this.end = function()
- {
- self._response.end(JSON.stringify(self._JSONObject, null, 2));
- }
- }
- function Database(sqlClient)
- {
- var self = this;
- /** @var The MySQL Client connection. */
- this._sql = sqlClient;
- /** @var A cache with Product-objects. */
- this._products = {};
- /** @var A cache with User-objects. */
- this._users = {};
- /** @var A cache with Bid-objects. */
- this._bids = {};
- /** @var A reference to the last bid. */
- this._lastBid = undefined;
- this._init = function(cb)
- {
- self.query("SELECT id FROM bids ORDER BY id DESC LIMIT 1",
- [],
- function(results)
- {
- if(!results.length)
- {
- self._lastBid = null;
- self._init = undefined;
- if(cb)cb(self);
- return;
- }
- self.getBid(results[0].id, function(bid)
- {
- self._lastBid = bid;
- self.addOnBidPlacedEventListener(function(bid)
- {
- self._lastBid = bid;
- });
- self._init = undefined;
- if(cb)cb(self);
- return;
- });
- });
- }
- /** @var An array with on-bid-placed-event listeners. */
- this._onBidPlacedEventListeners = [];
- /**
- *
- */
- this._triggerOnBidPlacedEventListeners = function(bid)
- {
- for(var i=0; i<self._onBidPlacedEventListeners.length; i++)
- self._onBidPlacedEventListeners[i](bid);
- }
- /**
- * Add a on-bid-placed-event-listener. The function will be called everytime
- * a bid is placed on any product. The callback will be given a
- * Bid-object which the bid was placed on as a first parameter.
- * @param cb The event-listener.
- */
- this.addOnBidPlacedEventListener = function(cb)
- {
- self._onBidPlacedEventListeners.add(cb);
- }
- this.removeOnBidPlacedEventListener = function(cb)
- {
- self._onBidPlacedEventListeners.remove(cb);
- }
- this.query = function(sql, params, cb)
- {
- self._sql.query(sql, params, function(err, results)
- {
- if(err)
- {
- console.log("ERROR EXECUTING QUERY:");
- console.log(sql);
- console.log(self._sql);
- throw err;
- }
- if(cb)cb(results);
- });
- }
- this.getLastBid = function()
- {
- return self._lastBid;
- }
- this.getProductsStartingBetween = function(start, end, cb)
- {
- self.query("SELECT id FROM products WHERE UNIX_TIMESTAMP(timeStart) "
- +"BETWEEN ? AND ?",
- [start.getTime()/1000, end.getTime()/1000],
- function(results)
- {
- var products = new Array();
- var productsLoadedCallback = function()
- {
- if(products.length < results.length)
- return;
- if(cb)cb(products);
- }
- for(var i=0; i<results.length; i++)
- {
- self.getProduct(results[i].id, function(product)
- {
- products.push(product);
- productsLoadedCallback();
- });
- }
- });
- }
- this.getLastBidsPlacedAfterBid = function(bid, cb)
- {
- self.query("SELECT id FROM bids WHERE id > ? "
- +"GROUP BY product ORDER BY id",
- [bid?bid.getId():0],
- function(results)
- {
- var bids = new Array();
- var bidsLoadedCallback = function()
- {
- if(bids.length < results.length)
- return;
- if(cb)cb(bids);
- }
- for(var i=0; i<results.length; i++)
- {
- self.getBid(results[i].id, function(bid)
- {
- bids.push(bid);
- bidsLoadedCallback();
- });
- }
- });
- }
- this.getLastBidsPlacedBetween = function(start, end, cb)
- {
- self.query("SELECT bid.id AS id FROM bids AS bid "
- +"JOIN products AS product ON bid.product = product.id "
- +"WHERE UNIX_TIMESTAMP(product.timeStart)+bid.centiTime/100 "
- +"BETWEEN ? AND ? GROUP BY product.id ORDER BY "
- +"bid.id DESC",
- [start.getTime()/1000, end.getTime()/1000],
- function(results)
- {
- var bids = new Array();
- var bidsLoadedCallback = function()
- {
- if(bids.length < results.length)
- return;
- if(cb)cb(bids);
- }
- for(var i=0; i<results.length; i++)
- {
- self.getBid(results[i].id, function(bid)
- {
- bids.push(bid);
- bidsLoadedCallback();
- });
- }
- });
- }
- /**
- * Get a product from this database. Calls a callback method with the
- * retrieved Product-object on completion, or with NULL if the Product
- * doesn't exist.
- * @param id The id of the product to get.
- * @param cb The callback.
- */
- this.getProduct = function(id, cb)
- {
- id = parseInt(id);
- if(self._products[id] !== undefined)
- {
- if(cb)cb(self._products[id]);
- return;
- }
- self.query("SELECT title, UNIX_TIMESTAMP(timeStart) AS time, thumbnail,"
- +"value/100 AS value FROM products WHERE id = ? LIMIT 1",
- [id],
- function(results)
- {
- if(self._products[id])
- {
- console.log("Tried to reload Product #"+id+".");
- if(cb)cb(self._products[id]);
- return;
- }
- if(results.length == 0)
- {
- console.log("Loaded Product #"+id+": NULL");
- self._products[id] = null;
- if(cb)cb(self._products[id]);
- return;
- }
- self._products[id] = new Product(self, id,
- results[0].title,
- results[0].thumbnail,
- results[0].value,
- new Date(results[0].time*1000));
- self._products[id].addOnBidPlacedEventListener(
- self._triggerOnBidPlacedEventListeners);
- self._products[id]._init(function(product)
- {
- console.log("Loaded Product #"+id+": "
- +JSON.stringify(product.getTitle()));
- if(cb)cb(product);
- });
- });
- }
- /**
- * Get a user from this database. Calls a callback method with the retrieved
- * User-object on completion, or with NULL if there is no user with that id.
- * @param id The id of the user.
- * @param cb The callback.
- */
- this.getUser = function(id, cb)
- {
- id = parseInt(id);
- if(self._users[id] !== undefined)
- {
- if(cb)cb(self._users[id]);
- return;
- }
- self.query("SELECT username FROM users WHERE id = ? LIMIT 1",
- [id],
- function(results)
- {
- if(self._users[id])
- {
- console.log("Tried to reload User #"+id+".");
- if(cb)cb(self._users[id]);
- return;
- }
- self._users[id] = results.length == 0
- ?null
- :new User(self, id, results[0].username);
- console.log("Loaded User #"+id+": "
- +(self._users[id]
- ?JSON.stringify(self._users[id].getUsername())
- :"NULL"));
- if(cb)cb(self._users[id]);
- });
- }
- /**
- * Get a bid from this database. Calls a callback method with the retrieved
- * Bid-object on completion, or with NULL if there is no bid with that id.
- * @param id The id of the bid.
- * @param cb The callback.
- */
- this.getBid = function(id, cb)
- {
- id = parseInt(id);
- if(self._bids[id] !== undefined)
- {
- cb(self._bids[id]);
- return;
- }
- self.query("SELECT id, product, centiTime, user "
- +"FROM bids WHERE id = ? LIMIT 1",
- [id],
- function(results)
- {
- if(results.length == 0)
- {
- console.log("Loaded Bid #"+id+": NULL");
- self._bids[id] = null;
- if(cb)cb(self._bids[id]);
- return;
- }
- var bidUser = undefined;
- var bidProduct = undefined;
- var bidAdditionalDataCallback = function()
- {
- if(bidUser === undefined
- || bidProduct === undefined)
- return;
- if(self._bids[id])
- {
- console.log("Tried to reload Bid #"+id+".");
- if(cb)cb(self._bids[id]);
- return;
- }
- var time = new Date( bidProduct.getStartTime().getTime()
- + results[0].centiTime*10);
- self._bids[id] = new Bid(self, id, bidProduct,
- new Date(time), bidUser);
- console.log("Loaded Bid #"+id+": Bid #? on "
- +JSON.stringify(bidProduct.getTitle()));
- if(cb)cb(self._bids[id]);
- }
- self.getUser(results[0].user, function(user)
- {
- bidUser = user;
- bidAdditionalDataCallback();
- });
- self.getProduct(results[0].product, function(product)
- {
- bidProduct = product;
- bidAdditionalDataCallback();
- });
- });
- }
- }
- function User(db, id, username)
- {
- var self = this;
- this._database = db;
- this._id = id;
- this._username = username;
- this.getId = function()
- {
- return self._id;
- }
- this.getUsername = function()
- {
- return self._username;
- }
- /**
- * Check a user's password. Calls a callback after checking is done. The
- * callback will be called with a boolean as a first parameter, containing
- * TRUE if the given passwordhash did match the password or FALSE otherwise.
- */
- this.checkPassword = function(passhash, cb)
- {
- self._database.query("SELECT COUNT(1) FROM users "
- +"WHERE id = ? AND password = UNHEX(?) LIMIT 1",
- [self.getId(), passhash],
- function(results)
- {
- if(cb)cb(results.length > 0);
- });
- }
- this.toJSON = function()
- {
- return {
- id: self.getId(),
- username: self.getUsername()
- };
- }
- }
- function Product(db, id, title, thumbnail, value, time)
- {
- var self = this;
- this._database = db;
- this._id = id;
- this._thumbnail = thumbnail;
- this._value = value;
- this._title = title;
- this._time = time;
- this._lastBid = undefined;
- this._init = function(cb)
- {
- self._database.query("SELECT id FROM bids WHERE product = ? "
- +"ORDER BY centiTime DESC LIMIT 1",
- [self.getId()],
- function(results)
- {
- if(results.length == 0)
- {
- self._lastBid = null;
- self._init = undefined;
- if(cb)cb(self);
- return;
- }
- db.getBid(results[0].id, function(bid)
- {
- self._lastBid = bid;
- self._init = undefined;
- if(cb)cb(self);
- });
- });
- }
- /** @var An array with on-bid-placed-event listeners. */
- this._onBidPlacedEventListeners = [];
- /**
- *
- */
- this._triggerOnBidPlacedEventListeners = function(bid)
- {
- for(var i=0; i<self._onBidPlacedEventListeners.length; i++)
- self._onBidPlacedEventListeners[i](bid);
- }
- /**
- * Add a on-bid-placed-event-listener. The function will be called everytime
- * a bid is placed on any product. The callback will be given a
- * Bid-object which the bid was placed on as a first parameter.
- * @param cb The event-listener.
- */
- this.addOnBidPlacedEventListener = function(cb)
- {
- self._onBidPlacedEventListeners.add(cb);
- }
- this.removeOnBidPlacedEventListener = function(cb)
- {
- self._onBidPlacedEventListeners.remove(cb);
- }
- /**
- * Get the id of this product.
- * @type Number
- * @return the id
- */
- this.getId = function()
- {
- return self._id;
- }
- this.getTitle = function()
- {
- return self._title;
- }
- this.getThumbnail = function()
- {
- return self._thumbnail;
- }
- this.getValue = function()
- {
- return self._value;
- }
- /**
- * Get the time this Product will start.
- * @type Date
- * @return The time
- */
- this.getStartTime = function()
- {
- return self._time;
- }
- this.getLastBid = function()
- {
- return self._lastBid;
- }
- this.placeBid = function(time, user, cb)
- {
- var centiTime = (time.getTime() - self.getStartTime().getTime())/10;
- self._database.query(
- "INSERT INTO bids (product, centiTime, user) VALUES(?,?,?)",
- [self.getId(), centiTime, user.getId()],
- function(results)
- {
- db.getBid(results.insertId, function(bid)
- {
- self._lastBid = bid;
- self._triggerOnBidPlacedEventListeners(bid);
- if(cb)cb(bid);
- });
- });
- }
- this.toJSON = function()
- {
- var bid = self.getLastBid();
- return {
- id: self.getId(),
- title: self.getTitle(),
- time: self.getStartTime().getTime(),
- thumbnail: self.getThumbnail(),
- value: self.getValue(),
- lastBid: !bid?null:{
- id: bid.getId(),
- time: bid.getTime().getTime(),
- user: {
- id: bid.getUser().getId(),
- username: bid.getUser().getUsername()
- }
- }
- };
- }
- }
- function Bid(db, id, product, time, user)
- {
- var self = this;
- this._database = db;
- this._id = id;
- this._product = product;
- this._time = time;
- this._user = user;
- this.getId = function()
- {
- return self._id;
- }
- /**
- * Get the time this Bid was placed.
- * @type Date
- * @return The time
- */
- this.getTime = function()
- {
- return self._time;
- }
- this.getProduct = function()
- {
- return self._product;
- }
- this.getUser = function()
- {
- return self._user;
- }
- this.toJSON = function()
- {
- return {
- id: self.getId(),
- time: self.getTime().getTime(),
- user: self.getUser().toJSON(),
- product: self.getProduct().toJSON()
- };
- }
- }
- function handleJSONResponse(response)
- {
- switch(response.getParam(0))
- {
- case "place-bid":
- var bidProduct = undefined;
- var bidUser = undefined;
- var productAndUserFetchedCallback = function()
- {
- if(bidProduct === undefined
- || bidUser === undefined)
- return;
- if(!bidUser||!bidProduct)
- {
- if(!bidUser)
- response.addError("Placing a bid requires a login.");
- if(!bidProduct)
- response.addError("Product does not exist.");
- response.end();
- return;
- }
- bidProduct.placeBid(response.getTime(), bidUser,
- function(bid)
- {
- response.set("bid", bid?bid.toJSON():null);
- response.end();
- });
- }
- db.getProduct(response.getParam(1), function(product)
- {
- bidProduct = product;
- productAndUserFetchedCallback();
- });
- response.validateLogin(function(user)
- {
- bidUser = user;
- productAndUserFetchedCallback();
- });
- break;
- case "next-bid-since":
- db.getBid(parseInt(response.getParam(1)), function(sinceBid)
- {
- if(sinceBid != db.getLastBid())
- {
- db.getLastBidsPlacedAfterBid(sinceBid,
- function(bids)
- {
- var bidData = new Array(bids.length);
- for(var i=0; i<bidData.length; i++)
- bidData[i] = bids[i].toJSON();
- response.set("bids", bidData);
- response.end();
- });
- }
- else
- {
- db.addOnBidPlacedEventListener(function(bid)
- {
- response.set("bids", [bid]);
- response.end();
- });
- }
- });
- break;
- case "active-products":
- db.getProductsStartingBetween(new Date(0), new Date(), function(products)
- {
- var productData = new Array(products.length);
- for(var i=0; i<productData.length; i++)
- productData[i] = products[i].toJSON();
- response.set("active-products", productData);
- response.end();
- });
- break;
- case "product-info":
- db.getProduct(response.getParam(1), function(product)
- {
- var bid = product.getLastBid();
- response.set("product", product?product.toJSON():null);
- response.end();
- });
- break;
- case "time":
- response.set("time", response.getTime().getTime());
- response.end();
- break;
- default:
- response.addError("Unknown Command");
- response.end();
- }
- }
- var client = mysql.Client();
- client.host = settings.sqlHost;
- client.user = settings.sqlUser;
- client.password = settings.sqlPass;
- client.database = settings.sqlDatabase;
- client.connect();
- var db = new Database(client);
- db._init(function(db)
- {
- http.createServer(function(request, response)
- {
- var jsonresponse = new JSONResponse(db, request, response);
- handleJSONResponse(jsonresponse);
- }).listen(settings.httpPort);
- });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement