MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add better res/req for Ant.serve

+150 -49
+3 -1
include/ant.h
··· 35 35 jsval_t js_mkfalse(void); 36 36 jsval_t js_mknum(double); 37 37 38 + jsval_t js_getthis(struct js *); 39 + jsval_t js_get(struct js *, jsval_t, const char *); 40 + 38 41 jsval_t js_mkobj(struct js *); 39 42 jsval_t js_mkstr(struct js *, const void *, size_t); 40 43 jsval_t js_mkerr(struct js *js, const char *fmt, ...); 41 - jsval_t js_get(struct js *, jsval_t, const char *); 42 44 jsval_t js_mkfun(jsval_t (*fn)(struct js *, jsval_t *, int)); 43 45 jsval_t js_call(struct js *js, jsval_t func, jsval_t *args, int nargs); 44 46
+1
src/ant.c
··· 3735 3735 jsval_t js_mkobj(struct js *js) { return mkobj(js, 0); } 3736 3736 jsval_t js_glob(struct js *js) { (void) js; return mkval(T_OBJ, 0); } 3737 3737 jsval_t js_mkfun(jsval_t (*fn)(struct js *, jsval_t *, int)) { return mkval(T_CFUNC, (size_t) (void *) fn); } 3738 + jsval_t js_getthis(struct js *js) { return js->this_val; } 3738 3739 3739 3740 void js_set(struct js *js, jsval_t obj, const char *key, jsval_t val) { 3740 3741 if (vtype(obj) == T_OBJ) {
+125 -19
src/modules/server.c
··· 8 8 #include "modules/timer.h" 9 9 10 10 typedef struct { 11 + int status; 12 + char *body; 13 + char *content_type; 14 + int sent; 15 + } response_ctx_t; 16 + 17 + typedef struct { 11 18 struct js *js; 12 19 jsval_t handler; 13 20 int port; ··· 59 66 return promise_val; 60 67 } 61 68 69 + static jsval_t res_status(struct js *js, jsval_t *args, int nargs) { 70 + if (nargs < 1) return js_mkundef(); 71 + 72 + jsval_t this_val = js_getthis(js); 73 + jsval_t ctx_val = js_get(js, this_val, "__response_ctx"); 74 + if (js_type(ctx_val) != JS_NUM) return js_mkundef(); 75 + 76 + response_ctx_t *ctx = (response_ctx_t *)(unsigned long)js_getnum(ctx_val); 77 + if (!ctx) return js_mkundef(); 78 + 79 + if (js_type(args[0]) == JS_NUM) { 80 + ctx->status = (int)js_getnum(args[0]); 81 + } 82 + 83 + return js_mkundef(); 84 + } 85 + 86 + static jsval_t res_body(struct js *js, jsval_t *args, int nargs) { 87 + if (nargs < 1) return js_mkundef(); 88 + 89 + jsval_t this_val = js_getthis(js); 90 + jsval_t ctx_val = js_get(js, this_val, "__response_ctx"); 91 + if (js_type(ctx_val) != JS_NUM) return js_mkundef(); 92 + 93 + response_ctx_t *ctx = (response_ctx_t *)(unsigned long)js_getnum(ctx_val); 94 + if (!ctx) return js_mkundef(); 95 + 96 + if (js_type(args[0]) == JS_STR) { 97 + ctx->body = js_getstr(js, args[0], NULL); 98 + } 99 + 100 + if (nargs >= 2 && js_type(args[1]) == JS_NUM) { 101 + ctx->status = (int)js_getnum(args[1]); 102 + } 103 + 104 + if (nargs >= 3 && js_type(args[2]) == JS_STR) { 105 + ctx->content_type = js_getstr(js, args[2], NULL); 106 + } else { 107 + ctx->content_type = "text/plain"; 108 + } 109 + 110 + ctx->sent = 1; 111 + 112 + return js_mkundef(); 113 + } 114 + 115 + static jsval_t res_html(struct js *js, jsval_t *args, int nargs) { 116 + if (nargs < 1) return js_mkundef(); 117 + 118 + jsval_t this_val = js_getthis(js); 119 + jsval_t ctx_val = js_get(js, this_val, "__response_ctx"); 120 + if (js_type(ctx_val) != JS_NUM) return js_mkundef(); 121 + 122 + response_ctx_t *ctx = (response_ctx_t *)(unsigned long)js_getnum(ctx_val); 123 + if (!ctx) return js_mkundef(); 124 + 125 + if (js_type(args[0]) == JS_STR) { 126 + ctx->body = js_getstr(js, args[0], NULL); 127 + } 128 + 129 + if (nargs >= 2 && js_type(args[1]) == JS_NUM) { 130 + ctx->status = (int)js_getnum(args[1]); 131 + } 132 + 133 + ctx->content_type = "text/html"; 134 + ctx->sent = 1; 135 + 136 + return js_mkundef(); 137 + } 138 + 139 + static jsval_t res_json(struct js *js, jsval_t *args, int nargs) { 140 + if (nargs < 1) return js_mkundef(); 141 + 142 + jsval_t this_val = js_getthis(js); 143 + jsval_t ctx_val = js_get(js, this_val, "__response_ctx"); 144 + if (js_type(ctx_val) != JS_NUM) return js_mkundef(); 145 + 146 + response_ctx_t *ctx = (response_ctx_t *)(unsigned long)js_getnum(ctx_val); 147 + if (!ctx) return js_mkundef(); 148 + 149 + const char *json_str = js_str(js, args[0]); 150 + if (json_str) { 151 + ctx->body = (char *)json_str; 152 + } 153 + 154 + if (nargs >= 2 && js_type(args[1]) == JS_NUM) { 155 + ctx->status = (int)js_getnum(args[1]); 156 + } 157 + 158 + ctx->content_type = "application/json"; 159 + ctx->sent = 1; 160 + 161 + return js_mkundef(); 162 + } 163 + 62 164 static void http_handler(struct mg_connection *c, int ev, void *ev_data) { 63 165 if (ev == MG_EV_HTTP_MSG) { 64 166 http_server_t *server = (http_server_t *)c->fn_data; ··· 71 173 72 174 jsval_t result = js_mkundef(); 73 175 176 + response_ctx_t res_ctx = { 177 + .status = 200, 178 + .body = "", 179 + .content_type = "text/plain", 180 + .sent = 0 181 + }; 182 + 74 183 if (server->handler != 0 && js_type(server->handler) != JS_UNDEF) { 75 184 jsval_t req = js_mkobj(server->js); 76 185 js_set(server->js, req, "method", js_mkstr(server->js, hm->method.buf, hm->method.len)); ··· 79 188 js_set(server->js, req, "body", js_mkstr(server->js, hm->body.buf, hm->body.len)); 80 189 81 190 jsval_t res_obj = js_mkobj(server->js); 191 + js_set(server->js, res_obj, "__response_ctx", js_mknum((unsigned long)&res_ctx)); 192 + js_set(server->js, res_obj, "status", js_mkfun(res_status)); 193 + js_set(server->js, res_obj, "body", js_mkfun(res_body)); 194 + js_set(server->js, res_obj, "html", js_mkfun(res_html)); 195 + js_set(server->js, res_obj, "json", js_mkfun(res_json)); 196 + 82 197 jsval_t args[2] = {req, res_obj}; 83 198 84 199 result = js_call(server->js, server->handler, args, 2); 85 200 result = wait_for_promise(server->js, result); 201 + 202 + if (res_ctx.sent) { 203 + char headers[256]; 204 + snprintf(headers, sizeof(headers), "Content-Type: %s\r\n", 205 + res_ctx.content_type ? res_ctx.content_type : "text/plain"); 206 + mg_http_reply(c, res_ctx.status, headers, "%s", res_ctx.body ? res_ctx.body : ""); 207 + return; 208 + } 86 209 } 87 210 211 + // If we get here, no response was sent 88 212 if (js_type(result) == JS_ERR) { 89 213 fprintf(stderr, "Handler error: %s\n", js_str(server->js, result)); 90 214 mg_http_reply(c, 500, "Content-Type: text/plain\r\n", "Internal Server Error"); 91 - } else if (js_type(result) == JS_STR) { 92 - char *response = js_getstr(server->js, result, NULL); 93 - mg_http_reply(c, 200, "Content-Type: text/plain\r\n", "%s", response ? response : ""); 94 - } else if (js_type(result) == JS_PRIV) { 95 - jsval_t status_val = js_get(server->js, result, "status"); 96 - jsval_t body_val = js_get(server->js, result, "body"); 97 - 98 - int status = 200; 99 - if (js_type(status_val) == JS_NUM) { 100 - status = (int)js_getnum(status_val); 101 - } 102 - 103 - char *body_str = ""; 104 - if (js_type(body_val) == JS_STR) { 105 - body_str = js_getstr(server->js, body_val, NULL); 106 - } 107 - 108 - mg_http_reply(c, status, "Content-Type: text/plain\r\n", "%s", body_str ? body_str : ""); 109 215 } else { 110 - mg_http_reply(c, 200, "Content-Type: text/plain\r\n", "Hello from Ant HTTP Server!"); 216 + mg_http_reply(c, 404, "Content-Type: text/plain\r\n", "Not Found"); 111 217 } 112 218 } 113 219 }
+21 -29
tests/server/server.cjs
··· 1 1 const Radix3 = Ant.require('./radix3.cjs'); 2 2 const router = new Radix3(); 3 3 4 - router.insert('/', () => { 5 - return { 6 - status: 200, 7 - body: `Welcome to Ant HTTP Server with Radix3 Router! 8 - 4 + router.insert('/', c => { 5 + return c.body(`Welcome to Ant HTTP Server with Radix3 Router! 6 + 9 7 Available routes: 10 8 GET / 11 9 GET /hello 12 10 GET /status 13 - GET /echo 14 11 GET /users/:id 15 12 GET /users/:id/posts 16 13 GET /files/*path 17 14 GET /api/v1/users 18 - GET /api/v2/users` 19 - }; 15 + GET /api/v2/users`); 20 16 }); 21 17 22 - router.insert('/hello', async () => { 23 - return { status: 200, body: 'Hello, World!' }; 24 - }); 25 - 26 - router.insert('/status', async () => { 27 - return { status: 200, body: 'Server is running with Radix3 router!' }; 18 + router.insert('/hello', async c => { 19 + return c.body('Hello, World!'); 28 20 }); 29 21 30 - router.insert('/echo', async () => { 31 - return { status: 200, body: 'Echo endpoint - returns request details' }; 22 + router.insert('/status', async c => { 23 + return c.body('Server is running with Radix3 router!'); 32 24 }); 33 25 34 - router.insert('/users/:id', async p => { 35 - return { status: 200, body: 'User ID: ' + p.id }; 26 + router.insert('/users/:id', async c => { 27 + return c.body(`User ID: ${c.params.id}`); 36 28 }); 37 29 38 - router.insert('/users/:id/posts', async () => { 39 - return { status: 200, body: 'Posts for user: ' + p.id }; 30 + router.insert('/users/:id/posts', async c => { 31 + return c.body(`Posts for user: ${c.params.id}`); 40 32 }); 41 33 42 - router.insert('/api/v1/users', async () => { 43 - return { status: 200, body: 'API v1 users endpoint' }; 34 + router.insert('/api/v1/users', async c => { 35 + return c.json({ users: null }); 44 36 }); 45 37 46 - router.insert('/api/v2/users', async () => { 47 - return { status: 200, body: 'API v2 users endpoint' }; 38 + router.insert('/api/v2/users', async c => { 39 + return c.json({ users: [] }); 48 40 }); 49 41 50 - router.insert('/files/*path', async () => { 51 - return { status: 200, body: 'File path: ' + p.path }; 42 + router.insert('/files/*path', async c => { 43 + return c.html(p.params.path); 52 44 }); 53 45 54 46 router.printTree(); 55 47 Ant.println(''); 56 48 57 - async function handleRequest(req, _res) { 49 + async function handleRequest(req, res) { 58 50 Ant.println('request:', req.method, req.uri); 59 51 60 52 const { handler, params } = router.lookup(req.uri); 61 - if (handler) return handler(params); 53 + if (handler) return handler({ req, res, params }); 62 54 63 - return { status: 404, body: 'Not Found: ' + req.uri }; 55 + return res.body('not found: ' + req.uri, 404); 64 56 } 65 57 66 58 Ant.println('started on http://localhost:8000');