Welcome! Log In Create A New Profile

Advanced

[njs] Introduced fs.promises API.

Dmitry Volyntsev
February 07, 2020 09:36AM
details: https://hg.nginx.org/njs/rev/03ec7b441da8
branches:
changeset: 1321:03ec7b441da8
user: Artem S. Povalyukhin <artem.povaluhin@gmail.com>
date: Sat Jan 25 21:55:50 2020 +0300
description:
Introduced fs.promises API.

diffstat:

src/njs_fs.c | 759 ++++++++++++++++++++++----------------------
src/njs_object.h | 2 +
src/njs_object_prop.c | 51 +++
src/test/njs_unit_test.c | 25 +-
test/js/fs_promises_001.js | 60 +++
test/njs_expect_test.exp | 9 +
6 files changed, 522 insertions(+), 384 deletions(-)

diffs (truncated from 1262 to 1000 lines):

diff -r f15c819f79e9 -r 03ec7b441da8 src/njs_fs.c
--- a/src/njs_fs.c Thu Feb 06 20:23:12 2020 +0300
+++ b/src/njs_fs.c Sat Jan 25 21:55:50 2020 +0300
@@ -25,39 +25,33 @@ typedef enum {
} njs_fs_writemode_t;


+typedef enum {
+ NJS_FS_ENC_INVALID,
+ NJS_FS_ENC_NONE,
+ NJS_FS_ENC_UTF8,
+} njs_fs_encoding_t;
+
+
typedef struct {
njs_str_t name;
int value;
} njs_fs_entry_t;


-typedef struct {
- int errn;
- const char *desc;
- const char *syscall;
-} njs_fs_ioerror_t;
-
+static njs_int_t njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data);

-static njs_int_t njs_fs_read_file(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t calltype);
-static njs_int_t njs_fs_write_file(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t magic);
-static njs_int_t njs_fs_rename_sync(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
+static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall,
+ const char *desc, njs_value_t *path, int errn, njs_value_t *retval);
+static njs_int_t njs_fs_result(njs_vm_t *vm, njs_value_t *result,
+ njs_index_t calltype, const njs_value_t* callback, njs_uint_t nargs);

-static njs_int_t njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data,
- njs_fs_ioerror_t *ioerror);
-static njs_int_t njs_fs_error(njs_vm_t *vm, const char *syscall,
- const char *description, njs_value_t *path, int errn, njs_value_t *retval);
-static int njs_fs_flags(njs_str_t *value);
-static mode_t njs_fs_mode(njs_value_t *value);
+static int njs_fs_flags(njs_vm_t *vm, njs_value_t *value, int default_flags);
+static mode_t njs_fs_mode(njs_vm_t *vm, njs_value_t *value,
+ mode_t default_mode);
+static njs_fs_encoding_t njs_fs_encoding(njs_vm_t *vm, njs_value_t *value);
+
static njs_int_t njs_fs_add_event(njs_vm_t *vm, const njs_value_t *callback,
- const njs_value_t *err, const njs_value_t *result);
-
-
-static const njs_value_t njs_fs_errno_string = njs_string("errno");
-static const njs_value_t njs_fs_path_string = njs_string("path");
-static const njs_value_t njs_fs_syscall_string = njs_string("syscall");
+ const njs_value_t *args, njs_uint_t nargs);


