faucet.html 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <title>{{.Network}}: Faucet</title>
  8. <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
  9. <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
  10. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  11. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-noty/2.4.1/packaged/jquery.noty.packaged.min.js"></script>
  12. <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
  13. <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.0/moment.min.js"></script>
  14. <style>
  15. .vertical-center {
  16. min-height: 100%;
  17. min-height: 100vh;
  18. display: flex;
  19. align-items: center;
  20. }
  21. .progress {
  22. position: relative;
  23. }
  24. .progress span {
  25. position: absolute;
  26. display: block;
  27. width: 100%;
  28. color: white;
  29. }
  30. pre {
  31. padding: 6px;
  32. margin: 0;
  33. }
  34. </style>
  35. </head>
  36. <body>
  37. <div class="vertical-center">
  38. <div class="container">
  39. <div class="row" style="margin-bottom: 16px;">
  40. <div class="col-lg-12">
  41. <h1 style="text-align: center;"><i class="fa fa-bath" aria-hidden="true"></i> {{.Network}} Faucet</h1>
  42. </div>
  43. </div>
  44. <div class="row">
  45. <div class="col-lg-8 col-lg-offset-2">
  46. <div class="input-group">
  47. <input id="url" name="url" type="text" class="form-control" placeholder="Social network URL containing your Core Chain address...">
  48. <span class="input-group-btn">
  49. <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Give me BNB <i class="fa fa-caret-down" aria-hidden="true"></i></button>
  50. <ul class="dropdown-menu dropdown-menu-right">{{range $idx, $amount := .Amounts}}
  51. <li><a style="text-align: center;" onclick="tier={{$idx}};symbol='BNB'; {{if $.Recaptcha}}grecaptcha.execute(){{else}}submit({{$idx}}){{end}}">{{$amount}}</a></li>{{end}}
  52. </ul>
  53. </span>
  54. <span class="input-group-btn">
  55. <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Peggy tokens<i class="fa fa-caret-down" aria-hidden="true"></i></button>
  56. <ul class="dropdown-menu dropdown-menu-right"> {{range $symbol, $bep2eInfo := .Bep2eInfos}}
  57. <li><a style="text-align: center;" onclick="symbol={{$symbol}}; {{if $.Recaptcha}}grecaptcha.execute(){{else}}submitBep2e({{$symbol}}){{end}}">{{$bep2eInfo.AmountStr}} {{$symbol}}</a></li>{{end}}
  58. </ul>
  59. </span>
  60. </div>{{if .Recaptcha}}
  61. <div class="g-recaptcha" data-sitekey="{{.Recaptcha}}" data-callback="submit" data-size="invisible"></div>{{end}}
  62. </div>
  63. </div>
  64. <div class="row" style="margin-top: 32px;">
  65. <div class="col-lg-6 col-lg-offset-3">
  66. <div class="panel panel-small panel-default">
  67. <div class="panel-body" style="padding: 0; overflow: auto; max-height: 300px;">
  68. <table id="requests" class="table table-condensed" style="margin: 0;"></table>
  69. </div>
  70. <div class="panel-footer">
  71. <table style="width: 100%"><tr>
  72. <td style="text-align: center;"><i class="fa fa-rss" aria-hidden="true"></i> <span id="peers"></span> peers</td>
  73. <td style="text-align: center;"><i class="fa fa-database" aria-hidden="true"></i> <span id="block"></span> blocks</td>
  74. <td style="text-align: center;"><i class="fa fa-heartbeat" aria-hidden="true"></i> <span id="funds"></span> BNBs</td>
  75. <td style="text-align: center;"><i class="fa fa-university" aria-hidden="true"></i> <span id="funded"></span> funded</td>
  76. </tr></table>
  77. </div>
  78. </div>
  79. </div>
  80. </div>
  81. </div>
  82. </div>
  83. <script>
  84. // Global variables to hold the current status of the faucet
  85. var attempt = 0;
  86. var server;
  87. var tier = 0;
  88. var symbol="";
  89. var requests = [];
  90. // Define a function that creates closures to drop old requests
  91. var dropper = function(hash) {
  92. return function() {
  93. for (var i=0; i<requests.length; i++) {
  94. if (requests[i].tx.hash == hash) {
  95. requests.splice(i, 1);
  96. break;
  97. }
  98. }
  99. }
  100. };
  101. // Define the function that submits a gist url to the server
  102. var submit = function({{if .Recaptcha}}captcha{{end}}) {
  103. server.send(JSON.stringify({url: $("#url")[0].value, symbol: symbol, tier: tier{{if .Recaptcha}}, captcha: captcha{{end}}}));{{if .Recaptcha}}
  104. grecaptcha.reset();{{end}}
  105. };
  106. // Define a method to reconnect upon server loss
  107. var reconnect = function() {
  108. server = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/faucet-smart/api");
  109. server.onmessage = function(event) {
  110. var msg = JSON.parse(event.data);
  111. if (msg === null) {
  112. return;
  113. }
  114. if (msg.funds !== undefined) {
  115. $("#funds").text(msg.funds);
  116. }
  117. if (msg.funded !== undefined) {
  118. $("#funded").text(msg.funded);
  119. }
  120. if (msg.peers !== undefined) {
  121. $("#peers").text(msg.peers);
  122. }
  123. if (msg.number !== undefined) {
  124. $("#block").text(parseInt(msg.number, 16));
  125. }
  126. if (msg.error !== undefined) {
  127. noty({layout: 'topCenter', text: msg.error, type: 'error', timeout: 5000, progressBar: true});
  128. }
  129. if (msg.success !== undefined) {
  130. noty({layout: 'topCenter', text: msg.success, type: 'success', timeout: 5000, progressBar: true});
  131. }
  132. if (msg.requests !== undefined && msg.requests !== null) {
  133. // Mark all previous requests missing as done
  134. for (var i=0; i<requests.length; i++) {
  135. if (msg.requests.length > 0 && msg.requests[0].tx.hash == requests[i].tx.hash) {
  136. break;
  137. }
  138. if (requests[i].time != "") {
  139. requests[i].time = "";
  140. setTimeout(dropper(requests[i].tx.hash), 3000);
  141. }
  142. }
  143. // Append any new requests into our local collection
  144. var common = -1;
  145. if (requests.length > 0) {
  146. for (var i=0; i<msg.requests.length; i++) {
  147. if (requests[requests.length-1].tx.hash == msg.requests[i].tx.hash) {
  148. common = i;
  149. break;
  150. }
  151. }
  152. }
  153. for (var i=common+1; i<msg.requests.length; i++) {
  154. requests.push(msg.requests[i]);
  155. }
  156. // Iterate over our entire local collection and re-render the funding table
  157. var content = "";
  158. for (var i=requests.length-1; i >= 0; i--) {
  159. var done = requests[i].time == "";
  160. var elapsed = moment().unix()-moment(requests[i].time).unix();
  161. content += "<tr id='" + requests[i].tx.hash + "'>";
  162. content += " <td><div style=\"background: url('" + requests[i].avatar + "'); background-size: cover; width:32px; height: 32px; border-radius: 4px;\"></div></td>";
  163. content += " <td><pre>" + requests[i].account + "</pre></td>";
  164. content += " <td style=\"width: 100%; text-align: center; vertical-align: middle;\">";
  165. if (done) {
  166. content += " funded";
  167. } else {
  168. content += " <span id='time-" + i + "' class='timer'>" + moment.duration(-elapsed, 'seconds').humanize(true) + "</span>";
  169. }
  170. content += " <div class='progress' style='height: 4px; margin: 0;'>";
  171. if (done) {
  172. content += " <div class='progress-bar progress-bar-success' role='progressbar' aria-valuenow='30' style='width:100%;'></div>";
  173. } else if (elapsed > 30) {
  174. content += " <div class='progress-bar progress-bar-danger progress-bar-striped active' role='progressbar' aria-valuenow='30' style='width:100%;'></div>";
  175. } else {
  176. content += " <div class='progress-bar progress-bar-striped active' role='progressbar' aria-valuenow='" + elapsed + "' style='width:" + (elapsed * 100 / 30) + "%;'></div>";
  177. }
  178. content += " </div>";
  179. content += " </td>";
  180. content += "</tr>";
  181. }
  182. $("#requests").html("<tbody>" + content + "</tbody>");
  183. }
  184. }
  185. server.onclose = function() { setTimeout(reconnect, 3000); };
  186. }
  187. // Start a UI updater to push the progress bars forward until they are done
  188. setInterval(function() {
  189. $('.progress-bar').each(function() {
  190. var progress = Number($(this).attr('aria-valuenow')) + 1;
  191. if (progress < 30) {
  192. $(this).attr('aria-valuenow', progress);
  193. $(this).css('width', (progress * 100 / 30) + '%');
  194. } else if (progress == 30) {
  195. $(this).css('width', '100%');
  196. $(this).addClass("progress-bar-danger");
  197. }
  198. })
  199. $('.timer').each(function() {
  200. var index = Number($(this).attr('id').substring(5));
  201. $(this).html(moment.duration(moment(requests[index].time).unix()-moment().unix(), 'seconds').humanize(true));
  202. })
  203. }, 1000);
  204. // Establish a websocket connection to the API server
  205. reconnect();
  206. </script>{{if .Recaptcha}}
  207. <script src="https://www.google.com/recaptcha/api.js" async defer></script>{{end}}
  208. </body>
  209. </html>