1 /*
2 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3 */
4
5 /* #define LOG_NDEBUG 0
6 */
7
8 #include <stdint.h>
9
10 #include "amp_config.h"
11 #include "amp_defines.h"
12 #include "amp_task.h"
13 #include "repl.h"
14 #include "quickjs.h"
15 #include "quickjs_addon_common.h"
16 #include "aos_system.h"
17
18 #define MOD_STR "MODULE_REPL"
19
20 static JSClassID js_repl_class_id;
21
22 extern JSContext *js_get_context(void);
23
24 static uint16_t repl_init_flag = 0;
25 static uint16_t repl_js_cb_flag = 0;
26 static JSValue repl_js_cb_ref = JS_UNDEFINED;
27 static aos_sem_t g_repl_close_sem = NULL;
28
native_repl_open(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)29 static JSValue native_repl_open(JSContext *ctx, JSValueConst this_val,
30 int argc, JSValueConst *argv)
31 {
32 aos_repl_init(NULL);
33
34 return JS_NewInt32(ctx, 0);
35 }
36
native_repl_close(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)37 static JSValue native_repl_close(JSContext *ctx, JSValueConst this_val,
38 int argc, JSValueConst *argv)
39 {
40 int ret = 0;
41 repl_init_flag = 0;
42
43 aos_sem_wait(&g_repl_close_sem, AOS_WAIT_FOREVER);
44
45 ret = aos_repl_close();
46
47 return JS_NewInt32(ctx, ret);
48 }
49
native_repl_puts(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)50 static JSValue native_repl_puts(JSContext *ctx, JSValueConst this_val,
51 int argc, JSValueConst *argv)
52 {
53 int ret = -1;
54 int i = 0;
55 char *msg = NULL;
56 size_t msg_len = 0;
57 JSValue val;
58 const char *buf;
59
60 if(argc < 1)
61 {
62 amp_warn(MOD_STR, "parameter must be array");
63 goto out;
64 }
65
66 if(JS_IsString(argv[0])) {
67 buf = JS_ToCString(ctx, argv[0]);
68 msg_len = strlen(buf);
69 i = 1;
70 } else {
71 buf = JS_GetArrayBuffer(ctx, &msg_len, argv[0]);
72 if(!buf) {
73 amp_warn(MOD_STR, "parameter buffer is invalid, size: %d", msg_len);
74 goto out;
75 }
76 }
77
78 msg = (char *)aos_malloc(msg_len + 1);
79 if (!msg) {
80 amp_warn(MOD_STR, "allocate memory failed");
81 goto out;
82 }
83
84 memcpy(msg, buf, msg_len);
85
86 msg[msg_len] = 0;
87
88 ret = aos_repl_write(msg);
89 if (-1 == ret) {
90 amp_error(MOD_STR, "native_repl_write fail!");
91 }
92 aos_free(msg);
93 out:
94 if(i == 1) {
95 JS_FreeCString(ctx, buf);
96 }
97 return JS_NewInt32(ctx, ret);
98 }
99
native_repl_read(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)100 static JSValue native_repl_read(JSContext *ctx, JSValueConst this_val,
101 int argc, JSValueConst *argv)
102 {
103 uint32_t max_len = 16;
104 uint32_t recvsize = 0;
105
106 uint64_t pos, len;
107 size_t size;
108 size_t ret;
109 uint8_t *buf;
110
111 if (JS_ToIndex(ctx, &pos, argv[1]))
112 return JS_EXCEPTION;
113 if (JS_ToIndex(ctx, &len, argv[2]))
114 return JS_EXCEPTION;
115
116 buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
117 if (!buf)
118 return JS_EXCEPTION;
119 if ((uint32_t)pos + (uint32_t)len > size)
120 return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
121
122 ret = aos_repl_read(buf + (uint32_t)pos, (uint32_t)len, &recvsize);
123
124 return JS_NewInt32(ctx, ret);
125 }
126
repl_read_notify(void * arg)127 static void repl_read_notify(void *arg)
128 {
129 JSContext *ctx = js_get_context();
130 if (repl_init_flag) {
131 JSValue val = JS_Call(ctx, repl_js_cb_ref, JS_UNDEFINED, 0, NULL);
132 JS_FreeValue(ctx, val);
133 }
134 }
135
repl_task_entry()136 static void repl_task_entry()
137 {
138 aos_printf("repl task begin\n");
139 while (repl_init_flag) {
140 if(repl_js_cb_flag == 1) {
141 amp_task_schedule_call(repl_read_notify, NULL);
142 }
143 aos_msleep(100);
144 }
145 aos_printf("repl task exited\n");
146 aos_sem_signal(&g_repl_close_sem);
147 aos_task_exit(0);
148 }
149
repl_read_task_start(void)150 void repl_read_task_start(void)
151 {
152 aos_task_t repl_task;
153
154 if (!repl_init_flag) {
155 repl_init_flag = 1;
156 aos_task_new_ext(&repl_task, "amp repl task", repl_task_entry, NULL, 1024 * 4, AOS_DEFAULT_APP_PRI);
157 }
158 }
159
native_repl_setReadHandler(JSContext * ctx,JSValueConst this_val,int argc,JSValueConst * argv)160 static JSValue native_repl_setReadHandler(JSContext *ctx, JSValueConst this_val,
161 int argc, JSValueConst *argv)
162 {
163 JSValue read_cb = argv[0];
164 if (!JS_IsFunction(ctx, read_cb)) {
165 return JS_ThrowTypeError(ctx, "not a function");
166 }
167 repl_js_cb_ref = JS_DupValue(ctx, read_cb);
168 repl_js_cb_flag = 1;
169 return JS_NewInt32(ctx, 0);
170 }
171
module_repl_source_clean(void)172 static void module_repl_source_clean(void)
173 {
174 JSContext *ctx = js_get_context();
175 if (repl_js_cb_flag) {
176 JS_FreeValue(ctx, repl_js_cb_ref);
177 }
178 }
179
180 static JSClassDef js_repl_class = {
181 "REPL",
182 };
183
184 static const JSCFunctionListEntry js_repl_funcs[] = {
185 JS_CFUNC_DEF("open", 1, native_repl_open),
186 JS_CFUNC_DEF("read", 0, native_repl_read ),
187 JS_CFUNC_DEF("puts", 1, native_repl_puts ),
188 JS_CFUNC_DEF("exit", 0, native_repl_close ),
189 JS_CFUNC_DEF("setReadHandler", 1, native_repl_setReadHandler )
190 };
191
js_repl_init(JSContext * ctx,JSModuleDef * m)192 static int js_repl_init(JSContext *ctx, JSModuleDef *m)
193 {
194 JSValue proto;
195
196 JS_NewClassID(&js_repl_class_id);
197
198 JS_NewClass(JS_GetRuntime(ctx), js_repl_class_id, &js_repl_class);
199 proto = JS_NewObject(ctx);
200 JS_SetPropertyFunctionList(ctx, proto, js_repl_funcs,
201 countof(js_repl_funcs));
202 JS_SetClassProto(ctx, js_repl_class_id, proto);
203
204 return JS_SetModuleExportList(ctx, m, js_repl_funcs,
205 countof(js_repl_funcs));
206 }
207
js_init_module_repl(JSContext * ctx,const char * module_name)208 JSModuleDef *js_init_module_repl(JSContext *ctx, const char *module_name)
209 {
210 JSModuleDef *m;
211 m = JS_NewCModule(ctx, module_name, js_repl_init);
212 if (!m)
213 return NULL;
214 JS_AddModuleExportList(ctx, m, js_repl_funcs, countof(js_repl_funcs));
215 return m;
216 }
217
module_repl_register(void)218 void module_repl_register(void)
219 {
220 amp_debug(MOD_STR, "module_repl_register\n");
221 JSContext *ctx = js_get_context();
222
223 if (!g_repl_close_sem) {
224 if (aos_sem_new(&g_repl_close_sem, 0) != 0) {
225 amp_error(MOD_STR, "create repl sem fail");
226 return;
227 }
228 }
229
230 amp_module_free_register(module_repl_source_clean);
231
232 js_init_module_repl(ctx, "REPL");
233 }
234