Last active
June 1, 2017 10:56
-
-
Save nicktelford/2e57785c772ab7c398c9d0b4a25cfc7a to your computer and use it in GitHub Desktop.
Rough sketch of ideas for a "scala.net" like package
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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