Browse Source

Rewrite websocket for Lua (Step 7 of ?)

bel 11 năm trước cách đây
mục cha
commit
e2f8196be3
2 tập tin đã thay đổi với 91 bổ sung50 xóa
  1. 70 48
      src/mod_lua.inl
  2. 21 2
      test/websocket.lua

+ 70 - 48
src/mod_lua.inl

@@ -704,17 +704,54 @@ enum {
     LUA_ENV_TYPE_LUA_WEBSOCKET = 2,
 };
 
-static void prepare_lua_environment(struct mg_context * ctx, struct mg_connection *conn, struct lua_websock_data *conn_list, lua_State *L, const char *script_name, int lua_env_type)
+static void prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
 {
-    const char * preload_file = ((conn != NULL) ? conn->ctx->config[LUA_PRELOAD_FILE] : NULL);
     char src_addr[IP_ADDR_STR_LEN] = "";
     int i;
 
-    extern void luaL_openlibs(lua_State *);
+    sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+
+    /* Export mg.request_info */
+    lua_pushstring(L, "request_info");
+    lua_newtable(L);
+    reg_string(L, "request_method", conn->request_info.request_method);
+    reg_string(L, "uri", conn->request_info.uri);
+    reg_string(L, "http_version", conn->request_info.http_version);
+    reg_string(L, "query_string", conn->request_info.query_string);
+    reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is deprecated, use remote_addr instead */
+    reg_string(L, "remote_addr", src_addr);
+    /* TODO: ip version */
+    reg_int(L, "remote_port", conn->request_info.remote_port);
+    reg_int(L, "num_headers", conn->request_info.num_headers);
+    reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
+
+    if (conn->request_info.remote_user != NULL) {
+        reg_string(L, "remote_user", conn->request_info.remote_user);
+        reg_string(L, "auth_type", "Digest");
+    }
 
-    if (conn != NULL) {
-        sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+    reg_boolean(L, "https", conn->ssl != NULL);
+
+    if (conn->status_code > 0) {
+        /* Lua error handler should show the status code */
+        reg_int(L, "status", conn->status_code);
+    }
+
+    lua_pushstring(L, "http_headers");
+    lua_newtable(L);
+    for (i = 0; i < conn->request_info.num_headers; i++) {
+        reg_string(L, conn->request_info.http_headers[i].name, conn->request_info.http_headers[i].value);
     }
+    lua_rawset(L, -3);
+
+    lua_rawset(L, -3);
+}
+
+static void prepare_lua_environment(struct mg_context * ctx, struct mg_connection *conn, struct lua_websock_data *conn_list, lua_State *L, const char *script_name, int lua_env_type)
+{
+    const char * preload_file = ((conn != NULL) ? conn->ctx->config[LUA_PRELOAD_FILE] : NULL);
+
+    extern void luaL_openlibs(lua_State *);
 
     luaL_openlibs(L);
 #ifdef USE_LUA_SQLITE3
@@ -806,40 +843,7 @@ static void prepare_lua_environment(struct mg_context * ctx, struct mg_connectio
 
     /* Export connection specific info */
     if (conn!=NULL) {
-        /* Export mg.request_info */
-        lua_pushstring(L, "request_info");
-        lua_newtable(L);
-        reg_string(L, "request_method", conn->request_info.request_method);
-        reg_string(L, "uri", conn->request_info.uri);
-        reg_string(L, "http_version", conn->request_info.http_version);
-        reg_string(L, "query_string", conn->request_info.query_string);
-        reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is deprecated, use remote_addr instead */
-        reg_string(L, "remote_addr", src_addr);
-        /* TODO: ip version */
-        reg_int(L, "remote_port", conn->request_info.remote_port);
-        reg_int(L, "num_headers", conn->request_info.num_headers);
-        reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
-
-        if (conn->request_info.remote_user != NULL) {
-            reg_string(L, "remote_user", conn->request_info.remote_user);
-            reg_string(L, "auth_type", "Digest");
-        }
-
-        reg_boolean(L, "https", conn->ssl != NULL);
-
-        if (conn->status_code > 0) {
-            /* Lua error handler should show the status code */
-            reg_int(L, "status", conn->status_code);
-        }
-
-        lua_pushstring(L, "http_headers");
-        lua_newtable(L);
-        for (i = 0; i < conn->request_info.num_headers; i++) {
-            reg_string(L, conn->request_info.http_headers[i].name, conn->request_info.http_headers[i].value);
-        }
-        lua_rawset(L, -3);
-
-        lua_rawset(L, -3);
+        prepare_lua_request_info(conn, L);
     }
 
     lua_setglobal(L, "mg");
@@ -1040,13 +1044,11 @@ static void * lua_websocket_new(const char * script, struct mg_connection *conn)
         prepare_lua_environment(conn->ctx, NULL, &((*shared_websock_list)->ws), (*shared_websock_list)->ws.state, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
         err = luaL_loadfile((*shared_websock_list)->ws.state, script);
         if (err != 0) {
-            mg_cry(conn, "Lua websocket: Error %i loading %s: %s", err, script,
-                lua_tostring((*shared_websock_list)->ws.state, -1));
+            websock_cry(conn, err, (*shared_websock_list)->ws.state, script, "load");
         }
         err = lua_pcall((*shared_websock_list)->ws.state, 0, 0, 0);
         if (err != 0) {
-            mg_cry(conn, "Lua websocket: Error %i initializing %s: %s", err, script,
-                lua_tostring((*shared_websock_list)->ws.state, -1));
+            websock_cry(conn, err, (*shared_websock_list)->ws.state, script, "init");
         }
     } else {
         /* inc ref count */
@@ -1059,8 +1061,7 @@ static void * lua_websocket_new(const char * script, struct mg_connection *conn)
     lua_getglobal((*shared_websock_list)->ws.state, "open");
     err = lua_pcall((*shared_websock_list)->ws.state, 0, 1, 0);
     if (err != 0) {
-        mg_cry(conn, "Lua websocket: Error %i calling open handler of %s: %s", err, script,
-            lua_tostring((*shared_websock_list)->ws.state, -1));
+        websock_cry(conn, err, (*shared_websock_list)->ws.state, script, "open handler");
     } else {
         if (lua_isboolean((*shared_websock_list)->ws.state, -1)) {
             ok = lua_toboolean((*shared_websock_list)->ws.state, -1);
@@ -1090,7 +1091,7 @@ static int lua_websocket_data(struct mg_connection * conn, void *ws_arg, int bit
     lua_pushlstring(ws->state, data, data_len);
     err = lua_pcall(ws->state, 2, 1, 0);
     if (err != 0) {
-        mg_cry(conn, "Lua websocket: Error %i calling data handler of %s", err, ws->script);
+        websock_cry(conn, err, ws->state, ws->script, "open handler");
     } else {
         if (lua_isboolean(ws->state, -1)) {
             ok = lua_toboolean(ws->state, -1);
@@ -1104,7 +1105,28 @@ static int lua_websocket_data(struct mg_connection * conn, void *ws_arg, int bit
 
 static int lua_websocket_ready(struct mg_connection * conn, void * ws_arg)
 {
-    return lua_websocket_data(conn, ws_arg, -1, NULL, 0);
+    struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+    int err, ok = 0;
+
+    assert(ws != NULL);
+    assert(ws->state != NULL);
+
+    (void)pthread_mutex_lock(&ws->ws_mutex);
+    lua_getglobal(ws->state, "ready");
+    lua_newtable(ws->state);
+    prepare_lua_request_info(conn, ws->state);
+    err = lua_pcall(ws->state, 1, 1, 0);
+    if (err != 0) {
+        websock_cry(conn, err, ws->state, ws->script, "ready handler");
+    } else {
+        if (lua_isboolean(ws->state, -1)) {
+            ok = lua_toboolean(ws->state, -1);
+        }
+        lua_pop(ws->state, 1);
+    }
+    (void)pthread_mutex_unlock(&ws->ws_mutex);
+
+    return ok;
 }
 
 static void lua_websocket_close(struct mg_connection * conn, void * ws_arg)
@@ -1121,7 +1143,7 @@ static void lua_websocket_close(struct mg_connection * conn, void * ws_arg)
     lua_getglobal(ws->state, "close");
     err = lua_pcall(ws->state, 0, 0, 0);
     if (err != 0) {
-        mg_cry(conn, "Lua websocket: Error %i calling close handler of %s", err, ws->script);
+        websock_cry(conn, err, ws->state, ws->script, "close handler");
     }
     for (i=0;i<ws->references;i++) {
         if (ws->conn[i]==conn) {

+ 21 - 2
test/websocket.lua

@@ -23,6 +23,25 @@ if not iswebsocket() then
 end
 
 
+-- Serialize table to string
+function ser(val)
+  local t
+  if type(val) == "table" then
+    for k,v in pairs(val) do
+      if t then 
+        t = t .. ", " .. ser(k) .. "=" .. ser(v)
+      else
+        t = "{" .. ser(k) .. "=" .. ser(v)
+      end
+    end
+    t = t .. "}"
+  else
+    t = tostring(val)
+  end
+  return t
+end
+
+
 -- Callback to reject a connection
 function open()
   trace("open")
@@ -30,8 +49,8 @@ function open()
 end
 
 -- Callback for "Websocket ready"
-function ready()
-  trace("ready")
+function ready(tab)
+  trace("ready: " .. ser(tab))
   mg.write("text", "Websocket ready")
   senddata()
   return true