ffi: refactor cinterface (#43)

* ffi: refactor cinterface

* ffi: change Init parameters to JSON
This commit is contained in:
yzy-1 2022-10-25 14:16:57 +08:00 committed by GitHub
parent e5c7b811e5
commit 561c0a6955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -11,6 +11,7 @@ import (
"os"
"runtime"
"time"
"unsafe"
"github.com/criyle/go-judge/cmd/executorserver/model"
"github.com/criyle/go-judge/env"
@ -40,7 +41,7 @@ var (
srcPrefix string
)
func newFilsStore(dir string) filestore.FileStore {
func newFilsStore(dir string) (filestore.FileStore, error) {
if dir == "" {
if runtime.GOOS == "linux" {
dir = "/dev/shm"
@ -49,8 +50,10 @@ func newFilsStore(dir string) filestore.FileStore {
}
dir, _ = os.MkdirTemp(dir, "executorserver")
}
os.MkdirAll(dir, 0755)
return filestore.NewFileLocalStore(dir)
if err := os.MkdirAll(dir, 0o755); err != nil {
return nil, err
}
return filestore.NewFileLocalStore(dir), nil
}
// Init initialize the sandbox environment
@ -62,7 +65,7 @@ func Init(i *C.char) C.int {
return -1
}
if ip.Parallelism == 0 {
if ip.Parallelism <= 0 {
ip.Parallelism = 4
}
@ -76,7 +79,11 @@ func Init(i *C.char) C.int {
srcPrefix = ip.SrcPrefix
fs = newFilsStore(ip.Dir)
var err error
fs, err = newFilsStore(ip.Dir)
if err != nil {
log.Fatalln("file store create failed", err)
}
b, err := env.NewBuilder(env.Config{
ContainerInitPath: ip.CInitPath,
@ -105,6 +112,8 @@ func Init(i *C.char) C.int {
}
// Exec runs command inside container runner
//
// Remember to free the return char pointer value
//export Exec
func Exec(e *C.char) *C.char {
es := C.GoString(e)
@ -130,31 +139,33 @@ func Exec(e *C.char) *C.char {
return C.CString(buf.String())
}
// FileList get the list of files in the file store
// FileList get the list of files in the file store.
//
// Remember to free the 2-d char array `ids` and `names`
//export FileList
func FileList() *C.char {
ids := fs.List()
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(ids); err != nil {
return nil
func FileList(ids ***C.char, names ***C.char) C.size_t {
res := fs.List()
idsWrap := C.malloc(C.size_t(len(res)) * C.size_t(unsafe.Sizeof(uintptr(0))))
namesWrap := C.malloc(C.size_t(len(res)) * C.size_t(unsafe.Sizeof(uintptr(0))))
pIDsWrap := (*[1<<30 - 1]*C.char)(idsWrap)
pNamesWrap := (*[1<<30 - 1]*C.char)(namesWrap)
idx := 0
for id, name := range res {
pIDsWrap[idx] = C.CString(id)
pNamesWrap[idx] = C.CString(name)
idx++
}
return C.CString(buf.String())
*ids = (**C.char)(idsWrap)
*names = (**C.char)(namesWrap)
return C.size_t(len(res))
}
// FileAdd adds file to the file store
//
// Remember to free the return char pointer value
//export FileAdd
func FileAdd(e *C.char) *C.char {
type fileAdd struct {
Name string `json:"name"`
Content string `json:"content"`
}
es := C.GoString(e)
var fa fileAdd
if err := json.NewDecoder(bytes.NewBufferString(es)).Decode(&fa); err != nil {
return nil
}
func FileAdd(content *C.char, contentLen C.int, name *C.char) *C.char {
sContent := C.GoBytes(unsafe.Pointer(content), contentLen)
f, err := fs.New()
if err != nil {
@ -162,35 +173,34 @@ func FileAdd(e *C.char) *C.char {
}
defer f.Close()
if _, err := f.Write([]byte(fa.Content)); err != nil {
if _, err := f.Write(sContent); err != nil {
return nil
}
id, err := fs.Add(fa.Name, f.Name())
id, err := fs.Add(C.GoString(name), f.Name())
if err != nil {
return nil
}
return C.CString(id)
}
// FileGet gets file from file store by id
// FileGet gets file from file store by id.
// If the return value is a positive number or zero, the value represents the length of the file.
// Otherwise, if the return value is negative, the following error occurred:
//
// - `-1`: The file does not exist.
// - `-2`: go-judge internal error.
//
// Remember to free `out`.
//export FileGet
func FileGet(e *C.char) *C.char {
type fileGet struct {
ID string `json:"id"`
}
func FileGet(e *C.char, out **C.char) C.int {
es := C.GoString(e)
var f fileGet
if err := json.NewDecoder(bytes.NewBufferString(es)).Decode(&f); err != nil {
return nil
}
_, file := fs.Get(f.ID)
_, file := fs.Get(es)
if file == nil {
return nil
return -1
}
r, err := envexec.FileToReader(file)
if err != nil {
return nil
return -2
}
if f, ok := r.(*os.File); ok {
defer f.Close()
@ -198,32 +208,24 @@ func FileGet(e *C.char) *C.char {
c, err := io.ReadAll(r)
if err != nil {
return nil
return -2
}
return C.CString(string(c))
*out = (*C.char)(C.CBytes(c))
return (C.int)(len(c))
}
// FileDelete deletes file from file store by id
// FileDelete deletes file from file store by id, returns 0 if failed.
//export FileDelete
func FileDelete(e *C.char) *C.char {
type fileDelete struct {
ID string `json:"id"`
}
func FileDelete(e *C.char) C.int {
es := C.GoString(e)
var f fileDelete
if err := json.NewDecoder(bytes.NewBufferString(es)).Decode(&f); err != nil {
return nil
}
ok := fs.Remove(f.ID)
ok := fs.Remove(es)
if !ok {
return nil
return 0
}
return C.CString("")
return 1
}
type nopLogger struct {
}
type nopLogger struct{}
func (nopLogger) Debug(args ...interface{}) {
}