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

时间:2015-04-28 07:22:49

标签: scala scalaz scalaz-stream

我对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时也继续使用流来响应客户端。

2 个答案:

答案 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