Skip to content

Instantly share code, notes, and snippets.

@nicktelford
Last active June 1, 2017 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicktelford/2e57785c772ab7c398c9d0b4a25cfc7a to your computer and use it in GitHub Desktop.
Save nicktelford/2e57785c772ab7c398c9d0b4a25cfc7a to your computer and use it in GitHub Desktop.
Rough sketch of ideas for a "scala.net" like package
class UnknownHostException(hostname: String) extends RuntimeException(s"Unknown host: $hostname")
object NetworkAddress {
def apply(address: String): Option[NetworkAddress] = address match {
case addr @ IPv4NetworkAddress.pattern(_, _, _, _) => Some(new IPv4NetworkAddress(addr) {})
case addr @ IPv6NetworkAddress.pattern(_, _, _, _, _, _, _, _) => Some(new IPv6NetworkAddress(addr) {})
case addr @ UnresolvedNetworkAddress.pattern() => Some(new UnresolvedNetworkAddress(addr) {})
case _ => None
}
}
trait NetworkAddress {
def resolved(implicit ctx: ExecutionContext): Future[NetworkAddress]
}
object UnresolvedNetworkAddress {
val pattern: Regex = ??? // todo: a validation for hostnames
def apply(address: String): Option[NetworkAddress] address match {
case addr @ pattern() => Some(new UnresolvedNetworkAddress(addr) {})
case _ => None
}
}
sealed abstract case class UnresolvedNetworkAddress(address: String) extends NetworkAddress {
def resolved(implicit ctx: ExecutionContext,
platform: platform.Network): Future[NetworkAddress] =
platform.resolved(address).map {
_.flatMap(NetworkAddress.apply)
.headOption
.getOrElse(throw new UnknownHostException)
}
}
object IPv4NetworkAddress {
val pattern: Regex = ??? // todo: a validation for IPv4 addresses
def apply(address: String): Option[NetworkAddress] address match {
case addr @ pattern() => Some(new IPv4NetworkAddress(addr) {})
case _ => None
}
}
sealed abstract case class IPv4NetworkAddress(address: String) extends NetworkAddress {
def resolved(implicit ctx: ExecutionContext): Future[NetworkAddress] =
Future.successful(this)
}
object IPv6NetworkAddress {
val pattern: Regex = ??? // todo: a validation for IPv6 addresses
def apply(address: String): Option[NetworkAddress] address match {
case addr @ pattern() => Some(new IPv6NetworkAddress(addr) {})
case _ => None
}
}
sealed abstract case class IPv6NetworkAddress(address: String) extends NetworkAddress {
def resolved(implicit ctx: ExecutionContext): Future[NetworkAddress] =
Future.successful(this)
}
trait SocketAddress
case class NetworkSocketAddress(address: NetworkAddress, port: Int) extends SocketAddress {
def resolved(implicit ctx: ExecutionContext): Future[NetworkSocketAddress] =
address match {
case addr: UnresolvedNetworkAddress => addr.resolved.map(x => copy(address = x))
case _ => Future.successful(this)
}
}
// platform specific class for the JVM
class platform.Network {
private[this] val ip4Impl: Inet4AddressImpl = ??? // probably need to use reflection in order to construct this
private[this] val ip6Impl: Inet6AddressImpl = ??? // probably need to use reflection in order to construct this
def resolved(address: String)
(implicit ctx: ExecutionContext): Future[Seq[NetworkAddress]] =
Future.sequence {
Future(ip4Impl.lookupAllHostAddr(address)).map(IPv4NetworkAddress.apply) ::
Future(ip6Impl.lookupAllHostAddr(address)).map(IPv6NetworkAddress.apply) ::
Nil
}.transform(_, { case _: java.net.UnknownHostException => UnknownHostException(address) })
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment