Procházet zdrojové kódy

Allow Lua background scripts to use timers (Step 2/2)

bel2125 před 4 roky
rodič
revize
b5871a9138
2 změnil soubory, kde provedl 83 přidání a 23 odebrání
  1. 19 3
      docs/UserManual.md
  2. 64 20
      src/civetweb.c

+ 19 - 3
docs/UserManual.md

@@ -584,7 +584,7 @@ certificate with the same subject name they should have extensions ".0", ".1",
 ### ssl\_cache\_timeout `-1`
 Allow caching of SSL/TLS sessions, so HTTPS connection from the same client
 to the same server can be established faster. A configuration value >0 activates
-session caching. The configuration value is the maximum lifetime of a cached 
+session caching. The configuration value is the maximum lifetime of a cached
 session in seconds.
 The default is to deactivated session caching.
 
@@ -964,8 +964,7 @@ header and generate any kind of file.
 CivetWeb offers support for websockets in Lua as well. In contrast to plain
 Lua scripts and Lua server pages, Lua websocket scripts are shared by all clients.
 
-Lua websocket scripts must define a few functions:
-    open(arg)    -- callback to accept or reject a connection
+Lua websocket scripts must define the following functions:
     ready(arg)   -- called after a connection has been established
     data(arg)    -- called when the server receives data from the client
     close(arg)   -- called when a websocket connection is closed
