1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-04-28 03:20:10 +00:00

Use c to unmarshal json and decompress data

This commit is contained in:
杨赫然 2022-08-31 15:23:51 +08:00
parent 9debeec57e
commit 9d7e82a883
2 changed files with 212 additions and 21 deletions

View File

@ -284,25 +284,6 @@ func NewSeafile(version int, fileSize int64, blkIDs []string) (*Seafile, error)
return seafile, nil
}
func uncompress(p []byte) ([]byte, error) {
b := bytes.NewReader(p)
var out bytes.Buffer
r, err := zlib.NewReader(b)
if err != nil {
return nil, err
}
_, err = io.Copy(&out, r)
if err != nil {
r.Close()
return nil, err
}
r.Close()
return out.Bytes(), nil
}
func compress(p []byte) ([]byte, error) {
var out bytes.Buffer
w := zlib.NewWriter(&out)
@ -324,7 +305,7 @@ func (seafile *Seafile) FromData(p []byte) error {
if err != nil {
return err
}
err = json.Unmarshal(b, seafile)
err = seafile.unmarshal(b)
if err != nil {
return err
}
@ -368,7 +349,7 @@ func (seafdir *SeafDir) FromData(p []byte) error {
if err != nil {
return err
}
err = json.Unmarshal(b, seafdir)
err = seafdir.unmarshal(b)
if err != nil {
return err
}

210
fileserver/fsmgr/fsmgr_c.go Normal file
View File

@ -0,0 +1,210 @@
package fsmgr
/*#cgo pkg-config: zlib jansson glib-2.0
#include <stdio.h>
#include <glib.h>
#include <zlib.h>
#include <jansson.h>
#define ZLIB_BUF_SIZE 16384
int
seaf_decompress (unsigned char *input, int inlen, unsigned char **output, int *outlen)
{
int ret;
unsigned have;
z_stream strm;
unsigned char out[ZLIB_BUF_SIZE];
GByteArray *barray;
if (inlen == 0) {
g_warning ("Empty input for zlib, invalid.\n");
return -1;
}
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK) {
g_warning ("inflateInit failed.\n");
return -1;
}
strm.avail_in = inlen;
strm.next_in = input;
barray = g_byte_array_new ();
do {
strm.avail_out = ZLIB_BUF_SIZE;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret < 0) {
g_warning ("Failed to inflate.\n");
goto out;
}
have = ZLIB_BUF_SIZE - strm.avail_out;
g_byte_array_append (barray, out, have);
} while (ret != Z_STREAM_END);
out:
(void)inflateEnd(&strm);
if (ret == Z_STREAM_END) {
*outlen = barray->len;
*output = g_byte_array_free (barray, 0);
return 0;
} else {
g_byte_array_free (barray, 1);
return -1;
}
}
*/
import "C"
import (
"fmt"
"unsafe"
)
func (seafile *Seafile) unmarshal(b []byte) error {
if b == nil || len(b) == 0 {
err := fmt.Errorf("failed to load seafile json object")
return err
}
object := C.json_loadb((*C.char)(unsafe.Pointer(&b[0])), C.ulong(len(b)), 0, nil)
if unsafe.Pointer(object) == C.NULL {
err := fmt.Errorf("failed to load seafile json object2")
return err
}
err := seafile.fillSeafileFromJsonObject(object)
C.json_decref(object)
return err
}
func (seafile *Seafile) fillSeafileFromJsonObject(object *C.json_t) error {
seafile.Version = int(jsonGetIntMember(object, "version"))
seafile.FileType = int(jsonGetIntMember(object, "type"))
seafile.FileSize = uint64(jsonGetIntMember(object, "size"))
seafile.FileID = jsonGetStringMember(object, "file_id")
cKey := C.CString("block_ids")
block_id_array := C.json_object_get(object, cKey)
C.free(unsafe.Pointer(cKey))
if unsafe.Pointer(block_id_array) == C.NULL {
err := fmt.Errorf("no block id array in seafile object")
return err
}
n_blocks := C.json_array_size(block_id_array)
for i := 0; i < int(n_blocks); i++ {
block_id_obj := C.json_array_get(block_id_array, C.ulong(i))
block_id := C.json_string_value(block_id_obj)
if unsafe.Pointer(block_id) == C.NULL {
err := fmt.Errorf("no block id in block id array")
return err
}
seafile.BlkIDs = append(seafile.BlkIDs, C.GoString(block_id))
}
return nil
}
func (seafdir *SeafDir) unmarshal(b []byte) error {
if b == nil || len(b) == 0 {
err := fmt.Errorf("failed to load seafile json object")
return err
}
object := C.json_loadb((*C.char)(unsafe.Pointer(&b[0])), C.ulong(len(b)), 0, nil)
if unsafe.Pointer(object) == C.NULL {
err := fmt.Errorf("failed to load seafile json object2")
return err
}
err := seafdir.fillSeaDirFromJsonObject(object)
C.json_decref(object)
return err
}
func (seafdir *SeafDir) fillSeaDirFromJsonObject(object *C.json_t) error {
seafdir.Version = int(jsonGetIntMember(object, "version"))
seafdir.DirType = int(jsonGetIntMember(object, "type"))
seafdir.DirID = jsonGetStringMember(object, "dir_id")
cKey := C.CString("dirents")
dirent_array := C.json_object_get(object, cKey)
C.free(unsafe.Pointer(cKey))
if unsafe.Pointer(dirent_array) == C.NULL {
err := fmt.Errorf("no dirents in dir object")
return err
}
n_dirents := C.json_array_size(dirent_array)
for i := 0; i < int(n_dirents); i++ {
dirent_obj := C.json_array_get(dirent_array, C.ulong(i))
if unsafe.Pointer(dirent_obj) == C.NULL {
err := fmt.Errorf("no dirent in dirent array")
return err
}
seafdir.fillSeafDirentFromJsonObject(dirent_obj)
}
return nil
}
func (seafdir *SeafDir) fillSeafDirentFromJsonObject(object *C.json_t) {
dirent := new(SeafDirent)
dirent.Mode = uint32(jsonGetIntMember(object, "mode"))
dirent.ID = jsonGetStringMember(object, "id")
dirent.Name = jsonGetStringMember(object, "name")
dirent.Mtime = jsonGetIntMember(object, "mtime")
dirent.Modifier = jsonGetStringMember(object, "modifier")
dirent.Size = jsonGetIntMember(object, "size")
seafdir.Entries = append(seafdir.Entries, dirent)
}
func jsonGetIntMember(object *C.json_t, key string) int64 {
cKey := C.CString(key)
integer := C.json_object_get(object, cKey)
C.free(unsafe.Pointer(cKey))
return int64(C.json_integer_value(integer))
}
func jsonGetStringMember(object *C.json_t, key string) string {
cKey := C.CString(key)
str := C.json_object_get(object, cKey)
C.free(unsafe.Pointer(cKey))
if unsafe.Pointer(str) == C.NULL {
return C.GoString((*C.char)(C.NULL))
}
return C.GoString(C.json_string_value(str))
}
func uncompress(p []byte) ([]byte, error) {
var c_out *C.uchar
var outlen C.int
if p == nil || len(p) == 0 {
err := fmt.Errorf("empty input for zlib")
return nil, err
}
ret := C.seaf_decompress((*C.uchar)(unsafe.Pointer(&p[0])), C.int(len(p)), &c_out, &outlen)
if ret < 0 {
err := fmt.Errorf("failed to uncompress data")
return nil, err
}
out := []byte(C.GoStringN((*C.char)(unsafe.Pointer(c_out)), outlen))
C.free(unsafe.Pointer(c_out))
return out, nil
}