package fs2chat import cats.effect.Concurrent import cats.implicits._ import fs2.Stream import fs2.concurrent.Queue import fs2.io.tcp.Socket import scodec.{Decoder, Encoder} import scodec.stream.{StreamDecoder, StreamEncoder} /** * Socket which reads a stream of messages of type `In` and allows writing * messages of type `Out`. */ trait MessageSocket[F[_], In, Out] { def read: Stream[F, In] def write1(out: Out): F[Unit] } object MessageSocket { def apply[F[_]: Concurrent, In, Out]( socket: Socket[F], inDecoder: Decoder[In], outEncoder: Encoder[Out], outputBound: Int ): F[MessageSocket[F, In, Out]] = for { outgoing <- Queue.bounded[F, Out](outputBound) } yield new MessageSocket[F, In, Out] { def read: Stream[F, In] = { val readSocket = socket .reads(1024) .through(StreamDecoder.many(inDecoder).toPipeByte[F]) val writeOutput = outgoing.dequeue .through(StreamEncoder.many(outEncoder).toPipeByte) .through(socket.writes(None)) readSocket.concurrently(writeOutput) } def write1(out: Out): F[Unit] = outgoing.enqueue1(out) } }