#include "skynet.h" #include #include #include #include #include #include #include struct snlua { lua_State * L; struct skynet_context * ctx; }; // LUA_CACHELIB may defined in patched lua for shared proto #ifdef LUA_CACHELIB #define codecache luaopen_cache #else static int cleardummy(lua_State *L) { return 0; } static int codecache(lua_State *L) { luaL_Reg l[] = { { "clear", cleardummy }, { NULL, NULL }, }; luaL_newlib(L,l); lua_getglobal(L, "loadfile"); lua_setfield(L, -2, "loadfile"); return 1; } #endif static int traceback (lua_State *L) { const char *msg = lua_tostring(L, 1); if (msg) luaL_traceback(L, L, msg, 1); else { lua_pushliteral(L, "(no error message)"); } return 1; } static void _report_launcher_error(struct skynet_context *ctx) { // sizeof "ERROR" == 5 skynet_sendname(ctx, 0, ".launcher", PTYPE_TEXT, 0, "ERROR", 5); } static const char * optstring(struct skynet_context *ctx, const char *key, const char * str) { const char * ret = skynet_command(ctx, "GETENV", key); if (ret == NULL) { return str; } return ret; } static int _init(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz) { lua_State *L = l->L; l->ctx = ctx; lua_gc(L, LUA_GCSTOP, 0); lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); luaL_openlibs(L); lua_pushlightuserdata(L, ctx); lua_setfield(L, LUA_REGISTRYINDEX, "skynet_context"); luaL_requiref(L, "skynet.codecache", codecache , 0); lua_pop(L,1); const char *path = optstring(ctx, "lua_path","./lualib/?.lua;./lualib/?/init.lua"); lua_pushstring(L, path); lua_setglobal(L, "LUA_PATH"); const char *cpath = optstring(ctx, "lua_cpath","./luaclib/?.so"); lua_pushstring(L, cpath); lua_setglobal(L, "LUA_CPATH"); const char *service = optstring(ctx, "luaservice", "./service/?.lua"); lua_pushstring(L, service); lua_setglobal(L, "LUA_SERVICE"); const char *preload = skynet_command(ctx, "GETENV", "preload"); lua_pushstring(L, preload); lua_setglobal(L, "LUA_PRELOAD"); lua_pushcfunction(L, traceback); assert(lua_gettop(L) == 1); const char * loader = optstring(ctx, "lualoader", "./lualib/loader.lua"); int r = luaL_loadfile(L,loader); if (r != LUA_OK) { skynet_error(ctx, "Can't load %s : %s", loader, lua_tostring(L, -1)); _report_launcher_error(ctx); return 1; } lua_pushlstring(L, args, sz); r = lua_pcall(L,1,0,1); if (r != LUA_OK) { skynet_error(ctx, "lua loader error : %s", lua_tostring(L, -1)); _report_launcher_error(ctx); return 1; } lua_settop(L,0); lua_gc(L, LUA_GCRESTART, 0); return 0; } static int _launch(struct skynet_context * context, void *ud, int type, int session, uint32_t source , const void * msg, size_t sz) { assert(type == 0 && session == 0); struct snlua *l = ud; skynet_callback(context, NULL, NULL); int err = _init(l, context, msg, sz); if (err) { skynet_command(context, "EXIT", NULL); } return 0; } int snlua_init(struct snlua *l, struct skynet_context *ctx, const char * args) { int sz = strlen(args); char * tmp = skynet_malloc(sz); memcpy(tmp, args, sz); skynet_callback(ctx, l , _launch); const char * self = skynet_command(ctx, "REG", NULL); uint32_t handle_id = strtoul(self+1, NULL, 16); // it must be first message skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY,0, tmp, sz); return 0; } struct snlua * snlua_create(void) { struct snlua * l = skynet_malloc(sizeof(*l)); memset(l,0,sizeof(*l)); l->L = lua_newstate(skynet_lalloc, NULL); return l; } void snlua_release(struct snlua *l) { lua_close(l->L); skynet_free(l); }