1
0

server_selector.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. HTML5 Speedtest v4.7 MPOT - Server selector
  3. by Federico Dossena
  4. https://github.com/adolfintel/speedtest/
  5. GNU LGPLv3 License
  6. */
  7. //pings the specified URL, then calls the function result. Result will receive a parameter which is either the time it took to ping the URL, or -1 if something went wrong.
  8. var PING_TIMEOUT=1000;
  9. var USE_PING_TIMEOUT=true; //will be disabled on unsupported browsers
  10. if(/MSIE.(\d+\.\d+)/i.test(navigator.userAgent)){ //IE11 doesn't support XHR timeout
  11. USE_PING_TIMEOUT=false;
  12. }
  13. function ping(url,result){
  14. var xhr=new XMLHttpRequest();
  15. var t=new Date().getTime();
  16. xhr.onload=function(){
  17. if(xhr.responseText.length==0){ //we expect an empty response
  18. var instspd=new Date().getTime()-t; //rough timing estimate
  19. try{
  20. //try to get more accurate timing using performance API
  21. var p=performance.getEntries();
  22. p=p[p.length-1];
  23. var d=p.responseStart-p.requestStart;
  24. if(d<=0) d=p.duration;
  25. if(d>0&&d<instspd) instspd=d;
  26. }catch(e){
  27. }
  28. result(instspd);
  29. }else result(-1);
  30. }.bind(this);
  31. xhr.onerror=function(){
  32. result(-1);
  33. }.bind(this);
  34. xhr.open("GET",url);
  35. if(USE_PING_TIMEOUT){
  36. try{
  37. xhr.timeout=PING_TIMEOUT;
  38. xhr.ontimeout=xhr.onerror;
  39. }catch(e){}
  40. }
  41. xhr.send();
  42. }
  43. //this function repeatedly pings a server to get a good estimate of the ping. When it's done, it calls the done function without parameters. At the end of the execution, the server will have a new parameter called pingT, which is either the best ping we got from the server or -1 if something went wrong.
  44. var PINGS=3, //up to 3 pings are performed, unless the server is down...
  45. SLOW_THRESHOLD=500; //...or one of the pings is above this threshold
  46. function checkServer(server,done){
  47. var i=0;
  48. server.pingT=-1;
  49. if(server.server.indexOf(location.protocol)==-1) done(); else{
  50. var nextPing=function(){
  51. if(i++==PINGS){done(); return;}
  52. ping(server.server+server.pingURL,function(t){
  53. if(t>=0){
  54. if(t<server.pingT||server.pingT==-1) server.pingT=t;
  55. if(t<SLOW_THRESHOLD) nextPing(); else done();
  56. }else done();
  57. }.bind(this));
  58. }.bind(this);
  59. nextPing();
  60. }
  61. }
  62. /*this function goes through a list of servers, each with this format:
  63. {
  64. name: "User friendly name",
  65. server:"http://yourBackend.com/", <---- make sure there's a / at the end!
  66. dlURL:"garbage.php" <----- path to garbage.php or its replacement on the server
  67. ulURL:"empty.php" <----- path to empty.php or its replacement on the server
  68. pingURL:"empty.php" <----- path to empty.php or its replacement on the server. This is used to ping the server by this selector
  69. getIpURL:"getIP.php" <----- path to getIP.php or its replacement on the server
  70. }
  71. For each server, the ping is measured, then the server with the function result is called with the best server, or null if all the servers were down.
  72. */
  73. function selectServer(serverList,result){
  74. var i=0;
  75. var done=function(){
  76. var bestServer=null;
  77. for(var i=0;i<serverList.length;i++){
  78. if(serverList[i].pingT!=-1&&(bestServer==null||serverList[i].pingT<bestServer.pingT)) bestServer=serverList[i];
  79. }
  80. result(bestServer);
  81. }.bind(this);
  82. var nextServer=function(){
  83. if(i==serverList.length){done(); return;}
  84. checkServer(serverList[i++],nextServer);
  85. }.bind(this);
  86. nextServer();
  87. }
  88. /*
  89. this function is a faster version of selectServer that tests multiple servers concurrently. Useful for large server lists
  90. */
  91. var CONCURRENCY=4; //4 seems to be the safest value
  92. function fastSelectServer(serverList,result){
  93. var serverLists=[];
  94. for(var i=0;i<CONCURRENCY;i++){
  95. serverLists[i]=[];
  96. }
  97. for(var i=0;i<serverList.length;i++){
  98. serverLists[i%CONCURRENCY].push(serverList[i]);
  99. }
  100. var completed=0;
  101. var bestServer=null;
  102. for(var i=0;i<CONCURRENCY;i++){
  103. selectServer(serverLists[i],function(server){
  104. if(server!=null){
  105. if(bestServer==null||server.pingT<bestServer.pingT) bestServer=server;
  106. }
  107. completed++;
  108. if(completed==CONCURRENCY) result(bestServer);
  109. }.bind(this));
  110. }
  111. }