go-judge icon indicating copy to clipboard operation
go-judge copied to clipboard

在用了除 gRPC 外其他传输层时,无法向 sandbox 中添加二进制文件

Open yzy-1 opened this issue 2 years ago • 4 comments

在使用除 gRPC 外其他传输层时(HTTP / WebSocket / FFI 等)时,数据都是以 JSON 方式传递的,然而 struct CmdFile 里的 Content 被声明称了 *string 类型:

https://github.com/criyle/go-judge/blob/e5c7b811e5c72f5e7fb494c8e4914a5b0729ed6c/cmd/executorserver/model/model.go#L14-L22

也就是说,似乎是没办法把一个二进制文件作为调用 /run 时的 copyIn 直接扔到沙盒里去.我尝试了下面几种方法:

  • 使用 README 中的方式,传一个 Buffer 进去,但是直接返回 json: cannot unmarshal object into Go struct field CmdFile.cmd.files.content of type string
  • 使用 buffer.toString('binary'),这样倒是可以传进沙盒,但是沙盒里面的文件会变,比如一个值(十进制)为 $200$ 的 byte 会变成 $195$ 和 $136$ 两个 byte.

如果仅是这样那么问题还不是很大,至少可以通过 file post 先把文件传入沙盒,再用 fileId 来在 cmd 中使用文件.但是 FFI 传输层中的 FileAdd 仍然是接受 JSON 字符串作为参数.也就是说,在使用 FFI 时,这个问题目前无解.


顺便提个建议,由于存在二进制文件,且 JSON 里没有对应 byte 的类型,JSON 不太适合作为这个项目的信息传输格式.在假设把 CmdFile 里的 Content 重构成 []byte 类型后,一个 byte 在 JSON 中会占用四个 byte 的空间(包含三个十进制数位和一个逗号),因此建议采用一些更加适合的格式.需要注意的是,BSON 由于其 16 MB 的最大文档大小,同样也不是一个适合的格式.或许 MessagePack 是一个较优的选择.

yzy-1 avatar Oct 22 '22 05:10 yzy-1

定义成 *string 类型的考虑是可以直接传递字面值来作为文件内容。通常来说文件也是以 UTF-8 编码的。在 go 中,如果定义的是 []byte 来接受 json 值的话要经过 base64 的编码。

在大多数的情况下文件是由 src 来传递来自本机文件系统的文件,可以支持二进制文件。

FFI 有段时间没有更新过了,考虑到没有已知的使用者,可以借此机会更新接口实现。

从支持二进制编码来考虑的话,也许 gRPC 使用的 protobuf 可以作为备选的一种格式。使用 base64 编码的字符串在 json 中也可行。

criyle avatar Oct 22 '22 08:10 criyle

protobuf 的话有个小问题,就是传文件的时候会经常套娃.

就比如 cmd_file 里有个 file,file 里有个 memory_file,memory_file 有个 content 这样的.

yzy-1 avatar Oct 22 '22 10:10 yzy-1

定义成 *string 类型的考虑是可以直接传递字面值来作为文件内容。通常来说文件也是以 UTF-8 编码的。在 go 中,如果定义的是 []byte 来接受 json 值的话要经过 base64 的编码。

所以说 JSON 就不太适合这种出现了二进制数据的场合,不管是编码成十进制整数字面量数组还是 base64 都会增加数据的长度.本来传输题目的测试数据这种东西就不是为了「人类可读性」的,结合这一点,换用二进制编码的数据交换格式可能更合适.

yzy-1 avatar Oct 22 '22 10:10 yzy-1

在设计的时候,沙箱服务通常作为一个附属组件的方式和评测服务部署在同一个 host 或者是共享卷宗的 pod 里面。在 FFI 的使用情况下甚至是同一个进程。在这种部署下,测试数据是由 src 路径来提供,并且支持非 UTF-8 文件。

content 提供内容是为了自测这种使用示例,用来提供非持久化的测试数据。而在这种情况下,用户提供的数据通常来自于网页上的文本框并由 JSON 编码传递的 UTF-8 内容。

在这个设计下,让 Rest API 或者 FFI 来支持 content 传递非 UTF-8 文件似乎是一个伪需求。

criyle avatar Oct 23 '22 06:10 criyle

现在在使用 WebSocket 作为 API 接口时,可以传递二进制数据给输入输出了。

criyle avatar Mar 14 '24 00:03 criyle