xref: /unit/src/nodejs/unit-http/nxt_napi.h (revision 1132:9ac5b5f33ed9)
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, &param, &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