2

我对 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,但无论我尝试什么,我似乎都无法正确排列类型。我总是遇到任务和连接之间的类型冲突。tcp.lift 似乎有助于输入流,但它似乎不适用于接收器。是否有更清洁/更好的方法来执行 loggedCmds 部分(FWIW:我愿意对上述任何代码进行更正或改进)。

我应该注意,如果我只是通过 io.stdOutLines 将结果发送到标准输出,我没有问题(“通过”在这种情况下似乎有效,我在示例中看到过),这只是当我想发送流到 io.stdOutLines继续使用流响应客户端。

4

2 回答 2

0

我自己(终于)想出来了。使用“.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
于 2015-05-03T00:37:21.410 回答
0

一个更短的解决方案是

val log = stdOutLines contramap { (_: Any).toString }
requests map(parseRequest) observe log
于 2015-09-04T15:22:53.860 回答