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 @   无脑仔的小明  阅读(970)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2020-12-11 其他学习笔记
2020-12-11 QT创建代码编辑器(高亮显示)
点击右上角即可分享
微信分享提示