@@ -981,6 +980,23 @@ An example is shown in
 [websocket.lua](https://github.com/civetweb/civetweb/blob/master/test/websocket.lua).
 
 ##Lua background script
+The Lua background script is loaded when the server is starting,
+before any client is able to connect. It can be used for preparation and
+maintenance tasks, e.g., for preparing the web contents, cleaning log files,
+etc.
+
+The Name of the script file including path is configured as `lua_background_script`. 
+Additional parameters can be supplied using `lua_background_script_params`.
+
+The background script is loaded before the server is ready to start.
+It may return a boolean value. If "false" in returned, the server will
+not be started. Since the server is not fully initialized when the script is loaded,
+some features of the "mg" library are not available yet. Use the "start()" callbacks
+function instead.
+
+A Lua background script may define the following functions:
+    start()      -- called wnen the server is started
+    stop()       -- called when the server is stopped
 
 
 # Using CGI

+ 64 - 20
src/civetweb.c

@@ -2468,6 +2468,7 @@ static const char month_names[][4] = {"Jan",
                                       "Dec"};
 #endif /* !NO_CACHING */
 
+
 /* Unified socket address. For IPv6 support, add IPv6 address structure in
  * the union u. */
 union usa {
@@ -2478,6 +2479,7 @@ union usa {
 #endif
 };
 
+
 #if defined(USE_IPV6)
 #define USA_IN_PORT_UNSAFE(s)                                                  \
 	(((s)->sa.sa_family == AF_INET6) ? (s)->sin6.sin6_port : (s)->sin.sin_port)
@@ -4164,7 +4166,6 @@ mg_construct_local_link(const struct mg_connection *conn,
 	if ((buflen < 1) || (buf == 0) || (conn == 0)) {
 		return -1;
 	} else {
-
 		int truncated = 0;
 		const struct mg_request_info *ri = &conn->request_info;
 
@@ -15301,6 +15302,7 @@ set_ports_option(struct mg_context *phys_ctx)
 			}
 		}
 #endif
+
 		else {
 			mg_cry_ctx_internal(
 			    phys_ctx,
@@ -19240,10 +19242,20 @@ master_thread_run(struct mg_context *ctx)
 		tls.user_ptr = NULL;
 	}
 
+	/* Lua background script "start" event */
+#if defined(USE_LUA)
+	if (ctx->lua_background_state) {
+		lua_State *lstate = (lua_State *)ctx->lua_background_state;
+		/* call "start()" in Lua */
+		lua_getglobal(lstate, "start");
+		(void)lua_pcall(lstate, /* args */ 0, /* results */ 0, 0);
+	}
+#endif
+
 	/* Server starts *now* */
 	ctx->start_time = time(NULL);
 
-	/* Start the server */
+	/* Server accept loop */
 	pfd = ctx->listening_socket_fds;
 	while (STOP_FLAG_IS_ZERO(&ctx->stop_flag)) {
 		for (i = 0; i < ctx->num_listening_sockets; i++) {
@@ -19295,12 +19307,9 @@ master_thread_run(struct mg_context *ctx)
 	/* Free Lua state of lua background task */
 	if (ctx->lua_background_state) {
 		lua_State *lstate = (lua_State *)ctx->lua_background_state;
-		lua_getglobal(lstate, LUABACKGROUNDPARAMS);
-		if (lua_istable(lstate, -1)) {
-			reg_boolean(lstate, "shutdown", 1);
-			lua_pop(lstate, 1);
-			mg_sleep(2);
-		}
+		/* call "stop()" in Lua */
+		lua_getglobal(lstate, "stop");
+		(void)lua_pcall(lstate, /* args */ 0, /* results */ 0, 0);
 		lua_close(lstate);
 		ctx->lua_background_state = 0;
 	}
@@ -19831,10 +19840,14 @@ static
 		struct vec opt_vec;
 		struct vec eq_vec;
 		const char *sparams;
-		lua_State *state = mg_prepare_lua_context_script(
+
+		/* Create a Lua state, load all standard libraries and the mg table */
+		lua_State *state = mg_lua_context_script_prepare(
 		    ctx->dd.config[LUA_BACKGROUND_SCRIPT], ctx, ebuf, sizeof(ebuf));
 		if (!state) {
-			mg_cry_ctx_internal(ctx, "lua_background_script error: %s", ebuf);
+			mg_cry_ctx_internal(ctx,
+			                    "lua_background_script load error: %s",
+			                    ebuf);
 			if ((error != NULL) && (error->text_buffer_size > 0)) {
 				mg_snprintf(NULL,
 				            NULL, /* No truncation check for error buffers */
@@ -19848,20 +19861,51 @@ static
 			pthread_setspecific(sTlsKey, NULL);
 			return NULL;
 		}
-		ctx->lua_background_state = (void *)state;
-
-		lua_newtable(state);
-		reg_boolean(state, "shutdown", 0);
 
+		/* Add a table with parameters into mg.params */
 		sparams = ctx->dd.config[LUA_BACKGROUND_SCRIPT_PARAMS];
+		if (sparams && sparams[0]) {
+			lua_getglobal(state, "mg");
+			lua_pushstring(state, "params");
+			lua_newtable(state);
+
+			while ((sparams = next_option(sparams, &opt_vec, &eq_vec))
+			       != NULL) {
+				reg_llstring(
+				    state, opt_vec.ptr, opt_vec.len, eq_vec.ptr, eq_vec.len);
+				if (mg_strncasecmp(sparams, opt_vec.ptr, opt_vec.len) == 0)
+					break;
+			}
+			lua_rawset(state, -3);
+			lua_pop(state, 1);
+		}
 
-		while ((sparams = next_option(sparams, &opt_vec, &eq_vec)) != NULL) {
-			reg_llstring(
-			    state, opt_vec.ptr, opt_vec.len, eq_vec.ptr, eq_vec.len);
-			if (mg_strncasecmp(sparams, opt_vec.ptr, opt_vec.len) == 0)
-				break;
+		/* Call script */
+		state = mg_lua_context_script_run(state,
+		                                  ctx->dd.config[LUA_BACKGROUND_SCRIPT],
+		                                  ctx,
+		                                  ebuf,
+		                                  sizeof(ebuf));
+		if (!state) {
+			mg_cry_ctx_internal(ctx,
+			                    "lua_background_script start error: %s",
+			                    ebuf);
+			if ((error != NULL) && (error->text_buffer_size > 0)) {
+				mg_snprintf(NULL,
+				            NULL, /* No truncation check for error buffers */
+				            error->text,
+				            error->text_buffer_size,
+				            "Error in script %s: %s",
+				            config_options[DOCUMENT_ROOT].name,
+				            ebuf);
+			}
+			free_context(ctx);
+			pthread_setspecific(sTlsKey, NULL);
+			return NULL;
 		}
-		lua_setglobal(state, LUABACKGROUNDPARAMS);
+
+		/* state remains valid */
+		ctx->lua_background_state = (void *)state;
 
 	} else {
 		ctx->lua_background_state = 0;