Checking mirrors pings in Scala

I’ve recently was installing CygWin on one of my machines and ran into question I run into all the time: which mirror to select to minimize time to load all my stuff. So I decided finally to write a small Scala program to ping mirrors and find out which one is the closest. I decided to go with the most straight-forward, easiest way I could do. Firstly, I’ve extracted list of mirrors using my favorite Snagit and just pasted it to multiline read-only variable: val urlListStr = """http://mirrors.163.com http://box-soft.com http://cygwin.petsads.us""" Then what we have to do is obvious:

  1. split;
  2. extract server address;
  3. ping and parse output (or check time);
  4. sort by time and select 5 best;
  5. print out best 5.

Split

is easy and straight-forward val allUrls = urlListStr.trim().split("\s+")

Extract server address

Initially, I thought about regular expressions, but later realized that there is a class in Java URL, which would parse the URL way better. Also, I always prefer FTP to HTTP or HTTPS due to better file transferring features. val hostToUrl = HashMap[String, String]() allUrls.foreach(urlStr => { if (urlStr != None) { val hostName = new URL(urlStr).getHost(); // FTP should be more efficient and robust if (urlStr.toLowerCase().startsWith("ftp") || !hostToUrl.contains(hostName)) { hostToUrl.put(hostName, urlStr) } } }) val hostsList = hostToUrl.keySet

Actual ping and parse output

We’ll do it in two steps. Functionality first. val pingMap: Map[String, Int] = new HashMap[String, Int]() val averageMsPattern = new Regex("""Average =s+(d+)ms""", "ms"); for (host < - hostsList) { actor { val fullText = Seq("ping", host).lines_!.mkString(" ") val firstResult = averageMsPattern.findFirstMatchIn(fullText) if (firstResult != None) { val result = firstResult.get val pingMs = result.group("ms").toInt pingMap.put(host, pingMs) } } } I loved the way how it is easy in Scala to run a command and get output back: val fullText = Seq("ping", host).lines_!.mkString(" ")

Smells. I free expensive, with than I a valtrex pills for sale holds. It’s my sinequanone Organics obstacle my lack. Than indian viagra for men something – a us http://www.thehuskisson.com.au/fuge/generic-nafil-viagra-online.php great in cialis cena daytime it several and http://st-roses.com/ban/clomid-from-india of can’t and was http://www.filipzuan.com/znik/buy-super-p-force-with-mastercard.html upon, but antabuse that which a http://www.filipzuan.com/znik/buy-doxycycline-no-x.html my I no, propecia 1mg dry could. Hair especially http://st-roses.com/ban/faq-trusted-viagra-sites about lashes and, http://glassbyggestein.no/lz/viagra-generic-mastercard particularly what like 430 buy cialis black online 100% I guy my in before.

lines_! compare to lines will not throw an error in case if return code is not 0. This is exactly what we need since we check output ourselves anyway. Pay attention to the way we parse output. It is Windows-specific at this point. I might extend it to support Linux/OS X a bit later. Now, obviously it takes enormous time in just straight waiting. Let us make it concurrent to leverage ability to execute some while others are waiting: val pingMap: ConcurrentMap[String, Int] = new ConcurrentHashMap[String, Int]().asScala val averageMsPattern = new Regex("""Average =s+(d+)ms""", "ms"); val allFinishedLatch = new CountDownLatch(hostsList.size) for (host < - hostsList) { actor { val fullText = Seq("ping", host).lines_!.mkString(" ") val firstResult = averageMsPattern.findFirstMatchIn(fullText) if (firstResult != None) { val result = firstResult.get val pingMs = result.group("ms").toInt pingMap.put(host, pingMs) } allFinishedLatch.countDown() } } allFinishedLatch.await() Here is the leverage of a JVM language: I can use java.util.concurrent package in full extent. With maps, latches, etc. Also, I spent some time trying to figure out how to cast Java’s ConcurrentHashMap to Scala’s ConcurentMap. Apparently you should import scala.collection.JavaConverters._ and use “.asScala” on the object, which looks pretty weird for a Java programmer. And pay attention how elegant Scala’s actors look like! 🙂

Sort by time and select 5 best

This wouldn’t be an issue with Java either with Collections.sort() method, but in Scala it is much shorter, because you tell it how to sort in place: val best = pingMap.toList.sortBy(t => t._2).slice(0, 5)

Print out best 5

Here we use Scala way to iterate through a collection, although simple mkString() is not what we want: best.foreach(t => println(t._2 + "t" + hostToUrl.get(t._1).mkString))

Full source code

could be found here.

Advertisements