Skip to content

Instantly share code, notes, and snippets.

@euch
Created June 29, 2016 10:06
Show Gist options
  • Select an option

  • Save euch/b104d1e40ee4bbea8bbf9d4fcfbccb25 to your computer and use it in GitHub Desktop.

Select an option

Save euch/b104d1e40ee4bbea8bbf9d4fcfbccb25 to your computer and use it in GitHub Desktop.
Fetch OpenTTD server statistics from http://openttd.org
def getOpenTTDServerInfoCached(serverName: String): Option[String] = {
val cacheKey = OpenTTDServerInfo(serverName)
reachabilityCache.get(cacheKey) match {
case Some(expired) if expired.time.plusMinutes(1).isBefore(now) => reachabilityCache.update(cacheKey, getOpenTTDServerInfo(cacheKey))
case None => reachabilityCache.put(cacheKey, getOpenTTDServerInfo(cacheKey))
case Some(actual) =>
}
reachabilityCache.get(cacheKey) match {
case Some(info) => info.status
case None => None
}
}
private def getOpenTTDServerInfo(openTTDServerInfo: OpenTTDServerInfo): ReachabilityOnTime = {
val cleaner = new HtmlCleaner
def getServerPage(serverName: String): Option[String] = try {
cleaner.clean(new URL("https://www.openttd.org/en/servers")).getElementsByName("tr", true)
.filter(elem => StringEscapeUtils.unescapeHtml4(elem.getText.toString).contains(openTTDServerInfo.serverName))
.map(elem => "https://www.openttd.org/" + elem.getAllChildren.get(3).asInstanceOf[TagNode].getAllChildren.get(0).asInstanceOf[TagNode].getAllChildren.get(0).asInstanceOf[TagNode].getAttributeByName("href"))
.headOption
} catch {
case th: Throwable =>
println(s"failed to get openttd server page ${th.getMessage}")
th.printStackTrace()
None
}
getServerPage(openTTDServerInfo.serverName) match {
case None =>
return ReachabilityOnTime(reachable = false, now)
case Some(sp) =>
val elements = cleaner.clean(new URL(sp)).getElementsByName("tr", true).toList
def getRowByName(name: String): Option[String] = try {
elements.filter(_.getAllChildren.get(0) match {
case tn: TagNode =>
tn.getAllChildren.get(0) match {
case cn: ContentNode => cn.getContent.equals(name)
case not => false
}
case not => false
}).map(_.getAllChildren.get(1).asInstanceOf[TagNode].getText.toString).headOption
} catch {
case th: Throwable => None
}
val currentDate = getRowByName("Current date:")
val clients = getRowByName("Clients:")
return ReachabilityOnTime(reachable = true, now, status = Some(s"""Clients: ${clients.getOrElse("n/a")}<br/>Date: ${currentDate.getOrElse("n/a")}<br><a href=$sp>more info</a>"""))
}
ReachabilityOnTime(reachable = false, now)
}
private def now = LocalDateTime.now()
private val reachabilityCache = mutable.ParHashMap[CacheKey, ReachabilityOnTime]()
private trait CacheKey
private case class OpenTTDServerInfo(serverName: String) extends CacheKey
private case class HostPort(host: String, port: Int) extends CacheKey
case class ReachabilityOnTime(reachable: Boolean, time: LocalDateTime, status: Option[String] = None)
@euch
Copy link
Author

euch commented Jun 29, 2016

Cache should store Future, of course

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment