PageRenderTime 57ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/Connectors/foursquare/client.js

https://github.com/arfrank/Locker
JavaScript | 272 lines | 244 code | 21 blank | 7 comment | 26 complexity | 850d676fc4e49814a46c2218fd8de7ba MD5 | raw file
  1. /**
  2. * Module dependencies.
  3. */
  4. var fs = require('fs');
  5. var express = require('express'),
  6. connect = require('connect'),
  7. url = require('url'),
  8. sys = require('sys'),
  9. app = express.createServer(
  10. connect.bodyDecoder(),
  11. connect.cookieDecoder(),
  12. connect.session({secret : "locker"})
  13. ),
  14. http = require('http'),
  15. https = require("https"),
  16. wwwdude = require('wwwdude'),
  17. locker = require('../../Common/node/locker.js'),
  18. lfs = require('../../Common/node/lfs.js');
  19. var lockerInfo;
  20. var me;
  21. var accessData;
  22. var wwwdude_client = wwwdude.createClient({
  23. encoding: 'binary'
  24. });
  25. Array.prototype.addAll = function(anotherArray) {
  26. if(!anotherArray || !anotherArray.length)
  27. return;
  28. for(var i = 0; i < anotherArray.length; i++)
  29. this.push(anotherArray[i]);
  30. }
  31. //app.set('views', __dirname);
  32. app.get('/',
  33. function(req, res) {
  34. res.writeHead(200, {
  35. 'Content-Type': 'text/html'
  36. });
  37. if(!accessData.accessToken)
  38. res.end("<html>you need to <a href='go4sq'>auth w/ foursquare</a> yet</html>");
  39. else
  40. res.end("<html>found a token, load <a href='friends'>friends</a> or <a href='checkins'>checkins</a></html>");
  41. });
  42. var oaTokenSecret = "";
  43. app.get('/go4sq',
  44. function(req, res) {
  45. if(!(accessData.appKey && accessData.appSecret)) {
  46. res.writeHead(200, { 'Content-Type': 'text/html' });
  47. res.end("<html>Enter your personal Twitter app info that will be used to sync your data" +
  48. " (create a new one <a href='https://foursquare.com/oauth/register'>" +
  49. "here</a> using the callback url of " +
  50. me.uri+"auth) " +
  51. "<form method='get' action='save'>" +
  52. "Client ID: <input name='appKey'><br>" +
  53. "Client Secret: <input name='appSecret'><br>" +
  54. "<input type='submit' value='Save'>" +
  55. "</form></html>");
  56. } else {
  57. res.writeHead(302);
  58. sys.debug('redirecting to ' + me.uri + 'auth');
  59. res.redirect('https://foursquare.com/oauth2/authenticate?client_id=' + accessData.appKey + '&response_type=code&redirect_uri=' + me.uri + 'auth');
  60. res.end();
  61. }
  62. });
  63. function get(host, url, callback) {
  64. var httpClient = http.createClient(443, host, true);
  65. var httpOpts = {
  66. "host" : host,
  67. port : 443,
  68. path: url,
  69. method: "GET"
  70. };
  71. var request = https.request(httpOpts, function(res) {
  72. var data = '';
  73. res.on('data', function(chunk) {
  74. data += chunk;
  75. });
  76. res.on('end', function() {
  77. callback(data);
  78. });
  79. });
  80. request.end();
  81. }
  82. app.get('/auth',
  83. function(req, res) {
  84. res.writeHead(200, {
  85. 'Content-Type': 'text/html'
  86. });
  87. var url = '/oauth2/access_token' +
  88. '?client_id=' + accessData.appKey +
  89. '&client_secret=' + accessData.appSecret +
  90. '&grant_type=authorization_code' +
  91. '&redirect_uri=' + me.uri + 'auth' +
  92. '&code=' + req.param('code');
  93. get('foursquare.com', url, function(data) {
  94. console.log("Got " + data);
  95. var responseObject = JSON.parse(data);
  96. accessData.accessToken = responseObject.access_token;
  97. lfs.writeObjectsToFile("access.json", [accessData]);
  98. res.end("<html>too legit to quit: " + responseObject.access_token + " so now <a href='/friends'>load friends</a>or <a href='checkins'>checkins</a></html>");
  99. });
  100. });
  101. app.get('/save',
  102. function(req, res) {
  103. res.writeHead(200, {
  104. 'Content-Type': 'text/html'
  105. });
  106. if(!req.param('appKey') || !req.param('appSecret')) {
  107. res.end("missing field(s)?");
  108. return;
  109. }
  110. accessData.appKey = req.param('appKey');
  111. accessData.appSecret = req.param('appSecret');
  112. lfs.writeObjectsToFile("access.json", [accessData]);
  113. res.end("<html>thanks, now we need to <a href='./go4sq'>auth that app to your account</a>.</html>");
  114. });
  115. app.get('/friends',
  116. function(req, res) {
  117. res.writeHead(200, {
  118. 'Content-Type': 'text/html'
  119. });
  120. getMe(accessData.accessToken, function(data) {
  121. var self = JSON.parse(data).response.user;
  122. me.user_info = self;
  123. lfs.syncMeData(me);
  124. res.write('for user ' + self.firstName + ' with id ' + self.id + ': <br>');
  125. var userID = self.id;
  126. fs.mkdir('photos', 0755);
  127. get('api.foursquare.com', '/v2/users/self/friends.json?oauth_token=' + accessData.accessToken, function(data) {
  128. var friends = JSON.parse(data).response.friends.items;
  129. var queue = [];
  130. var users = {
  131. 'id': userID,
  132. 'queue': queue,
  133. 'token': accessData.accessToken
  134. };
  135. for (var i = 0; i < friends.length; i++) {
  136. res.write(friends[i].firstName + " " + friends[i].lastName + "<br>");
  137. queue.push(friends[i]);
  138. }
  139. locker.at('friends', 3600);
  140. res.end();
  141. downloadNextUser(users);
  142. });
  143. });
  144. });
  145. app.get('/getfriends',
  146. function(req, res) {
  147. res.writeHead(200, {
  148. 'Content-Type': 'text/plain'
  149. });
  150. fs.readFile("friends.json", "binary", function(err, file) {
  151. if(err) {
  152. res.end();
  153. return;
  154. }
  155. res.write(file, "binary");
  156. res.end();
  157. });
  158. });
  159. app.get('/checkins',
  160. function(req, res) {
  161. getMe(accessData.accessToken, function(data) {
  162. var self = JSON.parse(data).response.user;
  163. me.user_info = self;
  164. lfs.syncMeData(me);
  165. getCheckins(me.user_info.id, accessData.accessToken, 0, function(newCheckins) {
  166. lfs.appendObjectsToFile('places.json', newCheckins);
  167. locker.at('checkins', 600);
  168. res.writeHead(200, {
  169. 'Content-Type': 'text/html'
  170. });
  171. res.end();
  172. });
  173. });
  174. })
  175. function getMe(token, callback) {
  176. get('api.foursquare.com', '/v2/users/self.json?oauth_token=' + token, callback);
  177. }
  178. var checkins_limit = 500;
  179. function getCheckins(userID, token, offset, callback, checkins) {
  180. if(!checkins)
  181. checkins = [];
  182. var latest = '';
  183. if(me.checkins && me.checkins.latest)
  184. latest = '&afterTimestamp=' + me.checkins.latest;
  185. else if(!me.checkins)
  186. me.checkins = {};
  187. get('api.foursquare.com', '/v2/users/self/checkins.json?limit=' + checkins_limit + '&offset=' + offset + '&oauth_token=' + token + latest,
  188. function(data) {
  189. var newCheckins = JSON.parse(data).response.checkins.items;
  190. checkins.addAll(newCheckins);
  191. if(newCheckins && newCheckins.length == checkins_limit)
  192. getCheckins(userID, token, offset + checkins_limit, callback, checkins);
  193. else {
  194. if(checkins[0]) {
  195. me.checkins.latest = checkins[0].createdAt;
  196. lfs.syncMeData(me);
  197. }
  198. callback(checkins.reverse());
  199. }
  200. });
  201. }
  202. function downloadNextUser(users) {
  203. if (users.queue.length == 0)
  204. return;
  205. var friend = users.queue.pop();
  206. // get extra juicy contact info plz
  207. get('api.foursquare.com', '/v2/users/' + friend.id + '.json?oauth_token=' + users.token,
  208. function(data) {
  209. var js = JSON.parse(data).response.user;
  210. js.name = js.firstName + " " + js.lastName;
  211. lfs.appendObjectsToFile('friends.json', [js]);
  212. if (friend.photo.indexOf("userpix") < 0)
  213. return downloadNextUser(users);
  214. // fetch photo
  215. wwwdude_client.get(friend.photo)
  216. .addListener('error',
  217. function(err) {
  218. sys.debug(err);
  219. downloadNextUser(users);
  220. })
  221. .addListener('http-error',
  222. function(data, resp) {
  223. sys.debug('HTTP Error for: ' + resp.host + ' code: ' + resp.statusCode);
  224. downloadNextUser(users);
  225. })
  226. .addListener('success',
  227. function(data, resp) {
  228. fs.writeFileSync('photos/' + friend.id + '.jpg', data, 'binary');
  229. downloadNextUser(users);
  230. });
  231. });
  232. }
  233. // Process the startup JSON object
  234. process.stdin.resume();
  235. process.stdin.on("data", function(data) {
  236. lockerInfo = JSON.parse(data);
  237. if (!lockerInfo || !lockerInfo["workingDirectory"]) {
  238. process.stderr.write("Was not passed valid startup information."+data+"\n");
  239. process.exit(1);
  240. }
  241. process.chdir(lockerInfo.workingDirectory);
  242. me = lfs.loadMeData();
  243. try {
  244. accessData = JSON.parse(fs.readFileSync("access.json", "utf8"));
  245. } catch (E) {
  246. accessData = {};
  247. }
  248. app.listen(lockerInfo.port, "localhost", function() {
  249. process.stdout.write(data);
  250. });
  251. });