static njs_fs_entry_t njs_flags_table[] = {
@@ -101,130 +95,106 @@ njs_fs_path_arg(njs_vm_t *vm, const char
}


-njs_inline void
-njs_fs_set_ioerr(njs_fs_ioerror_t *ioerror, int errn, const char *desc,
- const char *syscall)
-{
- ioerror->errn = errn;
- ioerror->desc = desc;
- ioerror->syscall = syscall;
-}
-
-
static njs_int_t
njs_fs_read_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t calltype)
{
- int fd, flags;
- u_char *start;
- size_t size;
- ssize_t length;
- njs_str_t flag, encoding, data;
- njs_int_t ret;
- const char *path;
- struct stat sb;
- const njs_value_t *callback, *options;
- njs_value_t err;
- njs_object_prop_t *prop;
- njs_lvlhsh_query_t lhq;
- njs_fs_ioerror_t ioerror;
+ int fd, flags;
+ u_char *start;
+ size_t size;
+ ssize_t length;
+ njs_str_t data;
+ njs_int_t ret;
+ const char *file_path;
+ njs_value_t flag, encoding, retval, *callback, *options, *path;
+ struct stat sb;
+ njs_fs_encoding_t enc;

- ret = njs_fs_path_arg(vm, &path, njs_arg(args, nargs, 1),
- &njs_str_value("path"));
+ static const njs_value_t string_flag = njs_string("flag");
+ static const njs_value_t string_encoding = njs_string("encoding");
+
+ path = njs_arg(args, nargs, 1);
+ ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path"));
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}

+ callback = NULL;
+
options = njs_arg(args, nargs, 2);

- if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
+ if (calltype == NJS_FS_CALLBACK) {
callback = njs_arg(args, nargs, njs_min(nargs - 1, 3));
if (!njs_is_function(callback)) {
njs_type_error(vm, "\"callback\" must be a function");
return NJS_ERROR;
}
+
if (options == callback) {
- options = &njs_value_undefined;
- }
-
- } else {
- /* GCC complains about uninitialized callback. */
- callback = NULL;
- }
-
- flag.start = NULL;
- encoding.length = 0;
- encoding.start = NULL;
-
- if (njs_slow_path(!njs_is_undefined(options))) {
- if (njs_is_string(&args[2])) {
- njs_string_get(&args[2], &encoding);
-
- } else if (njs_is_object(&args[2])) {
- lhq.key_hash = NJS_FLAG_HASH;
- lhq.key = njs_str_value("flag");
- lhq.proto = &njs_object_hash_proto;
-
- ret = njs_lvlhsh_find(njs_object_hash(&args[2]), &lhq);
- if (ret == NJS_OK) {
- prop = lhq.value;
- njs_string_get(&prop->value, &flag);
- }
-
- lhq.key_hash = NJS_ENCODING_HASH;
- lhq.key = njs_str_value("encoding");
- lhq.proto = &njs_object_hash_proto;
-
- ret = njs_lvlhsh_find(njs_object_hash(&args[2]), &lhq);
- if (ret == NJS_OK) {
- prop = lhq.value;
- njs_string_get(&prop->value, &encoding);
- }
-
- } else {
- njs_type_error(vm, "Unknown options type "
- "(a string or object required)");
- return NJS_ERROR;
+ options = njs_value_arg(&njs_value_undefined);
}
}

