app/models/RecentLogin.scala (40 lines of code) (raw):
package models
import java.time.{Duration, LocalDateTime}
import scala.xml.NodeSeq
import java.time.format.{DateTimeFormatter, DateTimeFormatterBuilder}
import java.time.temporal.{ChronoField, ChronoUnit, TemporalAccessor, TemporalUnit}
object RecentLogin extends ((String, String, String, LocalDateTime, Duration)=>RecentLogin) {
private def parseFormat(forcedYear:Option[Int]) = new DateTimeFormatterBuilder()
.appendPattern("EE MMM d HH:mm:ss")
.parseStrict()
.parseDefaulting(ChronoField.YEAR, forcedYear match {
case None=> LocalDateTime.now().get(ChronoField.YEAR)
case Some(year)=> year
})
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter()
def durationFromXmlObj(xml: NodeSeq):Duration = {
val days = (xml \@ "days").toLong
val hours = (xml \@ "hours").toLong
val minutes = (xml \@ "minutes").toLong
val totalSeconds = days*3600L*24L + hours *3600L + minutes*60L
Duration.of(totalSeconds, ChronoUnit.SECONDS)
}
def fromXml(xml:NodeSeq, forcedYear:Option[Int]=None):Either[String,RecentLogin] = try {
val lastLoginTime = (xml \@ "login").replaceAll(" +", " ") + ":00"
val parsed = parseFormat(forcedYear).parse(lastLoginTime)
Right(new RecentLogin(
xml \@ "hostname", xml \@ "username", xml \@ "location", LocalDateTime.from(parsed), durationFromXmlObj(xml \ "duration")
))
} catch {
case ex:Throwable=>
Left(ex.toString)
}
}
case class RecentLogin(hostname:String, username:String,location:String,loginTime:LocalDateTime,duration:Duration) {
/**
* generate a unique ID for this login for the index
* @return
*/
def idForElastic:String = {
val encoder = java.util.Base64.getEncoder
val rawString=s"$username@$hostname@${loginTime.format(DateTimeFormatter.ISO_DATE_TIME)}"
encoder.encodeToString(rawString.toCharArray.map(_.toByte))
}
}