quickjs集成http功能

零、前言

  默认的quickjs,是js引擎,需要自己移植类似curl库,才能使quickjs有http请求功能。js引擎+一些本地功能调用=js运行时。

一、libcurl库

  这个库的安装或编译,也是比较麻烦的事情,特别是需要使其支持https访问,配置和编译更是麻烦。因此,还是使用上次提到的vcpkg。通过vcpkg search curl,然后根据需要安装对应支持ssl证书的。然后安装好的libcurl.dll libcrypto-3-x64.dll libssl-3-x64.dll 文件放到运行目录,同时也要复制对应include头文件到对应目录。

  一个curl例子

 1 #include <stdio.h>
 2 #include "curl/curl.h"
 3 
 4 
 5 size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
 6 {
 7   int len = size * nmemb;
 8     char buf[10240] = {'\0'};
 9     strncpy(buf, ptr, len);
10     printf("=========================get Data=====================\n");
11     printf("%s\n",buf);
12     printf("======================================================\n");
13   return len;
14 }
15 
16 int main()
17 {
18   CURL *curl;
19   CURLcode res;
20   curl = curl_easy_init();
21 
22   if (curl)
23   {
24     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
25     curl_easy_setopt(curl, CURLOPT_URL, "https://mock.apifox.com/m2/385371-0-default/33329355");
26     
27     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
28     curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
29     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);//忽略证书检查
30     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
31 
32     struct curl_slist *headers = NULL;
33     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
34     const char *data = "{}";
35     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
36     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData);
37 
38     res = curl_easy_perform(curl);
39     printf("res = %d\n", res);
40     if (res != CURLE_OK)
41       fprintf(stderr, "%s\n", curl_easy_strerror(res));
42 
43   }
44   curl_easy_cleanup(curl);
45   printf("Hello World!\n");
46   return 0;
47 }

  输出结果

1 D:\test\quickjs\examples\libuv>bin\main.exe
2 =========================get Data=====================
3 {"msg":"ok"}
4 ======================================================
5 res = 0
6 Hello World!

  CMakeList.txt

 1 cmake_minimum_required(VERSION 3.10)
 2 project(quickjs_libuv)
 3 
 4 SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 
 5 
 6 include_directories(${PROJECT_SOURCE_DIR})
 7 include_directories(${PROJECT_SOURCE_DIR}/include)
 8 
 9 link_directories(${PROJECT_SOURCE_DIR}/bin)
10 # add_executable(main main.c)
11 add_executable(main test_curl.c)
12 target_link_libraries(main quickjs uv curl)