- if (flag.start == NULL) {
- flag = njs_str_value("r");
+ njs_set_undefined(&flag);
+ njs_set_undefined(&encoding);
+
+ switch (options->type) {
+ case NJS_STRING:
+ encoding = *options;
+ break;
+
+ case NJS_UNDEFINED:
+ break;
+
+ default:
+ if (!njs_is_object(options)) {
+ njs_type_error(vm, "Unknown options type: \"%s\" "
+ "(a string or object required)",
+ njs_type_string(options->type));
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_property(vm, options, njs_value_arg(&string_flag),
+ &flag);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ ret = njs_value_property(vm, options, njs_value_arg(&string_encoding),
+ &encoding);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
}

- flags = njs_fs_flags(&flag);
+ flags = njs_fs_flags(vm, &flag, O_RDONLY);
if (njs_slow_path(flags == -1)) {
- njs_type_error(vm, "Unknown file open flags: \"%V\"", &flag);
return NJS_ERROR;
}

- if (encoding.length != 0
- && (encoding.length != 4 || memcmp(encoding.start, "utf8", 4) != 0))
- {
- njs_type_error(vm, "Unknown encoding: \"%V\"", &encoding);
+ enc = njs_fs_encoding(vm, &encoding);
+ if (njs_slow_path(enc == NJS_FS_ENC_INVALID)) {
return NJS_ERROR;
}

- njs_fs_set_ioerr(&ioerror, 0, NULL, NULL);
-
- fd = open(path, flags);
+ fd = open(file_path, flags);
if (njs_slow_path(fd < 0)) {
- njs_fs_set_ioerr(&ioerror, errno, strerror(errno), "open");
+ ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &retval);
goto done;
}

ret = fstat(fd, &sb);
if (njs_slow_path(ret == -1)) {
- njs_fs_set_ioerr(&ioerror, errno, strerror(errno), "fstat");
+ ret = njs_fs_error(vm, "stat", strerror(errno), path, errno, &retval);
goto done;
}

if (njs_slow_path(!S_ISREG(sb.st_mode))) {
- njs_fs_set_ioerr(&ioerror, 0, "File is not regular", "stat");
+ ret = njs_fs_error(vm, "stat", "File is not regular", path, 0, &retval);
goto done;
}

- if (encoding.length != 0) {
+ if (enc == NJS_FS_ENC_UTF8) {
length = sb.st_size;

if (length > NJS_STRING_MAP_STRIDE) {
@@ -244,21 +214,23 @@ njs_fs_read_file(njs_vm_t *vm, njs_value
size = sb.st_size;

if (njs_fast_path(size != 0)) {
- start = njs_string_alloc(vm, &vm->retval, size, length);
+ start = njs_string_alloc(vm, &retval, size, length);
if (njs_slow_path(start == NULL)) {
- goto fail;
+ ret = NJS_ERROR;
+ goto done;
}

data.start = start;
data.length = size;

- ret = njs_fs_fd_read(vm, fd, &data, &ioerror);
- if (ret != NJS_OK) {
- if (ioerror.desc != NULL) {
- goto done;
+ ret = njs_fs_fd_read(vm, fd, &data);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret == NJS_DECLINED) {
+ ret = njs_fs_error(vm, "read", strerror(errno), path, errno,
+ &retval);
}

- goto fail;
+ goto done;
}

start = data.start;
@@ -268,34 +240,34 @@ njs_fs_read_file(njs_vm_t *vm, njs_value

data.length = 0;

- ret = njs_fs_fd_read(vm, fd, &data, &ioerror);
- if (ret != NJS_OK) {
- if (ioerror.desc != NULL) {
- goto done;
+ ret = njs_fs_fd_read(vm, fd, &data);
+ if (njs_slow_path(ret != NJS_OK)) {
+ if (ret == NJS_DECLINED) {
+ ret = njs_fs_error(vm, "read", strerror(errno), path, errno,
+ &retval);
}

- goto fail;
+ goto done;
}

size = data.length;
start = data.start;

- ret = njs_string_new(vm, &vm->retval, start, size, length);
+ ret = njs_string_new(vm, &retval, start, size, length);
if (njs_slow_path(ret != NJS_OK)) {
- goto fail;
+ goto done;
}
}

- if (encoding.length != 0) {
+ if (enc == NJS_FS_ENC_UTF8) {
length = njs_utf8_length(start, size);

if (length >= 0) {
- njs_string_length_set(&vm->retval, length);
+ njs_string_length_set(&retval, length);

} else {
- njs_fs_set_ioerr(&ioerror, 0,
- "Non-UTF8 file, convertion is not implemented",
- NULL);
+ ret = njs_fs_error(vm, NULL, "Non-UTF8 file, convertion "
+ "is not implemented", path, 0, &retval);
goto done;
}
}
@@ -306,51 +278,8 @@ done:
(void) close(fd);
}

- if (njs_fast_path(calltype == NJS_FS_DIRECT)) {
- if (njs_slow_path(ioerror.desc != NULL)) {
- (void) njs_fs_error(vm, ioerror.syscall, ioerror.desc,
- &args[1], ioerror.errn, &vm->retval);
- return NJS_ERROR;
- }
-
- return NJS_OK;
- }
-
- if (calltype == NJS_FS_PROMISE) {
- njs_internal_error(vm, "promise callback is not implemented");
- return NJS_ERROR;
- }
-
- if (calltype == NJS_FS_CALLBACK) {
- if (njs_slow_path(ioerror.desc)) {
- ret = njs_fs_error(vm, ioerror.syscall, ioerror.desc,
- &args[1], ioerror.errn, &err);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- njs_set_undefined(&vm->retval);
-
- } else {
- njs_set_undefined(&err);
- }
-
- ret = njs_fs_add_event(vm, callback, &err, &vm->retval);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- njs_set_undefined(&vm->retval);
- return NJS_OK;
- }
-
- njs_internal_error(vm, "invalid calltype");
- return NJS_ERROR;
-
-fail:
-
- if (fd != -1) {
- (void) close(fd);
+ if (ret == NJS_OK) {
+ return njs_fs_result(vm, &retval, calltype, callback, 2);
}

return NJS_ERROR;
@@ -361,27 +290,30 @@ static njs_int_t
njs_fs_write_file(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t magic)
{
- int fd, flags;
- u_char *p, *end;
- mode_t md;
- ssize_t n;
- njs_str_t data, flag, encoding;
- njs_int_t ret;
- const char *path;
- njs_value_t *mode, err;
- njs_fs_calltype_t calltype;
- const njs_value_t *callback, *options;
- njs_fs_ioerror_t ioerror;
- njs_object_prop_t *prop;
- njs_lvlhsh_query_t lhq;
+ int fd, flags;
+ u_char *p, *end;
+ mode_t md;
+ ssize_t n;
+ njs_str_t content;
+ njs_int_t ret;
+ const char *file_path;
+ njs_value_t flag, mode, encoding, retval,
+ *path, *data, *callback, *options;
+ njs_fs_encoding_t enc;
+ njs_fs_calltype_t calltype;

- ret = njs_fs_path_arg(vm, &path, njs_arg(args, nargs, 1),
- &njs_str_value("path"));
+ static const njs_value_t string_flag = njs_string("flag");
+ static const njs_value_t string_mode = njs_string("mode");
+ static const njs_value_t string_encoding = njs_string("encoding");
+
+ path = njs_arg(args, nargs, 1);
+ ret = njs_fs_path_arg(vm, &file_path, path, &njs_str_value("path"));
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}

- if (njs_slow_path(!njs_is_string(njs_arg(args, nargs, 2)))) {
+ data = njs_arg(args, nargs, 2);
+ if (njs_slow_path(!njs_is_string(data))) {
njs_type_error(vm, "\"data\" must be a string");
return NJS_ERROR;
}
@@ -390,104 +322,84 @@ njs_fs_write_file(njs_vm_t *vm, njs_valu
calltype = magic & 3;
options = njs_arg(args, nargs, 3);

- if (njs_slow_path(calltype == NJS_FS_CALLBACK)) {
+ if (calltype == NJS_FS_CALLBACK) {
callback = njs_arg(args, nargs, njs_min(nargs - 1, 4));
if (!njs_is_function(callback)) {
njs_type_error(vm, "\"callback\" must be a function");
return NJS_ERROR;
}
+
if (options == callback) {
- options = &njs_value_undefined;
+ options = njs_value_arg(&njs_value_undefined);
}
}

- mode = NULL;
- /* GCC complains about uninitialized flag.length. */
- flag.length = 0;
- flag.start = NULL;
- encoding.length = 0;
- encoding.start = NULL;
-
- if (njs_slow_path(!njs_is_undefined(options))) {
- if (njs_is_string(&args[3])) {
- njs_string_get(&args[3], &encoding);
+ njs_set_undefined(&flag);
+ njs_set_undefined(&mode);
+ njs_set_undefined(&encoding);

- } else if (njs_is_object(&args[3])) {
- lhq.key_hash = NJS_FLAG_HASH;
- lhq.key = njs_str_value("flag");
- lhq.proto = &njs_object_hash_proto;
+ switch (options->type) {
+ case NJS_STRING:
+ encoding = *options;
+ break;

- ret = njs_lvlhsh_find(njs_object_hash(&args[3]), &lhq);
- if (ret == NJS_OK) {
- prop = lhq.value;
- njs_string_get(&prop->value, &flag);
- }
+ case NJS_UNDEFINED:
+ break;

- lhq.key_hash = NJS_ENCODING_HASH;
- lhq.key = njs_str_value("encoding");
- lhq.proto = &njs_object_hash_proto;
-
- ret = njs_lvlhsh_find(njs_object_hash(&args[3]), &lhq);
- if (ret == NJS_OK) {
- prop = lhq.value;
- njs_string_get(&prop->value, &encoding);
- }
+ default:
+ if (!njs_is_object(options)) {
+ njs_type_error(vm, "Unknown options type: \"%s\" "
+ "(a string or object required)",
+ njs_type_string(options->type));
+ return NJS_ERROR;
+ }

- lhq.key_hash = NJS_MODE_HASH;
- lhq.key = njs_str_value("mode");
- lhq.proto = &njs_object_hash_proto;
+ ret = njs_value_property(vm, options, njs_value_arg(&string_flag),
+ &flag);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }

- ret = njs_lvlhsh_find(njs_object_hash(&args[3]), &lhq);
- if (ret == NJS_OK) {
- prop = lhq.value;
- mode = &prop->value;
- }
+ ret = njs_value_property(vm, options, njs_value_arg(&string_mode),
+ &mode);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }

- } else {
- njs_type_error(vm, "Unknown options type "
- "(a string or object required)");
- return NJS_ERROR;
+ ret = njs_value_property(vm, options, njs_value_arg(&string_encoding),
+ &encoding);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
}
}

- if (flag.start != NULL) {
- flags = njs_fs_flags(&flag);
- if (njs_slow_path(flags == -1)) {
- njs_type_error(vm, "Unknown file open flags: \"%V\"", &flag);
- return NJS_ERROR;
- }
-
- } else {
- flags = O_CREAT | O_WRONLY;
- flags |= ((magic >> 2) == NJS_FS_APPEND) ? O_APPEND : O_TRUNC;
+ flags = njs_fs_flags(vm, &flag, O_CREAT | O_WRONLY);
+ if (njs_slow_path(flags == -1)) {
+ return NJS_ERROR;
}

- if (mode != NULL) {
- md = njs_fs_mode(mode);
+ flags |= ((magic >> 2) == NJS_FS_APPEND) ? O_APPEND : O_TRUNC;

- } else {
- md = 0666;
- }
-
- if (encoding.length != 0
- && (encoding.length != 4 || memcmp(encoding.start, "utf8", 4) != 0))
- {
- njs_type_error(vm, "Unknown encoding: \"%V\"", &encoding);
+ md = njs_fs_mode(vm, &mode, 0666);
+ if (njs_slow_path(md == (mode_t) -1)) {
return NJS_ERROR;
}

- njs_fs_set_ioerr(&ioerror, 0, NULL, NULL);
+ enc = njs_fs_encoding(vm, &encoding);
+ if (njs_slow_path(enc == NJS_FS_ENC_INVALID)) {
+ return NJS_ERROR;
+ }

- fd = open(path, flags, md);
+ fd = open(file_path, flags, md);
if (njs_slow_path(fd < 0)) {
- njs_fs_set_ioerr(&ioerror, errno, strerror(errno), "open");
+ ret = njs_fs_error(vm, "open", strerror(errno), path, errno, &retval);
goto done;
}

- njs_string_get(&args[2], &data);
+ njs_string_get(data, &content);

- p = data.start;
- end = p + data.length;
+ p = content.start;
+ end = p + content.length;

while (p < end) {
n = write(fd, p, end - p);
@@ -496,57 +408,27 @@ njs_fs_write_file(njs_vm_t *vm, njs_valu
continue;
}

- njs_fs_set_ioerr(&ioerror, errno, strerror(errno), "write");
+ ret = njs_fs_error(vm, "write", strerror(errno), path, errno,
+ &retval);
goto done;
}

p += n;
}

+ ret = NJS_OK;
+ njs_set_undefined(&retval);
+
done:

if (fd != -1) {
(void) close(fd);
}

- if (njs_fast_path(calltype == NJS_FS_DIRECT)) {
- if (njs_slow_path(ioerror.desc != NULL)) {
- (void) njs_fs_error(vm, ioerror.syscall, ioerror.desc, &args[1],
- ioerror.errn, &vm->retval);
- return NJS_ERROR;
- }
-
- njs_set_undefined(&vm->retval);
- return NJS_OK;
- }
-
- if (calltype == NJS_FS_PROMISE) {
- njs_internal_error(vm, "not implemented");
- return NJS_ERROR;
+ if (ret == NJS_OK) {
+ return njs_fs_result(vm, &retval, calltype, callback, 1);
}

- if (calltype == NJS_FS_CALLBACK) {
- if (ioerror.desc != NULL) {
- ret = njs_fs_error(vm, ioerror.syscall, ioerror.desc, &args[1],
- ioerror.errn, &err);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- } else {
- njs_set_undefined(&err);
- }
-
- ret = njs_fs_add_event(vm, callback, &err, NULL);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
- njs_set_undefined(&vm->retval);
- return NJS_OK;
- }
-
- njs_internal_error(vm, "invalid calltype");
return NJS_ERROR;
}

@@ -584,8 +466,7 @@ njs_fs_rename_sync(njs_vm_t *vm, njs_val


static njs_int_t
-njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data,
- njs_fs_ioerror_t *ioerror)
+njs_fs_fd_read(njs_vm_t *vm, int fd, njs_str_t *data)
{
u_char *p, *end, *start;
size_t size;
@@ -610,7 +491,6 @@ njs_fs_fd_read(njs_vm_t *vm, int fd, njs
n = read(fd, p, end - p);

if (njs_slow_path(n < 0)) {
- njs_fs_set_ioerr(ioerror, errno, strerror(errno), "read");
return NJS_DECLINED;
}

@@ -645,152 +525,224 @@ njs_fs_fd_read(njs_vm_t *vm, int fd, njs
}


+static int
+njs_fs_flags(njs_vm_t *vm, njs_value_t *value, int default_flags)
+{
+ njs_str_t flags;
+ njs_int_t ret;
+ njs_fs_entry_t *fl;
+
+ if (njs_is_undefined(value)) {
+ return default_flags;
+ }
+
+ ret = njs_value_to_string(vm, value, value);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return -1;
+ }
+
+ njs_string_get(value, &flags);
+
+ for (fl = &njs_flags_table[0]; fl->name.length != 0; fl++) {
+ if (njs_strstr_eq(&flags, &fl->name)) {
+ return fl->value;
+ }
+ }
+
+ njs_type_error(vm, "Unknown file open flags: \"%V\"", &flags);
+
+ return -1;
+}
+
+
+static mode_t
+njs_fs_mode(njs_vm_t *vm, njs_value_t *value, mode_t default_mode)
+{
+ uint32_t u32;
+ njs_int_t ret;
+
+ if (njs_is_undefined(value)) {
+ return default_mode;
+ }
+
+ ret = njs_value_to_uint32(vm, value, &u32);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return (mode_t) -1;
+ }
+
+ return (mode_t) u32;
+}
+
+
+static njs_fs_encoding_t
+njs_fs_encoding(njs_vm_t *vm, njs_value_t *value)
+{
+ njs_str_t enc;
+ njs_int_t ret;
+
+ if (njs_is_undefined(value)) {
+ return NJS_FS_ENC_NONE;
+ }
+
+ ret = njs_value_to_string(vm, value, value);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_FS_ENC_INVALID;
+ }
+
+ njs_string_get(value, &enc);
+
+ if (enc.length != 4 || memcmp(enc.start, "utf8", 4) != 0) {
+ njs_type_error(vm, "Unknown encoding: \"%V\"", &enc);
+ return NJS_FS_ENC_INVALID;
+ }
+
+ return NJS_FS_ENC_UTF8;
+}
+
+
static njs_int_t
njs_fs_error(njs_vm_t *vm, const char *syscall, const char *description,
njs_value_t *path, int errn, njs_value_t *retval)
{
- size_t size;
- njs_int_t ret;
- njs_value_t string, value;
- njs_object_t *error;
- njs_object_prop_t *prop;
- njs_lvlhsh_query_t lhq;
+ size_t size;
+ njs_int_t ret;
+ njs_value_t value;
+ njs_object_t *error;
+
+ static const njs_value_t string_errno = njs_string("errno");
+ static const njs_value_t string_path = njs_string("path");
+ static const njs_value_t string_syscall = njs_string("syscall");

size = description != NULL ? njs_strlen(description) : 0;

- ret = njs_string_new(vm, &string, (u_char *) description, size, size);
+ ret = njs_string_new(vm, &value, (u_char *) description, size, size);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}

- error = njs_error_alloc(vm, NJS_OBJ_TYPE_ERROR, NULL, &string);
+ error = njs_error_alloc(vm, NJS_OBJ_TYPE_ERROR, NULL, &value);
if (njs_slow_path(error == NULL)) {
return NJS_ERROR;
}

- lhq.replace = 0;
- lhq.pool = vm->mem_pool;
+ njs_set_object(retval, error);

if (errn != 0) {
- lhq.key = njs_str_value("errno");
- lhq.key_hash = NJS_ERRNO_HASH;
- lhq.proto = &njs_object_hash_proto;
-
njs_set_number(&value, errn);
-
- prop = njs_object_prop_alloc(vm, &njs_fs_errno_string, &value, 1);
- if (njs_slow_path(prop == NULL)) {
- return NJS_ERROR;
- }
-
- lhq.value = prop;
-
- ret = njs_lvlhsh_insert(&error->hash, &lhq);
+ ret = njs_value_property_set(vm, retval, njs_value_arg(&string_errno),
+ &value);
if (njs_slow_path(ret != NJS_OK)) {
- njs_internal_error(vm, "lvlhsh insert failed");
return NJS_ERROR;
}
}

if (path != NULL) {
- lhq.key = njs_str_value("path");
- lhq.key_hash = NJS_PATH_HASH;
- lhq.proto = &njs_object_hash_proto;
-
- prop = njs_object_prop_alloc(vm, &njs_fs_path_string, path, 1);
- if (njs_slow_path(prop == NULL)) {
- return NJS_ERROR;
- }
-
- lhq.value = prop;
-
- ret = njs_lvlhsh_insert(&error->hash, &lhq);
+ ret = njs_value_property_set(vm, retval, njs_value_arg(&string_path),
+ path);
if (njs_slow_path(ret != NJS_OK)) {
- njs_internal_error(vm, "lvlhsh insert failed");
return NJS_ERROR;
}
}

if (syscall != NULL) {
size = njs_strlen(syscall);
- ret = njs_string_new(vm, &string, (u_char *) syscall, size, size);
+ ret = njs_string_new(vm, &value, (u_char *) syscall, size, size);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}

- lhq.key = njs_str_value("sycall");
- lhq.key_hash = NJS_SYSCALL_HASH;
- lhq.proto = &njs_object_hash_proto;
-
- prop = njs_object_prop_alloc(vm, &njs_fs_syscall_string, &string, 1);
- if (njs_slow_path(prop == NULL)) {
- return NJS_ERROR;
- }
-
- lhq.value = prop;
-
- ret = njs_lvlhsh_insert(&error->hash, &lhq);
+ ret = njs_value_property_set(vm, retval, njs_value_arg(&string_syscall),
+ &value);
if (njs_slow_path(ret != NJS_OK)) {
- njs_internal_error(vm, "lvlhsh insert failed");
return NJS_ERROR;
}
}

- njs_set_object(retval, error);
-
return NJS_OK;
}


-static int
-njs_fs_flags(njs_str_t *value)
+static njs_int_t
+ngx_fs_promise_trampoline(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
{
- njs_fs_entry_t *fl;
+ njs_value_t value;

- for (fl = &njs_flags_table[0]; fl->name.length != 0; fl++) {
- if (njs_strstr_eq(value, &fl->name)) {
- return fl->value;
- }
- }
-
- return -1;
+ return njs_function_call(vm, njs_function(&args[1]), &njs_value_undefined,
+ &args[2], 1, &value);
}


-static mode_t
-njs_fs_mode(njs_value_t *value)
+static const njs_value_t promise_trampoline =
+ njs_native_function(ngx_fs_promise_trampoline, 2);
+
+
+static njs_int_t
+njs_fs_result(njs_vm_t *vm, njs_value_t *result, njs_index_t calltype,
+ const njs_value_t *callback, njs_uint_t nargs)
{
- switch (value->type) {
- case NJS_OBJECT_NUMBER:
- value = njs_object_value(value);
- /* Fall through. */
+ njs_int_t ret;
+ njs_value_t promise, callbacks[2], arguments[2];
+
+ switch (calltype) {
+ case NJS_FS_DIRECT:
+ vm->retval = *result;
+ return njs_is_error(result) ? NJS_ERROR : NJS_OK;
+
+ case NJS_FS_PROMISE:
+ ret = njs_vm_promise_create(vm, &promise, &callbacks[0]);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ arguments[0] = njs_is_error(result) ? callbacks[1] : callbacks[0];
+ arguments[1] = *result;

- case NJS_NUMBER:
- return (mode_t) njs_number(value);
+ ret = njs_fs_add_event(vm, njs_value_arg(&promise_trampoline),
+ njs_value_arg(&arguments), 2);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ vm->retval = promise;
+
+ return NJS_OK;
+
+ case NJS_FS_CALLBACK:
+ if (njs_is_error(result)) {
+ arguments[0] = *result;
+ njs_set_undefined(&arguments[1]);

- case NJS_OBJECT_STRING:
- value = njs_object_value(value);
- /* Fall through. */
+ } else {
+ njs_set_undefined(&arguments[0]);
+ arguments[1] = *result;
+ }

- case NJS_STRING:
- return (mode_t) njs_string_to_number(value, 0);
+ ret = njs_fs_add_event(vm, callback, njs_value_arg(&arguments),
+ nargs);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ njs_set_undefined(&vm->retval);
+
+ return NJS_OK;

default:
- return (mode_t) 0;
+ njs_internal_error(vm, "invalid calltype");
+
+ return NJS_ERROR;
}
}


static njs_int_t
njs_fs_add_event(njs_vm_t *vm, const njs_value_t *callback,
- const njs_value_t *err, const njs_value_t *result)
+ const njs_value_t *args, njs_uint_t nargs)
{
- njs_int_t nargs;
njs_event_t *event;
njs_vm_ops_t *ops;

- nargs = (result == NULL) ? 1 : 2;
-
ops = vm->options.ops;
if (njs_slow_path(ops == NULL)) {
njs_internal_error(vm, "not supported by host environment");
@@ -813,12 +765,7 @@ njs_fs_add_event(njs_vm_t *vm, const njs
goto memory_error;
}

- /* GC: retain */
- event->args[0] = *err;
-
- if (nargs == 2) {
- event->args[1] = *result;
- }
+ memcpy(event->args, args, sizeof(njs_value_t) * nargs);

event->host_event = ops->set_timer(vm->external, 0, event);
if (njs_slow_path(event->host_event == NULL)) {
@@ -836,6 +783,50 @@ memory_error:
}


+static const njs_object_prop_t njs_fs_promises_properties[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readFile"),
+ .value = njs_native_function2(njs_fs_read_file, 0, NJS_FS_PROMISE),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[njs] Introduced fs.promises API.

Dmitry Volyntsev 286 February 07, 2020 09:36AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 283
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready