如何干净地登录到 io.stdOutLines 并使用 scalaz.stream.tcp 服务器响应客户端

How do I cleanly log to io.stdOutLines and respond to the client with a scalaz.stream.tcp server

我对 scalaz-stream 很陌生,特别是 scalaz.stream.tcp。我正在尝试为我自己的教育目的做一个非常简单的服务器。我将请求解析为命令,执行它们以产生响应,然后将响应写回客户端。我遇到问题的部分是我想将每个收到的命令记录到标准输出。

这是我要传递给 tcp.server 的内部流程:

def inner: Process[tcp.Connection, Unit] = {
    val requests: Process[Connection, String] = tcp.reads(1024) pipe text.utf8Decode
    val cmds: Process[Connection, Command] = requests.map(parseRequest)
    val header: Process[Task, ByteVector] = Process("HEADER\n").pipe(text.utf8Encode)
    val loggedCmds: Process[Connection, Command] = cmds.map { cmd =>
        println(cmd.toString)
        cmd
    }
    val results: Process[Connection, Process[Task, ByteVector]] = loggedCmds.map(_.execute)
    val processedRequests: Process[Connection, Unit] = results.flatMap(result =>  tcp.writes(tcp.lift(header ++ result)))
    processedRequests
}

(我没有到处指定类型的习惯;我这样做只是为了尝试处理事情。我打算删除它们。)

上面的代码实际上可以正确编译和运行,但我觉得它不是很干净或地道。具体来说,我对 loggedCmds 部分不满意。我想通过 .observer 或使用 writer.logged/mapW/drainW 使用 io.stdOutLines,但无论我尝试什么,我似乎都无法让类型正确排列。我总是在 Task 和 Connection 之间遇到类型冲突。 tcp.lift 似乎有助于输入流,但它似乎不适用于 Sink。是否有 cleaner/better 方法来执行 loggedCmds 部分(FWIW:我愿意对上述任何代码进行更正或改进)。

我应该注意,如果我只是通过 io.stdOutLines 将结果转到标准输出,我没有问题("through" 似乎在那种情况下有效,我在示例中看到过) ,正好我要发流给io.stdOutLines 并且也继续用流响应客户端

我自己想出来了(终于)。使用“.toChannel”我能够做到:

val cmdFormatter = process1.id[Command].map(_.toString)
val cmdPrinter = io.stdOutLines.pipeIn(cmdFormatter)

...

val cmds: Process[Connection, Command] = requests.map(parseRequest) through
    cmdPrinter.toChannel

更短的解决方案是

val log = stdOutLines contramap { (_: Any).toString }
requests map(parseRequest) observe log