二、quickjs绑定

   1. 通过使用curl_easy_setopt函数设置 CURLOPT_WRITEDATA,实现请求结果回调。

 1 size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
 2 {
 3   http_ctx_t *ctx = (http_ctx_t *)stream;
 4   int len = size * nmemb;
 5   char buf[10240] = {'\0'};
 6   strncpy(buf, ptr, len);
 7   printf("=========================get Data=====================\n");
 8   // printf("%s\n", buf);
 9   JSValue func = ctx->func;
10   JSValueConst this_obj = JS_UNDEFINED;
11   JSValueConst argv[1] = {JS_NewString(ctx->ctx, buf)};
12   JSValue ret = JS_Call(ctx->ctx, func, this_obj, 1, argv);
13   JS_FreeValue(ctx->ctx, func);
14   if(JS_IsException(ret)){
15     js_std_dump_error(ctx->ctx);
16   }
17   JS_FreeValue(ctx->ctx, argv[0]);
18   JS_FreeValue(ctx->ctx, ret);
19   printf("======================================================\n");
20   return len;
21 }

  2. 实现两种调用方式,一种是同步调用,那就是简单的在js绑定函数处调用上一步的curl_request。另一种是异步调用方式,利用libuv,实现异步调用curl_request。 

 1 static JSValue js_http_get_request(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
 2 {
 3   const char* url = JS_ToCString(ctx, argv[0]);
 4   JSValueConst func = argv[1];
 5   int sync = JS_ToBool(ctx, argv[2]);
 6   if(!JS_IsFunction(ctx, func)){
 7     printf("not a function\n");
 8     return JS_EXCEPTION;
 9   }
10   JS_FreeValue(ctx, argv[0]);
11   http_ctx_t *data = calloc(1, sizeof(http_ctx_t));
12   data->url = url;
13   data->ctx = ctx;
14   data->func = JS_DupValue(ctx, func);
15   if(sync){
16     printf("c sync req\n");
17     curl_main(url, data);
18   }else{
19     printf("c async req\n");
20     data->handle.data = data;
21     uv_timer_init(loop, &data->handle);
22     uv_timer_start(&data->handle, js_http_get_request_async, 0, 0);
23   }
24   return JS_UNDEFINED;
25 }
26 static const JSCFunctionListEntry js_http_funcs[] = {
27   JS_CFUNC_DEF("get_request", 1, js_http_get_request),
28 };
29 static int js_http_init(JSContext *ctx, JSModuleDef *m)
30 {
31   return JS_SetModuleExportList(ctx, m, js_http_funcs, countof(js_http_funcs));
32 }
33 JSModuleDef *js_init_module_http(JSContext *ctx, const char *module_name)
34 {
35   JSModuleDef *m = JS_NewCModule(ctx, module_name, js_http_init);
36   if (!m)
37     return NULL;
38   JS_AddModuleExportList(ctx, m, js_http_funcs, countof(js_http_funcs));
39   return m;
40 }

 

三、代码如下

  tes_curl.c

  1 #include <stdio.h>
  2 #include "curl/curl.h"
  3 #include "quickjs.h"
  4 #include "quickjs-libc.h"
  5 #include "uv.h"
  6 #include "cutils.h"
  7 #include <string.h>
  8 
  9 uv_loop_t *loop;
 10 typedef struct _http_ctx_t{
 11   JSContext *ctx;
 12   JSValueConst func;
 13   uv_timer_t handle;
 14   const char * url;
 15 } http_ctx_t;
 16 
 17 size_t readData(void *ptr, size_t size, size_t nmemb, void *stream)
 18 {
 19   http_ctx_t *ctx = (http_ctx_t *)stream;
 20   int len = size * nmemb;
 21   char buf[10240] = {'\0'};
 22   strncpy(buf, ptr, len);
 23   printf("=========================get Data=====================\n");
 24   // printf("%s\n", buf);
 25   JSValue func = ctx->func;
 26   JSValueConst this_obj = JS_UNDEFINED;
 27   JSValueConst argv[1] = {JS_NewString(ctx->ctx, buf)};
 28   JSValue ret = JS_Call(ctx->ctx, func, this_obj, 1, argv);
 29   JS_FreeValue(ctx->ctx, func);
 30   if(JS_IsException(ret)){
 31     js_std_dump_error(ctx->ctx);
 32   }
 33   JS_FreeValue(ctx->ctx, argv[0]);
 34   JS_FreeValue(ctx->ctx, ret);
 35   printf("======================================================\n");
 36   return len;
 37 }
 38 
 39 void curl_main(const char * url, http_ctx_t *ctx)
 40 {
 41   CURL *curl;
 42   CURLcode res;
 43   curl = curl_easy_init();
 44 
 45   if (curl)
 46   {
 47     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
 48     curl_easy_setopt(curl, CURLOPT_URL, url);
 49 
 50     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
 51     curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
 52     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 忽略证书检查
 53     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
 54 
 55     struct curl_slist *headers = NULL;
 56     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
 57     const char *data = "{}";
 58     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
 59     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, readData);
 60     curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx);
 61     // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
 62 
 63     res = curl_easy_perform(curl);
 64     // printf("res = %d\n", res);
 65     if (res != CURLE_OK)
 66       fprintf(stderr, "%s\n", curl_easy_strerror(res));
 67   }
 68   curl_easy_cleanup(curl);
 69 }
 70 /*js绑定*/
 71 static void js_http_get_request_async(uv_timer_t *handle)
 72 {
 73   http_ctx_t *data = (http_ctx_t *)handle->data;
 74   curl_main(data->url, data);
 75 }
 76 static JSValue js_http_get_request(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
 77 {
 78   const char* url = JS_ToCString(ctx, argv[0]);
 79   JSValueConst func = argv[1];
 80   int sync = JS_ToBool(ctx, argv[2]);
 81   if(!JS_IsFunction(ctx, func)){
 82     printf("not a function\n");
 83     return JS_EXCEPTION;
 84   }
 85   JS_FreeValue(ctx, argv[0]);
 86   http_ctx_t *data = calloc(1, sizeof(http_ctx_t));
 87   data->url = url;
 88   data->ctx = ctx;
 89   data->func = JS_DupValue(ctx, func);
 90   if(sync){
 91     printf("c sync req\n");
 92     curl_main(url, data);
 93   }else{
 94     printf("c async req\n");
 95     data->handle.data = data;
 96     uv_timer_init(loop, &data->handle);
 97     uv_timer_start(&data->handle, js_http_get_request_async, 0, 0);
 98   }
 99   return JS_UNDEFINED;
100 }
101 static const JSCFunctionListEntry js_http_funcs[] = {
102   JS_CFUNC_DEF("get_request", 1, js_http_get_request),
103 };
104 static int js_http_init(JSContext *ctx, JSModuleDef *m)
105 {
106   return JS_SetModuleExportList(ctx, m, js_http_funcs, countof(js_http_funcs));
107 }
108 JSModuleDef *js_init_module_http(JSContext *ctx, const char *module_name)
109 {
110   JSModuleDef *m = JS_NewCModule(ctx, module_name, js_http_init);
111   if (!m)
112     return NULL;
113   JS_AddModuleExportList(ctx, m, js_http_funcs, countof(js_http_funcs));
114   return m;
115 }
116 
117 JSContext *js_init_context()
118 {
119   JSRuntime *rt = JS_NewRuntime();
120   js_std_init_handlers(rt);
121   JSContext *ctx = JS_NewContext(rt);
122   js_init_module_os(ctx, "os");
123   js_init_module_std(ctx, "std");
124   js_init_module_http(ctx, "http");
125   return ctx;
126 }
127 void run_js(JSContext *ctx)
128 {
129   const char *str =
130       "import * as std from 'std'\n"
131       "import * as http from 'http'\n"
132       "import * as os from 'os'\n"
133       "globalThis.std = std\n"
134       "globalThis.http = http\n"
135       "globalThis.os = os\n"
136       "var console = {};\n"
137       "console.log = function(msg) {\n"
138       "  std.printf(msg + '\\n');\n"
139       "}\n"
140       "globalThis.console = console;\n";
141   JSValue init_compile = JS_Eval(
142       ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
143   js_module_set_import_meta(ctx, init_compile, 1, 1);
144   JSValue init_run = JS_EvalFunction(ctx, init_compile);
145 
146   const char *buf = "console.log('start sync req');\n"
147   "var url = 'https://mock.apifox.com/m2/385371-0-default/33329355';\n"
148   "http.get_request(url, function(data){\n"
149   "  console.log('sync->>' + data);\n"
150   "}, true);\n"
151   "console.log('end sync req');\n"
152   "console.log('start async req');\n"
153   "var url = 'https://mock.apifox.com/m2/385371-0-default/33329355';\n"
154   "http.get_request(url, function(data){\n"
155   "  console.log('async->>' + data);\n"
156   "}, false);\n"
157   "console.log('end async req');"
158   ;
159   JSValue result = JS_Eval(ctx, buf, strlen(buf), "test", JS_EVAL_TYPE_GLOBAL);
160   js_std_loop(ctx);
161   int clen;
162   if (JS_ToInt32(ctx, &clen, result) != 0)
163   {
164     js_std_dump_error(ctx);
165   }
166   printf("exit run_js\n");
167 }
168 
169 int main()
170 {
171   loop = uv_default_loop();
172   JSContext *ctx = js_init_context();
173   run_js(ctx);
174   while(uv_run(loop, UV_RUN_NOWAIT)){
175     ;
176   }
177   JS_FreeContext(ctx);
178   JS_FreeRuntime(JS_GetRuntime(ctx));
179   printf("Success!\n");
180   return 0;
181 }

  运行结果打印

 1 D:\test\quickjs\examples\libuv>bin\main.exe
 2 start sync req
 3 c sync req
 4 =========================get Data=====================
 5 sync->>{"msg":"ok"}
 6 ======================================================
 7 end sync req
 8 start async req
 9 c async req
10 end async req
11 exit run_js
12 =========================get Data=====================
13 async->>{"msg":"ok"}
14 ======================================================
15 QuickJS memory usage -- BigNum 2021-03-27 version, 64-bit, malloc limit: -1
16 
17   712 + 0   JSRuntime
18   488 + 0   JSContext
19    80 + 0   JSObject
20    40 + 0   JSString
21   136 + 0   JSFunctionBytecode
22 
23 JSObject classes
24 
25 NAME                    COUNT     SIZE
26 memory allocated          548    54711  (99.8 per block)
27 memory used               398    31337  (8 overhead, 58.7 average slack)
28 atoms                     307    22887  (74.6 per atom)
29 strings                     1       46  (46.0 per string)
30 Success!

 

 

 

本文地址:https://www.cnblogs.com/wunaozai/p/17888426.html

系列目录:https://www.cnblogs.com/wunaozai/p/17853962.html

posted @ 2023-12-11 14:33  无脑仔的小明  阅读(296)  评论(0编辑  收藏  举报