trait Socket[F[_]] {
// Reads exactly `numBytes` from the peer in a single chunk.
def readN(numBytes: Int, timeout: Option[FiniteDuration]): F[Option[Chunk[Byte]]]
// Writes `bytes` to the peer.
def write(bytes: Chunk[Byte], timeout: Option[FiniteDuration]): F[Unit]
}
trait BlockSocket {
def readN(numBytes: Int): Option[Chunk[Byte]]
def write(bytes: Chunk[Byte]): Unit
}
trait CallbackSocket {
def readN(numBytes: Int, cb: Option[Chunk[Byte]] => Unit): Unit
def write(bytes: Chunk[Byte], cb: Unit => Unit): Unit
}
trait FutureSocket {
def readN(numBytes: Int): Future[Option[Chunk[Byte]]]
def write(bytes: Chunk[Byte]): Future[Unit]
}
type Id[A] = A
trait BlockSocket {
def readN(numBytes: Int): Id[Option[Chunk[Byte]]]
def write(bytes: Chunk[Byte]): Id[Unit]
}
type Callback[A] = (A => Unit) => Unit
trait CallbackSocket {
// readN(numBytes: Int, cb: Option[Chunk[Byte]] => Unit): Unit
// readN(numBytes: Int)(Option[Chunk[Byte]] => Unit): Unit
// readN(numBytes: Int): ((Option[Chunk[Byte]] => Unit) => Unit)
def readN(numBytes: Int): Callback[Option[Chunk[Byte]]]
def write(bytes: Chunk[Byte]): Callback[Unit]
}
trait FutureSocket {
def readN(numBytes: Int): Future[Option[Chunk[Byte]]]
def write(bytes: Chunk[Byte]): Future[Unit]
}
trait Socket[F[_]] {
def readN(numBytes: Int): F[Option[Chunk[Byte]]]
def write(bytes: Chunk[Byte]): F[Unit]
}
object Socket {
// blocking synchronous socket
def blocking: Socket[Id] = new Socket[Id] {
def readN(numBytes: Int): Id[Option[Chunk[Byte]]] = ???
def write(bytes: Chunk[Byte]): Id[Unit] = ???
}
// asynchronous callback socket
def async: Socket[Callback] = new Socket[Callback] {
def readN(numBytes: Int): Callback[Option[Chunk[Byte]]] = ???
def write(bytes: Chunk[Byte]): Callback[Unit] = ???
}
// asynchronous future socket
def future: Socket[Future] = new Socket[Future] { ... }
}
trait Socket[F[_]] {
// Reads exactly `numBytes` from the peer in a single chunk.
def readN(numBytes: Int, timeout: Option[FiniteDuration]): F[Option[Chunk[Byte]]]
// Writes `bytes` to the peer.
def write(bytes: Chunk[Byte], timeout: Option[FiniteDuration]): F[Unit]
}
TCP provides reliable, ordered, and error-checked delivery of a stream of octets (bytes) between applications running on hosts communicating via an IP network.
TCP does not provide framing.
PacketWrapper {
int totalPacketLength; ///< total length of packet
int checksum; ///< checksum of whole packet
int correlationId; ///< [optional] additional id
///< to be used to identify response
byte packetType; ///< type of packet
byte[] data;
}
def read[F[_]: FlatMap](S: Socket[F[_]],
timeout: Option[FiniteDuration]): F[Speech] = for {
Some(bs) <- S.readN(4, timeout) if bs.size == 4
size <- readSize(bs) // Little Endian, Codec Dependent
Some(bm) <- S.readN(size, timeout) if bm.size == size
speech <- readMessage(bm)
} yield speech
def write[F[_]: FlatMap](S: Socket[F[_]],
speech: Speech,
timeout: Option[FiniteDuration]): F[Unit] = for {
bm <- writeMessage(speech)
bs <- writeSize(bm) // Little Endian, Codec Dependent
_ <- S.write(bs)
_ <- S.write(bm)
} yield ()
trait IQBusConnection[F[_]] {
def incoming: Stream[F, Stream[F, Speech]]
def outgoing: Stream[F, Sink[F, Speech]]
}
type Pipe[F[_], A, B] = (Stream[F, A]) => Stream[F, B]
type Sink[F[_], A] = Pipe[F, A, Unit]
trait IQBusConnection[F[_]] {
def incoming: Stream[F, Stream[F, Speech]]
def outgoing: Stream[F, Sink[F, Correlation[F, Speech, Speech]]]
}
PacketWrapper {
int totalPacketLength; ///< total length of packet
int checksum; ///< checksum of whole packet
int correlationId; ///< [optional] additional id
///< to be used to identify response
byte packetType; ///< type of packet
byte[] data;
}
trait IQBusConnection[F[_]] {
def incoming: Stream[F, Stream[F, Speech]]
def outgoing: Stream[F, Sink[F, Speech]]
}
trait Correlation[F[_], +A, +B] {
def data[A1 >: A]: A1
def codata[B1 >: B]: Option[F[B1]]
}
final case class Absent[F[_], A](a: A)
extends Correlation[F, A, Nothing] { ... }
final case class Affirmed[F[_], A, B](a: A, da: Deferred[F, B])
extends Correlation[F, A, B] { ... }
abstract class Correlator[F[_]] {
def index[A, B](ca: Correlation[F, A, B]): F[(A, Option[Int])]
def split[A](ci: (A, Option[Int])): F[Option[A]]
}
trait IQBusConnection[F[_]] {
def incoming: Stream[F, Stream[F, Speech]]
def outgoing: Stream[F, Sink[F, Correlation[F, Speech, Speech]]]
}
trait IQBusPublisher[F[_]] {
def properties: IQBusPublisher.Properties
def publish: Sink[F, Dispatch.Outbound[F]]
def publish1(d: Dispatch.Outbound[F]): F[Option[MessageResponse]]
}
object IQBusPublisher {
final case class Properties(kind: MessageKind,
name: String,
version: Version,
parameters: Parameters = Parameters())
}
abstract class Outbound[F[_]] extends Dispatch {
def modify(f: Parameters => Parameters): Outbound[F]
def message(kind: MessageKind,
name: String,
version: Version,
defaults: Parameters = Parameters()): F[Messaging.Message]
}
trait IQBusConnection[F[_]] {
def incoming: Stream[F, Stream[F, Speech]]
def outgoing: Stream[F, Sink[F, Speech]]
}
def outbound[F[_], A, B](
data: Option[A],
meta: Option[B],
parameters: Parameters = Parameters(),
status: Status = 2000,
uid: => UUID = UUID.randomUUID()
)(implicit F: Sync[F], A: Encoder[A, String], B: Encoder[B, String])
: F[Outbound[F]] = ???
trait IQBusPublisher[F[_]] {
def publish: Sink[F, Dispatch.Outbound[F]]
def publish1(d: Dispatch.Outbound[F]): F[Option[MessageResponse]]
}
trait IQBusConnection[F[_]] {
def incoming: Stream[F, Stream[F, Speech]]
def outgoing: Stream[F, Sink[F, Correlation[F, Speech, Speech]]]
}
trait IQBusSubscriber[F[_]] {
def properties: IQBusSubscriber.Properties
def subscription: Signal[F, Option[Long]]
def subscribe(buffer: Int): Stream[F, Dispatch.Inbound[F]]
def subscribe1(f: Dispatch.Inbound[F] => F[Unit]): F[CancelToken[F]]
}
object IQBusSubscriber {
final case class Properties(kind: MessageKind,
name: String,
version: Version,
service: Option[String],
parameters: Parameters = Parameters(),
matchers: Matchers = Matchers())
}
abstract class Inbound[F[_]] extends Dispatch {
def message: Messaging.Message
def data[A: Decoder[String, ?]]: F[Option[A]]
def meta[B: Decoder[String, ?]]: F[Option[B]]
}
def inbound[F[_]: Concurrent](message: Messaging.Message): F[Inbound[F]] = ???
trait IQBusPublisher[F[_]] {
def publish: Sink[F, Dispatch.Outbound[F]]
def publish1(d: Dispatch.Outbound[F]): F[Option[MessageResponse]]
}
trait IQBusConnection[F[_]] {
def incoming: Stream[F, Stream[F, Speech]]
def outgoing: Stream[F, Sink[F, Correlation[F, Speech, Speech]]]
}
trait IQBusSubscriber[F[_]] {
def subscribe(buffer: Int): Stream[F, Dispatch.Inbound[F]]
def subscribe1(f: Dispatch.Inbound[F] => F[Unit]): F[CancelToken[F]]
}
trait IQBus[F[_]] {
def address: Address.Full
def config: cfg.Config
def publisher(props: IQBusPublisher.Properties): Resource[F, IQBusPublisher[F]]
def subscriber(props: IQBusSubscriber.Properties): Resource[F, IQBusSubscriber[F]]
}
sealed trait Resource[F[_], A] {
def use[B](f: A => F[B])(implicit F: Bracket[F, Throwable]): F[B]
}
object Resource {
def apply[F[_]: Functor, A](resource: F[(A, F[Unit])]): Resource[F, A] = ???
def make[F[_]: Functor, A](acquire: F[A])(release: A => F[Unit]): Resource[F, A] = ???
}
trait IQBus[F[_]] {
def address: Address.Full
def config: cfg.Config
def publisher(props: IQBusPublisher.Properties): Resource[F, IQBusPublisher[F]]
def subscriber(props: IQBusSubscriber.Properties): Resource[F, IQBusSubscriber[F]]
}
object IQBus {
def apply[F[_]](address: Address.Full, config: cfg.Config)(
implicit F: ConcurrentEffect[F], M: Metrics[F], T: Timer[F]
): Resource[F, IQBus[F]] = ???
}
F[_] is 'tagless' by default
Need something -- ask for it
Next in hierarchy is more powerful
trait IQPublication[A] { self =>
def properties: IQBusPublisher.Properties
def actor[F[_]](implicit B: IQBus[F]): Resource[F, IQBusPublisher[F]] =
B.publisher(self.properties)
def publish[F[_]: Concurrent: IQBus]: Sink[F, A] = ???
def publish1[F[_]: Sync: IQBus]: Resource[F, A => F[Option[MessageResponse]]] = ???
}
final class IQPublicationOps[F[_]](val B: IQBus[F]) extends AnyVal {
def publish[A](buffer: Int)(
implicit A: IQPublication[A],
F: Concurrent[F]
): Sink[F, A] = A.publish(B, F)
def publish1[A](
implicit A: IQPublication[A],
F: Sync[F]
): Resource[F, A => F[Option[MessageResponse]]] = A.publish1(B, F)
}
case class Quote(active: Int, value: Double, time: Long)
implicit val QP: IQPublication[Quote] = IQPublication.data.event(
name = "quote",
version = "1.0",
service = "quote-provider"
)
import iqbus.syntax.publisher._
val iqbus: IQBus[F] = ???
iqbus.publish1[Quote].use { pub =>
val qs = List(1.117, 1.118, 1.116).map { v =>
Quote(1, v, System.currentTimeMillis / 1000)
}
qs.traverse(pub).map { responses =>
responses.flatten.foreach(println)
}
}
trait IQSubscription[A] {
def properties: IQBusSubscriber.Properties
def actor[F[_]](implicit B: IQBus[F]): Resource[F, IQBusSubscriber[F]] =
B.subscriber(properties)
def subscribe[F[_]: Sync: IQBus](buffer: Int): Stream[F, A] = ???
def subscribe1[F[_]: Concurrent: IQBus](f: A => F[Unit]): F[CancelToken[F]] = ???
}
final class IQSubscriptionOps[F[_]](val B: IQBus[F]) extends AnyVal {
def subscribe[A](buffer: Int)(
implicit A: IQSubscription[A],
F: Sync[F]
): Stream[F, A] = A.subscribe(buffer)(B, F)
def subscribe1[A](f: A => F[Unit])(
implicit A: IQSubscription[A],
F: Concurrent[F]
): F[CancelToken[F]] = A.subscribe1(f)(B, F)
}
case class Quote(active: Int, value: Double, time: Long)
implicit val QP: IQSubscription[Quote] = IQSubscription.data.event(
name = "quote",
version = "1.0",
service = "quote-provider"
)
import iqbus.syntax.subscriber._
val iqbus: IQBus[F] = ???
iqbus
.subscribe[Quote](100)
.take(200)
.map(println)
.compile
.drain
trait IQRequest[A, B] {
def publication: IQPublication[A]
def subscription: IQSubscription[B]
def request1[F[_]: Concurrent: IQBus]: Resource[F, A => F[B]] = ???
def request[F[_]: Concurrent: IQBus](buffer: Long): Pipe[F, A, (A, B)] = ???
def requestR[F[_]: Concurrent: IQBus, R](buffer: Long): Pipe[F, (R, A), (R, B)] = ???
}
trait IQResponse[B, A] {
def publication: IQPublication[B]
def subscription: IQSubscription[A]
def respond1[F[_]: Concurrent: IQBus](f: A => F[Option[B]]): F[CancelToken[F]] = ???
def respond[F[_]: Concurrent: IQBus](buffer: Long): Pipe[F, (UUID, B), (UUID, A)] = ???
def respondIf[F[_]: Concurrent: IQBus](buffer: Long)(
f: A => F[Boolean]
): Pipe[F, (UUID, B), (UUID, A)] = ???
}