-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
201 lines (169 loc) · 5.94 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
var express = require('express')
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var sockets = [];
var request = require('request');
var fs = require('fs');
var endpoint = 'https://micropurchase.18f.gov/auctions/';
var refresh = 10;
var notToExceed = 500;
var configFile = './config.json';
var config = require(configFile);
var auctionID = config.auctionID;
var userID = config.userID;
var authToken = config.authToken;
log('Hello!');
// Due to an API change, we have to keep the current bid in memory.
// On init, we shoot for the stars! We also have some code below
// to store that last value in case we need to reboot this thing.
var lastBidFile = "./lastBid.json";
var currentBid = require(lastBidFile);
currentBid = (currentBid.bid === undefined) ? Infinity : currentBid.bid;
log('Setting currentBid to $' + currentBid);
app.use(express.static('public'));
server.listen(1337);
io.on('connection', function(socket) {
log('A wild client appears!');
socket.on('disconnect', function(){
var index = sockets.indexOf(socket);
sockets.splice(index, 1);
log('Client has died. Sorry for your loss. ' + sockets.length + ' left.');
});
sockets.push(socket);
});
function timeStamp() {
// https://gist.github.com/hurjas/2660489
var now = new Date();
var date = [ now.getMonth() + 1, now.getDate(), now.getFullYear() ];
var time = [ now.getHours(), now.getMinutes(), now.getSeconds() ];
var suffix = ( time[0] < 12 ) ? "AM" : "PM";
time[0] = ( time[0] < 12 ) ? time[0] : time[0] - 12;
time[0] = time[0] || 12;
for ( var i = 1; i < 3; i++ ) {
if ( time[i] < 10 ) {
time[i] = "0" + time[i];
}
}
return date.join("/") + " " + time.join(":") + " " + suffix;
}
function log(msg) {
console.log(timeStamp() + " | " + msg);
}
function getAuction(callback) {
var options = {
url: endpoint + auctionID,
headers: {
'Accept': 'text/x-json',
'Content-Type': 'application/json',
'Api-Key': authToken,
}
};
request(options, function(error, response, body) {
if (error) return callback(error);
callback(null, JSON.parse(body));
});
}
function bidAuction(bid, callback) {
if (bid >= notToExceed) {
log('Bidding $' + bid + '...');
var options = {
url: endpoint + auctionID + '/bids',
headers: {
'Accept': 'text/x-json',
'Content-Type': 'application/json',
'Api-Key': authToken,
},
body: '{"bid": {"amount": ' + bid + '}}'
};
request.post(options, function(error, response, body) {
if (error) log(error);
callback(null, JSON.parse(body));
});
}
else {
var msg = 'Bid is below the minimum of $' + notToExceed + '.';
log(msg);
callback(true, { error: msg });
}
}
function eachSocket(handle, payload) {
for(i = 0; i < sockets.length; i++) {
sockets[i].emit(handle, payload);
}
}
function setCurrentBid(bid) {
fs.writeFile(lastBidFile, JSON.stringify({ bid: bid }), function(err) {
if (err) { log('Error while saving!' + err); }
log('Setting currentBid to $' + bid);
currentBid = bid;
});
}
var counter = refresh;
setInterval( function() {
eachSocket('tick', counter--);
if (counter === 0) {
counter = refresh;
getAuction( function(err, res){
if (err) { eachSocket('error', { payload: err }); }
else {
// If user is the current winning bid.
// Due to an API change, we no longer can count on winning_bid...
// So since we are using auth on the GET for auctions, we get to
// see our data in the bid objects. Now we just check to see
// if the last bid has our data in it. #WINNING
// **NOTE:** You may need to bootstrap the current bid data if you
// are already the winning bidder and *then* fire this up. If you
// don't, you'll just wind up undercutting yourself for that first
// iteration of the loop. What a sucker.
if ((res.auction.bids[0].bidder_id !== null ||
res.auction.bids[0].bidder_id !== undefined) &&
res.auction.bids[0].bidder_id === userID) {
log('Currently winning with $' + currentBid);
eachSocket('status', {
payload: {
auction: res.auction,
winning: true
}
});
}
// If userID is no longer the current winning bid, we fire off
// a winning:false message to any clients that are connected.
else {
log('Uh oh. You are no longer the winner. ;(');
eachSocket('status', {
payload: {
auction: res.auction,
winning: false
}
});
// Here, we bid on the auction for one dollar less than the winning
// amount. Due to an API change, we cannot rely on the winning_bid
// amount (BOO!), so we first check to see if it is there (YAY!)
// and if not (DOUBLE BOO!), we go to what the last bid was on the
// auction and decrement that amount by 1 BIGONE.
// **NOTE**: Just like noted above, if you are currently the winner
// and *then* go to fire this up, you will just bid against yourself
// and bring shame upon your family. We do not have bidder information
// other than ourselves until *after* the auction is over.
var bid = (res.auction.winning_bid !== undefined) ?
res.auction.winning_bid.amount - 1 :
res.auction.bids[0].amount - 1;
bidAuction(bid, function(err, res) {
if (err) { eachSocket('error', { payload: err }); }
else {
log('Winning with $' + bid);
setCurrentBid(bid);
eachSocket('status', {
payload: {
auction: res.auction,
winning: true
}
});
}
});
}
}
});
}
}, 1000);