1*76404edcSAsim Jamshed #include "mod_magnet_cache.h"
2*76404edcSAsim Jamshed #include "stat_cache.h"
3*76404edcSAsim Jamshed 
4*76404edcSAsim Jamshed #include <stdlib.h>
5*76404edcSAsim Jamshed #include <time.h>
6*76404edcSAsim Jamshed #include <assert.h>
7*76404edcSAsim Jamshed 
8*76404edcSAsim Jamshed #ifdef HAVE_LUA_H
9*76404edcSAsim Jamshed #include <lualib.h>
10*76404edcSAsim Jamshed #include <lauxlib.h>
11*76404edcSAsim Jamshed 
script_init()12*76404edcSAsim Jamshed static script *script_init() {
13*76404edcSAsim Jamshed 	script *sc;
14*76404edcSAsim Jamshed 
15*76404edcSAsim Jamshed 	sc = calloc(1, sizeof(*sc));
16*76404edcSAsim Jamshed 	sc->name = buffer_init();
17*76404edcSAsim Jamshed 	sc->etag = buffer_init();
18*76404edcSAsim Jamshed 
19*76404edcSAsim Jamshed 	return sc;
20*76404edcSAsim Jamshed }
21*76404edcSAsim Jamshed 
script_free(script * sc)22*76404edcSAsim Jamshed static void script_free(script *sc) {
23*76404edcSAsim Jamshed 	if (!sc) return;
24*76404edcSAsim Jamshed 
25*76404edcSAsim Jamshed 	lua_pop(sc->L, 1); /* the function copy */
26*76404edcSAsim Jamshed 
27*76404edcSAsim Jamshed 	buffer_free(sc->name);
28*76404edcSAsim Jamshed 	buffer_free(sc->etag);
29*76404edcSAsim Jamshed 
30*76404edcSAsim Jamshed 	lua_close(sc->L);
31*76404edcSAsim Jamshed 
32*76404edcSAsim Jamshed 	free(sc);
33*76404edcSAsim Jamshed }
34*76404edcSAsim Jamshed 
script_cache_init()35*76404edcSAsim Jamshed script_cache *script_cache_init() {
36*76404edcSAsim Jamshed 	script_cache *p;
37*76404edcSAsim Jamshed 
38*76404edcSAsim Jamshed 	p = calloc(1, sizeof(*p));
39*76404edcSAsim Jamshed 
40*76404edcSAsim Jamshed 	return p;
41*76404edcSAsim Jamshed }
42*76404edcSAsim Jamshed 
script_cache_free(script_cache * p)43*76404edcSAsim Jamshed void script_cache_free(script_cache *p) {
44*76404edcSAsim Jamshed 	size_t i;
45*76404edcSAsim Jamshed 
46*76404edcSAsim Jamshed 	if (!p) return;
47*76404edcSAsim Jamshed 
48*76404edcSAsim Jamshed 	for (i = 0; i < p->used; i++) {
49*76404edcSAsim Jamshed 		script_free(p->ptr[i]);
50*76404edcSAsim Jamshed 	}
51*76404edcSAsim Jamshed 
52*76404edcSAsim Jamshed 	free(p->ptr);
53*76404edcSAsim Jamshed 
54*76404edcSAsim Jamshed 	free(p);
55*76404edcSAsim Jamshed }
56*76404edcSAsim Jamshed 
script_cache_get_script(server * srv,connection * con,script_cache * cache,buffer * name)57*76404edcSAsim Jamshed lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) {
58*76404edcSAsim Jamshed 	size_t i;
59*76404edcSAsim Jamshed 	script *sc = NULL;
60*76404edcSAsim Jamshed 	stat_cache_entry *sce;
61*76404edcSAsim Jamshed 
62*76404edcSAsim Jamshed 	for (i = 0; i < cache->used; i++) {
63*76404edcSAsim Jamshed 		sc = cache->ptr[i];
64*76404edcSAsim Jamshed 
65*76404edcSAsim Jamshed 		if (buffer_is_equal(name, sc->name)) {
66*76404edcSAsim Jamshed 			sc->last_used = time(NULL);
67*76404edcSAsim Jamshed 
68*76404edcSAsim Jamshed 			/* oops, the script failed last time */
69*76404edcSAsim Jamshed 
70*76404edcSAsim Jamshed 			if (lua_gettop(sc->L) == 0) break;
71*76404edcSAsim Jamshed 
72*76404edcSAsim Jamshed 			if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) {
73*76404edcSAsim Jamshed 				lua_pop(sc->L, 1); /* pop the old function */
74*76404edcSAsim Jamshed 				break;
75*76404edcSAsim Jamshed 			}
76*76404edcSAsim Jamshed 
77*76404edcSAsim Jamshed 			if (!buffer_is_equal(sce->etag, sc->etag)) {
78*76404edcSAsim Jamshed 				/* the etag is outdated, reload the function */
79*76404edcSAsim Jamshed 				lua_pop(sc->L, 1);
80*76404edcSAsim Jamshed 				break;
81*76404edcSAsim Jamshed 			}
82*76404edcSAsim Jamshed 
83*76404edcSAsim Jamshed 			assert(lua_isfunction(sc->L, -1));
84*76404edcSAsim Jamshed 			lua_pushvalue(sc->L, -1); /* copy the function-reference */
85*76404edcSAsim Jamshed 
86*76404edcSAsim Jamshed 			return sc->L;
87*76404edcSAsim Jamshed 		}
88*76404edcSAsim Jamshed 
89*76404edcSAsim Jamshed 		sc = NULL;
90*76404edcSAsim Jamshed 	}
91*76404edcSAsim Jamshed 
92*76404edcSAsim Jamshed 	/* if the script was script already loaded but either got changed or
93*76404edcSAsim Jamshed 	 * failed to load last time */
94*76404edcSAsim Jamshed 	if (sc == NULL) {
95*76404edcSAsim Jamshed 		sc = script_init();
96*76404edcSAsim Jamshed 
97*76404edcSAsim Jamshed 		if (cache->size == 0) {
98*76404edcSAsim Jamshed 			cache->size = 16;
99*76404edcSAsim Jamshed 			cache->ptr = malloc(cache->size * sizeof(*(cache->ptr)));
100*76404edcSAsim Jamshed 		} else if (cache->used == cache->size) {
101*76404edcSAsim Jamshed 			cache->size += 16;
102*76404edcSAsim Jamshed 			cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr)));
103*76404edcSAsim Jamshed 		}
104*76404edcSAsim Jamshed 
105*76404edcSAsim Jamshed 		cache->ptr[cache->used++] = sc;
106*76404edcSAsim Jamshed 
107*76404edcSAsim Jamshed 		buffer_copy_string_buffer(sc->name, name);
108*76404edcSAsim Jamshed 
109*76404edcSAsim Jamshed 		sc->L = luaL_newstate();
110*76404edcSAsim Jamshed 		luaL_openlibs(sc->L);
111*76404edcSAsim Jamshed 	}
112*76404edcSAsim Jamshed 
113*76404edcSAsim Jamshed 	sc->last_used = time(NULL);
114*76404edcSAsim Jamshed 
115*76404edcSAsim Jamshed 	if (0 != luaL_loadfile(sc->L, name->ptr)) {
116*76404edcSAsim Jamshed 		/* oops, an error, return it */
117*76404edcSAsim Jamshed 
118*76404edcSAsim Jamshed 		return sc->L;
119*76404edcSAsim Jamshed 	}
120*76404edcSAsim Jamshed 
121*76404edcSAsim Jamshed 	if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) {
122*76404edcSAsim Jamshed 		buffer_copy_string_buffer(sc->etag, sce->etag);
123*76404edcSAsim Jamshed 	}
124*76404edcSAsim Jamshed 
125*76404edcSAsim Jamshed 	/**
126*76404edcSAsim Jamshed 	 * pcall() needs the function on the stack
127*76404edcSAsim Jamshed 	 *
128*76404edcSAsim Jamshed 	 * as pcall() will pop the script from the stack when done, we have to
129*76404edcSAsim Jamshed 	 * duplicate it here
130*76404edcSAsim Jamshed 	 */
131*76404edcSAsim Jamshed 	assert(lua_isfunction(sc->L, -1));
132*76404edcSAsim Jamshed 	lua_pushvalue(sc->L, -1); /* copy the function-reference */
133*76404edcSAsim Jamshed 
134*76404edcSAsim Jamshed 	return sc->L;
135*76404edcSAsim Jamshed }
136*76404edcSAsim Jamshed 
137*76404edcSAsim Jamshed #endif
138