我对scalaz-stream和scalaz.stream.tcp都很新。我试图为自己的教育目的做一个非常简单的服务器。我将请求解析为命令,执行它们以产生响应,并将响应写回客户端。我遇到问题的部分是我想将每个收到的命令记录到stdout。
这是我传递给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.log / mapW / drainW来使用io.stdOutLines,但无论我尝试什么,我似乎无法使类型正确排列。我总是在Task和Connection之间遇到类型冲突。 tcp.lift似乎有助于输入流,但它似乎不适用于接收器。是否有更清洁/更好的方法来执行loggedCmds部分(FWIW:我可以对上述任何代码进行更正或改进)。
我应该注意,如果我只是通过io.stdOutLines将结果转到stdout我没有问题("通过"似乎在这种情况下工作,我在示例中看到过),它只是当我想将流发送到io.stdOutLines时和也继续使用流来响应客户端。
答案 0 :(得分: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
答案 1 :(得分:0)
更短的解决方案是
val log = stdOutLines contramap { (_: Any).toString }
requests map(parseRequest) observe log