status.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. <div class="ui stackable four column grid">
  2. <div class="column">
  3. <div id="serverstatus" class="ui green statustab inverted segment">
  4. <h4 class="ui header">
  5. <i class="power off icon"></i>
  6. <div class="content">
  7. <span id="statusTitle">Offline</span>
  8. <div style="color: white;" class="sub header" id="statusText">Reverse proxy server is offline</div>
  9. </div>
  10. </h4>
  11. </div>
  12. </div>
  13. <div class="column">
  14. <div id="connections" class="ui statustab summary segment">
  15. <h4 class="ui header">
  16. <i class="exchange icon"></i>
  17. <div class="content">
  18. <span id="summaryTotalCount"></span> <small>Req. Today</small>
  19. <div class="sub header" style="margin-top: 0.4em;">
  20. <i class="green circle check icon"></i> <span id="summarySuccCount"></span>
  21. / <i class="red red exclamation circle icon"></i> <span id="summaryErrCount"></span>
  22. </div>
  23. </div>
  24. </h4>
  25. </div>
  26. </div>
  27. <div class="column">
  28. <div id="connections" class="ui statustab segment" style="background-color: #f0ece1; border: 0px solid transparent;">
  29. <h4 class="ui header">
  30. <i class="arrows alternate horizontal icon"></i>
  31. <div class="content">
  32. <span id="forwardtype"></span>
  33. <div class="sub header" id="forwardtypeList">
  34. </div>
  35. </div>
  36. </h4>
  37. </div>
  38. </div>
  39. <div class="column">
  40. <div id="connections" class="ui statustab inverted segment" style="background-color: #7d8e88;">
  41. <h4 class="ui header">
  42. <i class="map marker alternate icon"></i>
  43. <div class="content">
  44. <span id="country"></span>
  45. <div class="sub header" id="countryList">
  46. </div>
  47. </div>
  48. </h4>
  49. </div>
  50. </div>
  51. </div>
  52. <div class="ui divider"></div>
  53. <p>Inbound Port (Port to be proxied)</p>
  54. <div class="ui action fluid input">
  55. <input type="text" id="incomingPort" placeholder="Incoming Port" value="80">
  56. <button class="ui button" onclick="handlePortChange();">Apply</button>
  57. </div>
  58. <br>
  59. <div id="tls" class="ui toggle checkbox">
  60. <input type="checkbox">
  61. <label>Use TLS to serve proxy request</label>
  62. </div>
  63. <br>
  64. <div id="redirect" class="ui toggle checkbox" style="margin-top: 0.6em;">
  65. <input type="checkbox">
  66. <label>Force redirect HTTP request to HTTPS<br>
  67. <small>(Only apply when listening port is not 80)</small></label>
  68. </div>
  69. <br>
  70. <div id="portUpdateSucc" class="ui green message" style="display:none;">
  71. <i class="ui green checkmark icon"></i> Setting Updated
  72. </div>
  73. <Br>
  74. <button id="startbtn" class="ui teal button" onclick="startService();">Start Service</button>
  75. <button id="stopbtn" class="ui red disabled button" onclick="stopService();">Stop Service</button>
  76. <div id="rploopbackWarning" class="ui segment" style="display:none;">
  77. <b><i class="yellow warning icon"></i> Loopback Routing Warning</b><br>
  78. <small>This management interface is a loopback proxied service. <br>If you want to shutdown the reverse proxy server, please remove the proxy rule for the management interface and refresh.</small>
  79. </div>
  80. <div id="statusErrmsg" class="ui red message" style="display: none;"></div>
  81. <div class="ui divider"></div>
  82. <div class="ui two column stackable grid">
  83. <div class="column">
  84. <p>Visitor Counts</p>
  85. <table class="ui unstackable celled table">
  86. <thead>
  87. <tr>
  88. <th>Country ISO Code</th>
  89. <th>Unique Visitors</th>
  90. </tr>
  91. </thead>
  92. <tbody id="countryCodetable">
  93. <tr>
  94. <td colspan="2">No Data</td>
  95. </tr>
  96. </tbody>
  97. </table>
  98. </div>
  99. <div class="column">
  100. <p>Proxy Request Types</p>
  101. <table class="ui unstackable celled table">
  102. <thead>
  103. <tr>
  104. <th>Proxy Type</th>
  105. <th>Count</th>
  106. </tr>
  107. </thead>
  108. <tbody id="forwardTypeTable">
  109. <tr>
  110. <td colspan="2">No Data</td>
  111. </tr>
  112. </tbody>
  113. </table>
  114. </div>
  115. </div>
  116. <br>
  117. <button class="ui basic green button" onclick="getDailySummaryDetails();"><i class="refresh icon"></i> Refresh</button>
  118. <script>
  119. let loopbackProxiedInterface = false;
  120. //Initial the start stop button if this is reverse proxied
  121. $.get("/api/proxy/requestIsProxied", function(data){
  122. if (data == true){
  123. //This management interface is reverse proxied by itself
  124. //do not allow turning off the proxy
  125. $("#stopbtn").addClass("disabled");
  126. loopbackProxiedInterface = true;
  127. $("#rploopbackWarning").show();
  128. }
  129. });
  130. //Get the latest server status from proxy server
  131. function initRPStaste(){
  132. $.get("/api/proxy/status", function(data){
  133. if (data.Running == true){
  134. $("#startbtn").addClass("disabled");
  135. if (!loopbackProxiedInterface){
  136. $("#stopbtn").removeClass("disabled");
  137. }
  138. $("#serverstatus").addClass("green");
  139. $("#statusTitle").text("Online");
  140. $("#statusText").text("Serving request on port: " + data.Option.Port);
  141. }else{
  142. $("#startbtn").removeClass("disabled");
  143. $("#stopbtn").addClass("disabled");
  144. $("#statusTitle").text("Offline");
  145. $("#statusText").text("Reverse proxy server is offline");
  146. $("#serverstatus").removeClass("green");
  147. }
  148. $("#incomingPort").val(data.Option.Port);
  149. });
  150. }
  151. function abbreviateNumber(value) {
  152. var newValue = value;
  153. var suffixes = ["", "k", "m", "b", "t"];
  154. var suffixNum = 0;
  155. while (newValue >= 1000 && suffixNum < suffixes.length - 1) {
  156. newValue /= 1000;
  157. suffixNum++;
  158. }
  159. if (value > 1000){
  160. newValue = newValue.toFixed(2);
  161. }
  162. return newValue + suffixes[suffixNum];
  163. }
  164. function getDailySummaryDetails(){
  165. function sortObjectByValue(obj) {
  166. // Convert object to array of [key, value] pairs
  167. const entries = Object.entries(obj);
  168. // Sort array based on value of each pair
  169. entries.sort((a, b) => {
  170. return b[1] - a[1];
  171. });
  172. // Convert sorted array back to object
  173. const sortedObj = {};
  174. for (const [key, value] of entries) {
  175. sortedObj[key] = value;
  176. }
  177. return sortedObj;
  178. }
  179. $.get("/api/stats/countries", function(data){
  180. data = sortObjectByValue(data);
  181. $("#country").html((Object.keys(data)[0])?Object.keys(data)[0]:"No Data");
  182. $("#countryList").html(`
  183. <div style="color: white;">
  184. ${(Object.keys(data)[1])?Object.keys(data)[1]:"No Data"}<br>
  185. ${(Object.keys(data)[2])?Object.keys(data)[2]:"No Data"}
  186. </div>
  187. `);
  188. //populate the table
  189. $("#countryCodetable").html("");
  190. for (const [key, value] of Object.entries(data)) {
  191. $("#countryCodetable").append(`<tr>
  192. <td>${key}</td>
  193. <td>${value}</td>
  194. </tr>`);
  195. }
  196. if (Object.keys(data).length == 0){
  197. $("#countryCodetable").append(`<tr>
  198. <td colspan="2">No Data</td>
  199. </tr>`);
  200. }
  201. });
  202. //Filter forward type
  203. function fft(ft){
  204. if (ft.indexOf("-") >= 0){
  205. ft = ft.replace("-", " (");
  206. ft = ft + ")";
  207. }
  208. ft = ft.charAt(0).toUpperCase() + ft.slice(1);
  209. return ft;
  210. }
  211. $.get("/api/stats/summary", function(data){
  212. data = sortObjectByValue(data.ForwardTypes);
  213. $("#forwardtype").html((Object.keys(data)[0])?fft(Object.keys(data)[0]) + ": " + abbreviateNumber(data[Object.keys(data)[0]]):"No Data");
  214. $("#forwardtypeList").html(`
  215. <div>
  216. ${(Object.keys(data)[1])?fft(Object.keys(data)[1]) + ": " + abbreviateNumber(data[Object.keys(data)[1]]):"No Data"}<br>
  217. ${(Object.keys(data)[2])?fft(Object.keys(data)[2]) + ": " + abbreviateNumber(data[Object.keys(data)[2]]):"No Data"}
  218. </div>
  219. `);
  220. $("#forwardTypeTable").html("");
  221. for (const [key, value] of Object.entries(data)) {
  222. $("#forwardTypeTable").append(`<tr>
  223. <td>${key}</td>
  224. <td>${value}</td>
  225. </tr>`);
  226. }
  227. if (Object.keys(data).length == 0){
  228. $("#forwardTypeTable").append(`<tr>
  229. <td colspan="2">No Data</td>
  230. </tr>`);
  231. }
  232. });
  233. }
  234. getDailySummaryDetails();
  235. function getDailySummary(){
  236. $.get("/api/stats/summary?fast=true", function(data){
  237. console.log(data);
  238. $("#summaryTotalCount").text(abbreviateNumber(data.TotalRequest));
  239. $("#summarySuccCount").text(abbreviateNumber(data.ValidRequest));
  240. $("#summaryErrCount").text(abbreviateNumber(data.ErrorRequest));
  241. });
  242. }
  243. setInterval(function(){
  244. getDailySummary();
  245. }, 10000);
  246. getDailySummary();
  247. //Start and stop service button
  248. function startService(){
  249. $.post("/api/proxy/enable", {enable: true}, function(data){
  250. if (data.error != undefined){
  251. statusErrmsg(data.error);
  252. }
  253. initRPStaste();
  254. });
  255. }
  256. function stopService(){
  257. $.post("/api/proxy/enable", {enable: false}, function(data){
  258. if (data.error != undefined){
  259. statusErrmsg(data.error);
  260. }
  261. initRPStaste();
  262. });
  263. }
  264. //Show error message
  265. function statusErrmsg(message){
  266. $("#statusErrmsg").html(`<i class="red remove icon"></i> ${message}`);
  267. $("#statusErrmsg").slideDown('fast').delay(5000).slideUp('fast');
  268. }
  269. function handlePortChange(){
  270. var newPortValue = $("#incomingPort").val();
  271. if (isNaN(newPortValue - 1)){
  272. alert("Invalid incoming port value");
  273. return;
  274. }
  275. $.post("/api/proxy/setIncoming", {incoming: newPortValue}, function(data){
  276. if (data.error != undefined){
  277. statusErrmsg(data.error);
  278. }
  279. $("#portUpdateSucc").stop().finish().slideDown("fast").delay(3000).slideUp("fast");
  280. initRPStaste();
  281. });
  282. }
  283. function initHTTPtoHTTPSRedirectSetting(){
  284. $.get("/api/proxy/useHttpsRedirect", function(data){
  285. if (data == true){
  286. $("#redirect").checkbox("set checked");
  287. }
  288. //Initiate the input listener on the checkbox
  289. $("#redirect").find("input").on("change", function(){
  290. let thisValue = $("#redirect").checkbox("is checked");
  291. $.ajax({
  292. url: "/api/proxy/useHttpsRedirect",
  293. data: {set: thisValue},
  294. success: function(data){
  295. if (data.error != undefined){
  296. alert(data.error);
  297. }else{
  298. //Updated
  299. $("#portUpdateSucc").stop().finish().slideDown("fast").delay(3000).slideUp("fast");
  300. initRPStaste();
  301. }
  302. }
  303. })
  304. });
  305. });
  306. }
  307. initHTTPtoHTTPSRedirectSetting();
  308. function initTlsSetting(){
  309. $.get("/api/cert/tls", function(data){
  310. if (data == true){
  311. $("#tls").checkbox("set checked");
  312. }else{
  313. $("#redirect").addClass('disabled');
  314. }
  315. //Initiate the input listener on the checkbox
  316. $("#tls").find("input").on("change", function(){
  317. let thisValue = $("#tls").checkbox("is checked");
  318. if (thisValue){
  319. $("#redirect").removeClass('disabled');
  320. }else{
  321. $("#redirect").addClass('disabled');
  322. }
  323. $.ajax({
  324. url: "/api/cert/tls",
  325. data: {set: thisValue},
  326. success: function(data){
  327. if (data.error != undefined){
  328. alert(data.error);
  329. }else{
  330. //Updated
  331. $("#portUpdateSucc").stop().finish().slideDown("fast").delay(3000).slideUp("fast");
  332. initRPStaste();
  333. }
  334. }
  335. })
  336. });
  337. })
  338. }
  339. initTlsSetting();
  340. </script>