1 2 /* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6 #ifndef _NXT_NODEJS_NAPI_H_INCLUDED_ 7 #define _NXT_NODEJS_NAPI_H_INCLUDED_ 8 9 #include <node_api.h> 10 11 12 #ifdef __cplusplus 13 extern "C" { 14 #endif 15 16 #include "version.h" 17 #include <nxt_unit.h> 18 19 #if NXT_VERNUM != NXT_NODE_VERNUM 20 #error "libunit version mismatch." 21 #endif 22 23 #include <nxt_unit_response.h> 24 #include <nxt_unit_request.h> 25 26 27 #ifdef __cplusplus 28 } /* extern "C" */ 29 #endif 30 31 32 struct nxt_napi { 33 34 struct exception { exceptionnxt_napi::exception35 exception(const char *s) : str(s) { } 36 37 const char *str; 38 }; 39 40 nxt_napinxt_napi41 nxt_napi(napi_env env) : env_(env) { } 42 43 44 inline napi_value coerce_to_stringnxt_napi45 coerce_to_string(napi_value val) 46 { 47 napi_value res; 48 napi_status status; 49 50 status = napi_coerce_to_string(env_, val, &res); 51 if (status != napi_ok) { 52 throw exception("Failed to coerce to string"); 53 } 54 55 return res; 56 } 57 58 59 inline napi_value create_buffernxt_napi60 create_buffer(size_t size, void **data) 61 { 62 napi_value res; 63 napi_status status; 64 65 status = napi_create_buffer(env_, size, data, &res); 66 if (status != napi_ok) { 67 throw exception("Failed to create buffer"); 68 } 69 70 return res; 71 } 72 73 74 inline napi_value create_functionnxt_napi75 create_function(const char *name, size_t len, napi_callback cb, void *data) 76 { 77 napi_value res; 78 napi_status status; 79 80 status = napi_create_function(env_, name, len, cb, data, &res); 81 if (status != napi_ok) { 82 throw exception("Failed to create function"); 83 } 84 85 return res; 86 } 87 88 89 inline napi_value create_functionnxt_napi90 create_function(napi_callback cb) 91 { 92 return create_function(NULL, 0, cb, NULL); 93 } 94 95 96 inline napi_value create_objectnxt_napi97 create_object() 98 { 99 napi_value res; 100 napi_status status; 101 102 status = napi_create_object(env_, &res); 103 if (status != napi_ok) { 104 throw exception("Failed to create object"); 105 } 106 107 return res; 108 } 109 110 111 inline napi_ref 112 create_reference(napi_value val, int ref_count = 1) 113 { 114 napi_ref res; 115 napi_status status; 116 117 status = napi_create_reference(env_, val, ref_count, &res); 118 if (status != napi_ok) { 119 throw exception("Failed to create reference"); 120 } 121 122 return res; 123 } 124 125 126 inline napi_value create_string_latin1nxt_napi127 create_string_latin1(const char *str, size_t len) 128 { 129 napi_value res; 130 napi_status status; 131 132 status = napi_create_string_latin1(env_, str, len, &res); 133 if (status != napi_ok) { 134 throw exception("Failed to create latin1 string"); 135 } 136 137 return res; 138 } 139 140 141 inline napi_value create_string_latin1nxt_napi142 create_string_latin1(nxt_unit_sptr_t &str, size_t len) 143 { 144 const char *p; 145 146 p = (const char *) nxt_unit_sptr_get(&str); 147 148 return create_string_latin1(p, len); 149 } 150 151 152 inline napi_value define_classnxt_napi153 define_class(const char *name, napi_callback ctor, size_t prop_count, 154 const napi_property_descriptor* props) 155 { 156 napi_value res; 157 napi_status status; 158 159 status = napi_define_class(env_, name, NAPI_AUTO_LENGTH, ctor, nullptr, 160 prop_count, props, &res); 161 if (status != napi_ok) { 162 throw exception("Failed to define class"); 163 } 164 165 return res; 166 } 167 168 169 inline void delete_referencenxt_napi170 delete_reference(napi_ref ref) 171 { 172 napi_delete_reference(env_, ref); 173 } 174 175 176 inline uint32_t get_array_lengthnxt_napi177 get_array_length(napi_value val) 178 { 179 uint32_t res; 180 napi_status status; 181 182 status = napi_get_array_length(env_, val, &res); 183 if (status != napi_ok) { 184 throw exception("Failed to get array length"); 185 } 186 187 return res; 188 } 189 190 191 inline void * get_buffer_infonxt_napi192 get_buffer_info(napi_value val, size_t &size) 193 { 194 void *res; 195 napi_status status; 196 197 status = napi_get_buffer_info(env_, val, &res, &size); 198 if (status != napi_ok) { 199 throw exception("Failed to get buffer info"); 200 } 201 202 return res; 203 } 204 205 206 inline napi_value get_cb_infonxt_napi207 get_cb_info(napi_callback_info info, size_t &argc, napi_value *argv) 208 { 209 napi_value res; 210 napi_status status; 211 212 status = napi_get_cb_info(env_, info, &argc, argv, &res, nullptr); 213 if (status != napi_ok) { 214 throw exception("Failed to get arguments from js"); 215 } 216 217 return res; 218 } 219 220 221 inline napi_value get_cb_infonxt_napi222 get_cb_info(napi_callback_info info) 223 { 224 napi_value res; 225 napi_status status; 226 227 status = napi_get_cb_info(env_, info, nullptr, nullptr, &res, nullptr); 228 if (status != napi_ok) { 229 throw exception("Failed to get arguments from js"); 230 } 231 232 return res; 233 } 234 235 236 inline napi_value get_cb_infonxt_napi237 get_cb_info(napi_callback_info info, napi_value &arg) 238 { 239 size_t argc; 240 napi_value res; 241 242 argc = 1; 243 res = get_cb_info(info, argc, &arg); 244 245 if (argc != 1) { 246 throw exception("Wrong args count. Expected 1"); 247 } 248 249 return res; 250 } 251 252 253 inline napi_value get_elementnxt_napi254 get_element(napi_value obj, uint32_t i) 255 { 256 napi_value res; 257 napi_status status; 258 259 status = napi_get_element(env_, obj, i, &res); 260 if (status != napi_ok) { 261 throw exception("Failed to get element"); 262 } 263 264 return res; 265 } 266 267 268 inline napi_value get_named_propertynxt_napi269 get_named_property(napi_value obj, const char *name) 270 { 271 napi_value res; 272 napi_status status; 273 274 status = napi_get_named_property(env_, obj, name, &res); 275 if (status != napi_ok) { 276 throw exception("Failed to get named property"); 277 } 278 279 return res; 280 } 281 282 283 inline napi_value get_new_targetnxt_napi284 get_new_target(napi_callback_info info) 285 { 286 napi_value res; 287 napi_status status; 288 289 status = napi_get_new_target(env_, info, &res); 290 if (status != napi_ok) { 291 throw exception("Failed to get new target"); 292 } 293 294 return res; 295 } 296 297 298 inline napi_value get_propertynxt_napi299 get_property(napi_value val, napi_value key) 300 { 301 napi_value res; 302 napi_status status; 303 304 status = napi_get_property(env_, val, key, &res); 305 if (status != napi_ok) { 306 throw exception("Failed to get property"); 307 } 308 309 return res; 310 } 311 312 313 inline napi_value get_property_namesnxt_napi314 get_property_names(napi_value val) 315 { 316 napi_value res; 317 napi_status status; 318 319 status = napi_get_property_names(env_, val, &res); 320 if (status != napi_ok) { 321 throw exception("Failed to get property names"); 322 } 323 324 return res; 325 } 326 327 328 inline napi_value get_reference_valuenxt_napi329 get_reference_value(napi_ref ref) 330 { 331 napi_value res; 332 napi_status status; 333 334 status = napi_get_reference_value(env_, ref, &res); 335 if (status != napi_ok) { 336 throw exception("Failed to get reference value"); 337 } 338 339 return res; 340 } 341 342 343 inline nxt_unit_request_info_t * get_request_infonxt_napi344 get_request_info(napi_value obj) 345 { 346 return (nxt_unit_request_info_t *) unwrap(obj); 347 } 348 349 350 inline uint32_t get_value_boolnxt_napi351 get_value_bool(napi_value obj) 352 { 353 bool res; 354 napi_status status; 355 356 status = napi_get_value_bool(env_, obj, &res); 357 if (status != napi_ok) { 358 throw exception("Failed to get bool"); 359 } 360 361 return res; 362 } 363 364 365 inline size_t get_value_string_latin1nxt_napi366 get_value_string_latin1(napi_value val, char *buf, size_t bufsize) 367 { 368 size_t res; 369 napi_status status; 370 371 status = napi_get_value_string_latin1(env_, val, buf, bufsize, &res); 372 if (status != napi_ok) { 373 throw exception("Failed to get string latin1"); 374 } 375 376 return res; 377 } 378 379 380 inline uint32_t get_value_uint32nxt_napi381 get_value_uint32(napi_value obj) 382 { 383 uint32_t res; 384 napi_status status; 385 386 status = napi_get_value_uint32(env_, obj, &res); 387 if (status != napi_ok) { 388 throw exception("Failed to get uint32_t"); 389 } 390 391 return res; 392 } 393 394 395 inline size_t get_value_string_utf8nxt_napi396 get_value_string_utf8(napi_value val, char *buf, size_t bufsize) 397 { 398 size_t res; 399 napi_status status; 400 401 status = napi_get_value_string_utf8(env_, val, buf, bufsize, &res); 402 if (status != napi_ok) { 403 throw exception("Failed to get string utf8"); 404 } 405 406 return res; 407 } 408 409 410 inline bool is_arraynxt_napi411 is_array(napi_value val) 412 { 413 bool res; 414 napi_status status; 415 416 status = napi_is_array(env_, val, &res); 417 if (status != napi_ok) { 418 throw exception("Failed to confirm value is array"); 419 } 420 421 return res; 422 } 423 424 425 inline bool is_buffernxt_napi426 is_buffer(napi_value val) 427 { 428 bool res; 429 napi_status status; 430 431 status = napi_is_buffer(env_, val, &res); 432 if (status != napi_ok) { 433 throw exception("Failed to confirm value is buffer"); 434 } 435 436 return res; 437 } 438 439 440 inline napi_value make_callbacknxt_napi441 make_callback(napi_async_context ctx, napi_value val, napi_value func, 442 int argc, const napi_value *argv) 443 { 444 napi_value res, ex; 445 napi_status status; 446 447 status = napi_make_callback(env_, ctx, val, func, argc, argv, &res); 448 if (status != napi_ok) { 449 if (status != napi_pending_exception) { 450 throw exception("Failed to make callback"); 451 } 452 453 status = napi_get_and_clear_last_exception(env_, &ex); 454 if (status != napi_ok) { 455 throw exception("Failed to get and clear last exception"); 456 } 457 458 /* Logging a description of the error and call stack. */ 459 status = napi_fatal_exception(env_, ex); 460 if (status != napi_ok) { 461 throw exception("Failed napi_fatal_exception()"); 462 } 463 } 464 465 return res; 466 } 467 468 469 inline napi_value make_callbacknxt_napi470 make_callback(napi_async_context ctx, napi_value val, napi_value func) 471 { 472 return make_callback(ctx, val, func, 0, NULL); 473 } 474 475 476 inline napi_value make_callbacknxt_napi477 make_callback(napi_async_context ctx, napi_value val, napi_value func, 478 napi_value arg1) 479 { 480 return make_callback(ctx, val, func, 1, &arg1); 481 } 482 483 484 inline napi_value make_callbacknxt_napi485 make_callback(napi_async_context ctx, napi_value val, napi_value func, 486 napi_value arg1, napi_value arg2) 487 { 488 napi_value args[2] = { arg1, arg2 }; 489 490 return make_callback(ctx, val, func, 2, args); 491 } 492 493 494 inline napi_value make_callbacknxt_napi495 make_callback(napi_async_context ctx, napi_value val, napi_value func, 496 napi_value arg1, napi_value arg2, napi_value arg3) 497 { 498 napi_value args[3] = { arg1, arg2, arg3 }; 499 500 return make_callback(ctx, val, func, 3, args); 501 } 502 503 504 inline napi_value new_instancenxt_napi505 new_instance(napi_value ctor) 506 { 507 napi_value res; 508 napi_status status; 509 510 status = napi_new_instance(env_, ctor, 0, NULL, &res); 511 if (status != napi_ok) { 512 throw exception("Failed to create instance"); 513 } 514 515 return res; 516 } 517 518 519 inline napi_value new_instancenxt_napi520 new_instance(napi_value ctor, napi_value param) 521 { 522 napi_value res; 523 napi_status status; 524 525 status = napi_new_instance(env_, ctor, 1, ¶m, &res); 526 if (status != napi_ok) { 527 throw exception("Failed to create instance"); 528 } 529 530 return res; 531 } 532 533 534 inline napi_value new_instancenxt_napi535 new_instance(napi_value ctor, napi_value param1, napi_value param2) 536 { 537 napi_value res; 538 napi_status status; 539 napi_value param[2] = { param1, param2 }; 540 541 status = napi_new_instance(env_, ctor, 2, param, &res); 542 if (status != napi_ok) { 543 throw exception("Failed to create instance"); 544 } 545 546 return res; 547 } 548 549 550 inline void set_elementnxt_napi551 set_element(napi_value obj, uint32_t i, napi_value val) 552 { 553 napi_status status; 554 555 status = napi_set_element(env_, obj, i, val); 556 if (status != napi_ok) { 557 throw exception("Failed to set element"); 558 } 559 } 560 561 562 inline void set_named_propertynxt_napi563 set_named_property(napi_value obj, const char *name, napi_value val) 564 { 565 napi_status status; 566 567 status = napi_set_named_property(env_, obj, name, val); 568 if (status != napi_ok) { 569 throw exception("Failed to set named property"); 570 } 571 } 572 573 574 inline void set_named_propertynxt_napi575 set_named_property(napi_value obj, const char *name, napi_callback cb) 576 { 577 set_named_property(obj, name, create_function(cb)); 578 } 579 580 581 inline napi_value set_named_propertynxt_napi582 set_named_property(napi_value obj, const char *name, nxt_unit_sptr_t &val, 583 size_t len) 584 { 585 napi_value str; 586 587 str = create_string_latin1(val, len); 588 589 set_named_property(obj, name, str); 590 591 return str; 592 } 593 594 595 template<typename T> 596 inline void set_named_propertynxt_napi597 set_named_property(napi_value obj, const char *name, T val) 598 { 599 set_named_property(obj, name, create(val)); 600 } 601 602 603 inline napi_value createnxt_napi604 create(int32_t val) 605 { 606 napi_value ptr; 607 napi_status status; 608 609 status = napi_create_int32(env_, val, &ptr); 610 if (status != napi_ok) { 611 throw exception("Failed to create int32"); 612 } 613 614 return ptr; 615 } 616 617 618 inline napi_value createnxt_napi619 create(uint32_t val) 620 { 621 napi_value ptr; 622 napi_status status; 623 624 status = napi_create_uint32(env_, val, &ptr); 625 if (status != napi_ok) { 626 throw exception("Failed to create uint32"); 627 } 628 629 return ptr; 630 } 631 632 633 inline napi_value createnxt_napi634 create(int64_t val) 635 { 636 napi_value ptr; 637 napi_status status; 638 639 status = napi_create_int64(env_, val, &ptr); 640 if (status != napi_ok) { 641 throw exception("Failed to create int64"); 642 } 643 644 return ptr; 645 } 646 647 648 inline void remove_wrapnxt_napi649 remove_wrap(napi_ref& ref) 650 { 651 if (ref != nullptr) { 652 remove_wrap(get_reference_value(ref)); 653 ref = nullptr; 654 } 655 } 656 657 658 inline void * remove_wrapnxt_napi659 remove_wrap(napi_value val) 660 { 661 void *res; 662 napi_status status; 663 664 status = napi_remove_wrap(env_, val, &res); 665 if (status != napi_ok) { 666 throw exception("Failed to remove_wrap"); 667 } 668 669 return res; 670 } 671 672 673 inline void throw_errornxt_napi674 throw_error(const char *str) 675 { 676 napi_throw_error(env_, NULL, str); 677 } 678 679 680 inline void throw_errornxt_napi681 throw_error(const exception &e) 682 { 683 napi_throw_error(env_, NULL, e.str); 684 } 685 686 687 inline napi_valuetype type_ofnxt_napi688 type_of(napi_value val) 689 { 690 napi_status status; 691 napi_valuetype res; 692 693 status = napi_typeof(env_, val, &res); 694 if (status != napi_ok) { 695 throw exception("Failed to get typeof"); 696 } 697 698 return res; 699 } 700 701 702 inline void * unwrapnxt_napi703 unwrap(napi_value val) 704 { 705 void *res; 706 napi_status status; 707 708 status = napi_unwrap(env_, val, &res); 709 if (status != napi_ok) { 710 throw exception("Failed to unwrap"); 711 } 712 713 return res; 714 } 715 716 717 inline napi_ref 718 wrap(napi_value val, void *obj, napi_finalize fin_cb, void *hint = nullptr) 719 { 720 napi_ref res; 721 napi_status status; 722 723 status = napi_wrap(env_, val, obj, fin_cb, hint, &res); 724 if (status != napi_ok) { 725 throw exception("Failed to wrap"); 726 } 727 728 return res; 729 } 730 731 732 inline napi_envnxt_napi733 operator napi_env() 734 { 735 return env_; 736 } 737 738 envnxt_napi739 napi_env env() 740 { 741 return env_; 742 } 743 744 private: 745 napi_env env_; 746 }; 747 748 749 struct nxt_handle_scope : public nxt_napi { nxt_handle_scopenxt_handle_scope750 nxt_handle_scope(napi_env env) : nxt_napi(env) 751 { 752 napi_status status; 753 754 status = napi_open_handle_scope(env, &scope_); 755 if (status != napi_ok) { 756 throw exception("Failed to open handle scope"); 757 } 758 } 759 ~nxt_handle_scopenxt_handle_scope760 ~nxt_handle_scope() 761 { 762 napi_status status; 763 764 status = napi_close_handle_scope(env(), scope_); 765 if (status != napi_ok) { 766 throw_error("Failed to close handle scope"); 767 } 768 } 769 770 private: 771 napi_handle_scope scope_; 772 }; 773 774 775 struct nxt_async_context : public nxt_napi { nxt_async_contextnxt_async_context776 nxt_async_context(napi_env env, const char *name) : 777 nxt_napi(env) 778 { 779 napi_value name_val; 780 napi_status status; 781 782 name_val = create_string_latin1(name, NAPI_AUTO_LENGTH); 783 784 status = napi_async_init(env, NULL, name_val, &context_); 785 if (status != napi_ok) { 786 throw exception("Failed to init async object"); 787 } 788 } 789 napi_async_contextnxt_async_context790 operator napi_async_context() { 791 return context_; 792 } 793 ~nxt_async_contextnxt_async_context794 ~nxt_async_context() 795 { 796 napi_status status; 797 798 status = napi_async_destroy(env(), context_); 799 if (status != napi_ok) { 800 throw_error("Failed to destroy async object"); 801 } 802 } 803 804 private: 805 napi_async_context context_; 806 }; 807 808 809 struct nxt_callback_scope : public nxt_napi { nxt_callback_scopenxt_callback_scope810 nxt_callback_scope(nxt_async_context& ctx) : 811 nxt_napi(ctx.env()) 812 { 813 napi_value resource; 814 napi_status status; 815 816 resource = create_object(); 817 818 status = napi_open_callback_scope(env(), resource, ctx, &scope_); 819 if (status != napi_ok) { 820 throw exception("Failed to open callback scope"); 821 } 822 } 823 ~nxt_callback_scopenxt_callback_scope824 ~nxt_callback_scope() 825 { 826 napi_status status; 827 828 status = napi_close_callback_scope(env(), scope_); 829 if (status != napi_ok) { 830 throw_error("Failed to close callback scope"); 831 } 832 } 833 834 private: 835 napi_callback_scope scope_; 836 }; 837 838 839 #endif /* _NXT_NODEJS_NAPI_H_INCLUDED_ */ 840