stats.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. (function(){
  2. "use strict";
  3. var WSController = function(endpoint){
  4. this.endpoint = endpoint;
  5. this.initWebSocket();
  6. this.stats = {
  7. 'live': [],
  8. 'lifetime': {},
  9. 'global': [0, 0],
  10. 'project': {},
  11. 'currentScanRate': 0
  12. };
  13. this.reconnectTimer = null;
  14. this.scanRateBucket = [];
  15. this.prevScanBucketIndex = 0;
  16. this.updateInterval = 500;
  17. for (var i = 0; i < 60; i++) {
  18. this.scanRateBucket.push(0);
  19. }
  20. };
  21. WSController.prototype.initWebSocket = function () {
  22. var scheme = window.location.protocol == "https:" ? "wss://" : "ws://";
  23. this.ws = new WebSocket("" + scheme + window.location.host + this.endpoint);
  24. this.ws.onmessage = this._onmessage.bind(this);
  25. this.ws.onopen = this.onConnect.bind(this);
  26. this.ws.onerror = this.onDisconnect.bind(this);
  27. this.ws.onclose = this.onDisconnect.bind(this);
  28. }
  29. WSController.prototype._onmessage = function(evt){
  30. var message = JSON.parse(evt.data);
  31. if(message.live){
  32. this.stats.live = message.live;
  33. }
  34. if(message.lifetime){
  35. this.stats.lifetime = message.lifetime;
  36. }
  37. if(message.global){
  38. this.stats.global = message.global;
  39. }
  40. if(message.project){
  41. this.stats.project = message.project;
  42. }
  43. if(message.live_new){
  44. this.stats.live.unshift(message.live_new);
  45. var lifetime = this.stats.lifetime[message.live_new.username];
  46. if(lifetime === undefined){
  47. lifetime = [0, 0];
  48. this.stats.lifetime[message.live_new.username] = lifetime;
  49. }
  50. lifetime[0] += message.live_new.found;
  51. lifetime[1] += message.live_new.scanned;
  52. this.stats.global[0] += message.live_new.found;
  53. this.stats.global[1] += message.live_new.scanned;
  54. var project = this.stats.project[message.live_new.project];
  55. if(lifetime === undefined){
  56. project = [0, 0];
  57. this.stats.project[message.live_new.project] = project;
  58. }
  59. project[0] += message.live_new.found;
  60. project[1] += message.live_new.scanned;
  61. var dateNow = new Date();
  62. var bucketIndex = dateNow.getUTCSeconds();
  63. if (this.prevScanBucketIndex != bucketIndex) {
  64. this.prevScanBucketIndex = bucketIndex;
  65. this.scanRateBucket[bucketIndex] = message.live_new.scanned;
  66. } else {
  67. this.scanRateBucket[bucketIndex] += message.live_new.scanned;
  68. }
  69. var sum = 0;
  70. for (var i = 0; i < 60; i++) {
  71. sum += this.scanRateBucket[i];
  72. }
  73. this.stats.currentScanRate = sum / 60.0;
  74. }
  75. this.onMessage(message);
  76. };
  77. WSController.prototype.onMessage = function(message){
  78. };
  79. WSController.prototype.onConnect = function () {
  80. var wsDiv = document.getElementById('websocket_message');
  81. wsDiv.style.display = 'none';
  82. };
  83. WSController.prototype.onDisconnect = function () {
  84. var wsDiv = document.getElementById('websocket_message');
  85. wsDiv.style.display = 'inherit';
  86. if (this.reconnectTimer) {
  87. clearTimeout(this.reconnectTimer);
  88. }
  89. this.reconnectTimer = setTimeout(this.initWebSocket.bind(this), 60000);
  90. };
  91. var app = angular.module("stats", []);
  92. var lastUpdate = new Date(0);
  93. app.constant("endpoint", "/api/live_stats");
  94. app.constant("max_display", 30);
  95. app.service("ws", ["endpoint", function(endpoint){
  96. return new WSController(endpoint);
  97. }]);
  98. app.filter("toArray", function(){
  99. return function(obj) {
  100. var result = [];
  101. angular.forEach(obj, function(val, key) {
  102. result.push([key, val]);
  103. });
  104. return result;
  105. };
  106. });
  107. app.controller("StatsController", ["$scope", "$filter", "ws", "max_display", function($scope, $filter, ws, max_display){
  108. $scope.stats = ws.stats;
  109. $scope.totalLimit = 30;
  110. $scope.recentLimit = 30;
  111. $scope.getScanned = function(item){
  112. return item[1][1];
  113. };
  114. ws.onMessage = function(){
  115. ws.stats.live.splice($scope.recentLimit - 1, ws.stats.live.length);
  116. // somehow computing this in page cause infinite digest cycles
  117. $scope.lifetime = $filter("toArray")(ws.stats.lifetime);
  118. var dateNow = new Date();
  119. if (dateNow - lastUpdate > ws.updateInterval) {
  120. $scope.$apply();
  121. lastUpdate = dateNow;
  122. var afterDate = new Date();
  123. var applyDifference = afterDate - dateNow;
  124. if (applyDifference > 50) {
  125. ws.updateInterval = 1000 + Math.min(10000, applyDifference * 2);
  126. } else {
  127. ws.updateInterval = 500;
  128. }
  129. }
  130. };
  131. }]);
  132. document.getElementById('websocket_message').innerHTML = 'Sorry, live stat updates is currently unavailable.';
  133. })();