mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 12:20:41 +00:00
add lua loader
This commit is contained in:
@@ -6,8 +6,8 @@ address = "127.0.0.1:2526"
|
|||||||
master = "127.0.0.1:2013"
|
master = "127.0.0.1:2013"
|
||||||
start = "main" -- main script
|
start = "main" -- main script
|
||||||
bootstrap = "snlua bootstrap" -- The service for bootstrap
|
bootstrap = "snlua bootstrap" -- The service for bootstrap
|
||||||
-- preload = "preload example" -- run preload.lua helloworld before every lua service start
|
|
||||||
standalone = "0.0.0.0:2013"
|
standalone = "0.0.0.0:2013"
|
||||||
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua"
|
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua"
|
||||||
|
lualoader = "lualib/loader.lua"
|
||||||
snax = root.."examples/?.lua;"..root.."test/?.lua"
|
snax = root.."examples/?.lua;"..root.."test/?.lua"
|
||||||
cpath = root.."cservice/?.so"
|
cpath = root.."cservice/?.so"
|
||||||
|
|||||||
@@ -16,18 +16,30 @@ struct snlua {
|
|||||||
const char * preload;
|
const char * preload;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 int
|
static int
|
||||||
_cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
|
_cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
|
||||||
lua_State *L = ud;
|
lua_State *L = ud;
|
||||||
int trace = 1;
|
int trace = 1;
|
||||||
int r;
|
int r;
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
if (top == 1) {
|
if (top == 0) {
|
||||||
|
lua_pushcfunction(L, traceback);
|
||||||
lua_rawgetp(L, LUA_REGISTRYINDEX, _cb);
|
lua_rawgetp(L, LUA_REGISTRYINDEX, _cb);
|
||||||
} else {
|
} else {
|
||||||
assert(top == 2);
|
assert(top == 2);
|
||||||
lua_pushvalue(L,2);
|
|
||||||
}
|
}
|
||||||
|
lua_pushvalue(L,2);
|
||||||
|
|
||||||
lua_pushinteger(L, type);
|
lua_pushinteger(L, type);
|
||||||
lua_pushlightuserdata(L, (void *)msg);
|
lua_pushlightuserdata(L, (void *)msg);
|
||||||
|
|||||||
40
lualib/loader.lua
Normal file
40
lualib/loader.lua
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
local args = {}
|
||||||
|
for word in string.gmatch(..., "%S+") do
|
||||||
|
table.insert(args, word)
|
||||||
|
end
|
||||||
|
|
||||||
|
local main, pattern
|
||||||
|
|
||||||
|
local err = {}
|
||||||
|
for pat in string.gmatch(LUA_SERVICE, "([^;]+);*") do
|
||||||
|
local filename = string.gsub(pat, "?", args[1])
|
||||||
|
local f, msg = loadfile(filename)
|
||||||
|
if not f then
|
||||||
|
table.insert(err, msg)
|
||||||
|
else
|
||||||
|
pattern = pat
|
||||||
|
main = f
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not main then
|
||||||
|
error(table.concat(err, "\n"))
|
||||||
|
end
|
||||||
|
|
||||||
|
LUA_SERVICE = nil
|
||||||
|
package.path , LUA_PATH = LUA_PATH
|
||||||
|
package.cpath , LUA_CPATH = LUA_CPATH
|
||||||
|
|
||||||
|
local service_path = string.match(pattern, "(.*/)[^/?]+$")
|
||||||
|
if service_path then
|
||||||
|
package.path = service_path .. ";" .. package.path
|
||||||
|
end
|
||||||
|
|
||||||
|
if LUA_PRELOAD then
|
||||||
|
local f = assert(loadfile(LUA_PRELOAD))
|
||||||
|
f(table.unpack(args))
|
||||||
|
LUA_PRELOAD = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
main(select(2, table.unpack(args)))
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
struct snlua {
|
struct snlua {
|
||||||
lua_State * L;
|
lua_State * L;
|
||||||
struct skynet_context * ctx;
|
struct skynet_context * ctx;
|
||||||
const char * preload;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// LUA_CACHELIB may defined in patched lua for shared proto
|
// LUA_CACHELIB may defined in patched lua for shared proto
|
||||||
@@ -35,85 +34,13 @@ codecache(lua_State *L) {
|
|||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
luaL_newlib(L,l);
|
luaL_newlib(L,l);
|
||||||
lua_getglobal(L, "loadfile");
|
lua_getglobal(L, "loadfile");
|
||||||
lua_setfield(L, -2, "loadfile");
|
lua_setfield(L, -2, "loadfile");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
|
||||||
_try_load(lua_State *L, const char * path, int pathlen, const char * name) {
|
|
||||||
int namelen = strlen(name);
|
|
||||||
char tmp[pathlen + namelen];
|
|
||||||
int i;
|
|
||||||
for (i=0;i<pathlen;i++) {
|
|
||||||
if (path[i] == '?')
|
|
||||||
break;
|
|
||||||
tmp[i] = path[i];
|
|
||||||
}
|
|
||||||
if (path[i] == '?') {
|
|
||||||
memcpy(tmp+i,name,namelen);
|
|
||||||
memcpy(tmp+i+namelen,path+i+1,pathlen - i -1);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr,"snlua : Invalid lua service path\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
tmp[namelen+pathlen-1] = '\0';
|
|
||||||
int r = luaL_loadfile(L,tmp);
|
|
||||||
if (r == LUA_OK) {
|
|
||||||
int i;
|
|
||||||
for (i=namelen+pathlen-2;i>=0;i--) {
|
|
||||||
if (tmp[i] == '/') {
|
|
||||||
lua_pushlstring(L,tmp,i+1);
|
|
||||||
lua_setglobal(L,"SERVICE_PATH");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i<0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lua_getglobal(L,"package");
|
|
||||||
lua_getfield(L,-1,"path");
|
|
||||||
luaL_Buffer b;
|
|
||||||
luaL_buffinit(L, &b);
|
|
||||||
luaL_addlstring(&b, tmp, i+1);
|
|
||||||
luaL_addstring(&b, "?.lua;");
|
|
||||||
luaL_addvalue(&b);
|
|
||||||
luaL_pushresult(&b);
|
|
||||||
lua_setfield(L,-2,"path");
|
|
||||||
lua_pop(L,1);
|
|
||||||
return 0;
|
|
||||||
} else if (r == LUA_ERRFILE) {
|
|
||||||
lua_pop(L,1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
_load(lua_State *L, char ** filename) {
|
|
||||||
const char * name = strsep(filename, " \r\n");
|
|
||||||
const char * path = skynet_command(NULL, "GETENV", "luaservice");
|
|
||||||
while (path[0]) {
|
|
||||||
int pathlen;
|
|
||||||
char * pathend = strchr(path,';');
|
|
||||||
if (pathend) {
|
|
||||||
pathlen = pathend - path;
|
|
||||||
} else {
|
|
||||||
pathlen = strlen(path);
|
|
||||||
}
|
|
||||||
int r = _try_load(L, path, pathlen, name);
|
|
||||||
if (r >=0) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
path+=pathlen;
|
|
||||||
if (path[0]==';')
|
|
||||||
++path;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
traceback (lua_State *L) {
|
traceback (lua_State *L) {
|
||||||
const char *msg = lua_tostring(L, 1);
|
const char *msg = lua_tostring(L, 1);
|
||||||
@@ -125,95 +52,65 @@ traceback (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
_report_error(lua_State *L, struct skynet_context *ctx, const char *filename, int err) {
|
|
||||||
switch (err) {
|
|
||||||
case LUA_ERRRUN:
|
|
||||||
skynet_error(ctx, "lua do [%s] error : %s", filename, lua_tostring(L,-1));
|
|
||||||
break;
|
|
||||||
case LUA_ERRMEM:
|
|
||||||
skynet_error(ctx, "lua memory error : %s",filename);
|
|
||||||
break;
|
|
||||||
case LUA_ERRERR:
|
|
||||||
skynet_error(ctx, "lua message error : %s",filename);
|
|
||||||
break;
|
|
||||||
case LUA_ERRGCMM:
|
|
||||||
skynet_error(ctx, "lua gc error : %s",filename);
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
lua_pop(L,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_report_launcher_error(struct skynet_context *ctx) {
|
_report_launcher_error(struct skynet_context *ctx) {
|
||||||
// sizeof "ERROR" == 5
|
// sizeof "ERROR" == 5
|
||||||
skynet_sendname(ctx, ".launcher", PTYPE_TEXT, 0, "ERROR", 5);
|
skynet_sendname(ctx, ".launcher", PTYPE_TEXT, 0, "ERROR", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static const char *
|
||||||
dofile(lua_State *L, struct skynet_context *ctx, const char * args) {
|
optstring(struct skynet_context *ctx, const char *key, const char * str) {
|
||||||
int traceback_index = 1;
|
const char * ret = skynet_command(ctx, "GETENV", key);
|
||||||
char tmp[strlen(args)+1];
|
if (ret == NULL) {
|
||||||
char *parm = tmp;
|
return str;
|
||||||
strcpy(parm,args);
|
|
||||||
|
|
||||||
const char * filename = parm;
|
|
||||||
int r = _load(L, &parm);
|
|
||||||
if (r != 0) {
|
|
||||||
if (r<0) {
|
|
||||||
skynet_error(ctx, "lua parser [%s] load error", filename);
|
|
||||||
} else {
|
|
||||||
skynet_error(ctx, "lua parser [%s] error : %s", filename, lua_tostring(L,-1));
|
|
||||||
}
|
|
||||||
_report_launcher_error(ctx);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
int n=0;
|
return ret;
|
||||||
while(parm) {
|
|
||||||
const char * arg = strsep(&parm, " \r\n");
|
|
||||||
if (arg && arg[0]!='\0') {
|
|
||||||
lua_pushstring(L, arg);
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r = lua_pcall(L,n,0,traceback_index);
|
|
||||||
if (r == LUA_OK) {
|
|
||||||
r = lua_gc(L, LUA_GCCOLLECT, 0);
|
|
||||||
if (r == LUA_OK) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_report_error(L, ctx, filename, r);
|
|
||||||
_report_launcher_error(ctx);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_init(struct snlua *l, struct skynet_context *ctx, const char * args) {
|
_init(struct snlua *l, struct skynet_context *ctx, const char * args, size_t sz) {
|
||||||
lua_State *L = l->L;
|
lua_State *L = l->L;
|
||||||
l->ctx = ctx;
|
l->ctx = ctx;
|
||||||
lua_gc(L, LUA_GCSTOP, 0);
|
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);
|
luaL_openlibs(L);
|
||||||
lua_pushlightuserdata(L, ctx);
|
lua_pushlightuserdata(L, ctx);
|
||||||
lua_setfield(L, LUA_REGISTRYINDEX, "skynet_context");
|
lua_setfield(L, LUA_REGISTRYINDEX, "skynet_context");
|
||||||
luaL_requiref(L, "skynet.codecache", codecache , 0);
|
luaL_requiref(L, "skynet.codecache", codecache , 0);
|
||||||
lua_pop(L,1);
|
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, "preload");
|
||||||
|
lua_setglobal(L, "LUA_PRELOAD");
|
||||||
|
|
||||||
lua_pushcfunction(L, traceback);
|
lua_pushcfunction(L, traceback);
|
||||||
assert(lua_gettop(L) == 1);
|
assert(lua_gettop(L) == 1);
|
||||||
|
|
||||||
if (l->preload) {
|
const char * loader = optstring(ctx, "lualoader", "./lualib/loader.lua");
|
||||||
size_t l1 = strlen(l->preload);
|
|
||||||
size_t l2 = strlen(args);
|
int r = luaL_loadfile(L,loader);
|
||||||
char tmp[l1 + l2 + 2];
|
if (r != LUA_OK) {
|
||||||
sprintf(tmp, "%s %s", l->preload, args);
|
skynet_error(ctx, "Can't load %s : %s", loader, lua_tostring(L, -1));
|
||||||
if (dofile(L, ctx, tmp)) {
|
_report_launcher_error(ctx);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dofile(L, ctx, args)) {
|
|
||||||
return 1;
|
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);
|
lua_gc(L, LUA_GCRESTART, 0);
|
||||||
|
|
||||||
@@ -225,7 +122,7 @@ _launch(struct skynet_context * context, void *ud, int type, int session, uint32
|
|||||||
assert(type == 0 && session == 0);
|
assert(type == 0 && session == 0);
|
||||||
struct snlua *l = ud;
|
struct snlua *l = ud;
|
||||||
skynet_callback(context, NULL, NULL);
|
skynet_callback(context, NULL, NULL);
|
||||||
int err = _init(l, context, msg);
|
int err = _init(l, context, msg, sz);
|
||||||
if (err) {
|
if (err) {
|
||||||
skynet_command(context, "EXIT", NULL);
|
skynet_command(context, "EXIT", NULL);
|
||||||
}
|
}
|
||||||
@@ -235,18 +132,14 @@ _launch(struct skynet_context * context, void *ud, int type, int session, uint32
|
|||||||
|
|
||||||
int
|
int
|
||||||
snlua_init(struct snlua *l, struct skynet_context *ctx, const char * args) {
|
snlua_init(struct snlua *l, struct skynet_context *ctx, const char * args) {
|
||||||
const char * preload = skynet_command(ctx, "GETENV", "preload");
|
|
||||||
if (preload && preload[0]) {
|
|
||||||
l->preload = skynet_strdup(preload);
|
|
||||||
}
|
|
||||||
int sz = strlen(args);
|
int sz = strlen(args);
|
||||||
char * tmp = skynet_malloc(sz+1);
|
char * tmp = skynet_malloc(sz);
|
||||||
memcpy(tmp, args, sz+1);
|
memcpy(tmp, args, sz);
|
||||||
skynet_callback(ctx, l , _launch);
|
skynet_callback(ctx, l , _launch);
|
||||||
const char * self = skynet_command(ctx, "REG", NULL);
|
const char * self = skynet_command(ctx, "REG", NULL);
|
||||||
uint32_t handle_id = strtoul(self+1, NULL, 16);
|
uint32_t handle_id = strtoul(self+1, NULL, 16);
|
||||||
// it must be first message
|
// it must be first message
|
||||||
skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY,0, tmp, sz+1);
|
skynet_send(ctx, 0, handle_id, PTYPE_TAG_DONTCOPY,0, tmp, sz);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,13 +148,11 @@ snlua_create(void) {
|
|||||||
struct snlua * l = skynet_malloc(sizeof(*l));
|
struct snlua * l = skynet_malloc(sizeof(*l));
|
||||||
memset(l,0,sizeof(*l));
|
memset(l,0,sizeof(*l));
|
||||||
l->L = lua_newstate(skynet_lalloc, NULL);
|
l->L = lua_newstate(skynet_lalloc, NULL);
|
||||||
l->preload = NULL;
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
snlua_release(struct snlua *l) {
|
snlua_release(struct snlua *l) {
|
||||||
lua_close(l->L);
|
lua_close(l->L);
|
||||||
skynet_free((void*)l->preload);
|
|
||||||
skynet_free(l);
|
skynet_free(l);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ skynet.start(function()
|
|||||||
skynet.name(".launcher", launcher)
|
skynet.name(".launcher", launcher)
|
||||||
|
|
||||||
if skynet.getenv "standalone" then
|
if skynet.getenv "standalone" then
|
||||||
local datacenter = assert(skynet.newservice "datacenter")
|
local datacenter = assert(skynet.newservice "datacenterd")
|
||||||
skynet.name("DATACENTER", datacenter)
|
skynet.name("DATACENTER", datacenter)
|
||||||
local smgr = assert(skynet.newservice "service_mgr")
|
local smgr = assert(skynet.newservice "service_mgr")
|
||||||
end
|
end
|
||||||
|
skynet.uniqueservice("multicastd")
|
||||||
assert(skynet.newservice(skynet.getenv "start" or "main"))
|
assert(skynet.newservice(skynet.getenv "start" or "main"))
|
||||||
skynet.exit()
|
skynet.exit()
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
local skynet = require "skynet"
|
local skynet = require "skynet"
|
||||||
local mc = require "multicast.c"
|
local mc = require "multicast.c"
|
||||||
|
local datacenter = require "datacenter"
|
||||||
|
|
||||||
local command = {}
|
local command = {}
|
||||||
local channel = {}
|
local channel = {}
|
||||||
@@ -49,4 +50,8 @@ skynet.start(function()
|
|||||||
local f = assert(command[cmd])
|
local f = assert(command[cmd])
|
||||||
skynet.ret(skynet.pack(f(source, ...)))
|
skynet.ret(skynet.pack(f(source, ...)))
|
||||||
end)
|
end)
|
||||||
|
local self = skynet.self()
|
||||||
|
local id = skynet.harbor(self)
|
||||||
|
assert(datacenter.set("multicast", id, self) == nil)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
@@ -113,12 +113,6 @@ main(int argc, char *argv[]) {
|
|||||||
printf("Skynet lua code cache enable\n");
|
printf("Skynet lua code cache enable\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char *path = optstring("lua_path","./lualib/?.lua;./lualib/?/init.lua");
|
|
||||||
setenv("LUA_PATH",path,1);
|
|
||||||
const char *cpath = optstring("lua_cpath","./luaclib/?.so");
|
|
||||||
setenv("LUA_CPATH",cpath,1);
|
|
||||||
optstring("luaservice","./service/?.lua");
|
|
||||||
|
|
||||||
config.thread = optint("thread",8);
|
config.thread = optint("thread",8);
|
||||||
config.module_path = optstring("cpath","./cservice/?.so");
|
config.module_path = optstring("cpath","./cservice/?.so");
|
||||||
config.logger = optstring("logger",NULL);
|
config.logger = optstring("logger",NULL);
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
skynet.start(function()
|
skynet.start(function()
|
||||||
local id = socket.listen("127.0.0.1", 8000)
|
local id = socket.listen("127.0.0.1", 8001)
|
||||||
|
print("Listen socket :", "127.0.0.1", 8001)
|
||||||
|
|
||||||
socket.start(id , function(id, addr)
|
socket.start(id , function(id, addr)
|
||||||
print("connect from " .. addr .. " " .. id)
|
print("connect from " .. addr .. " " .. id)
|
||||||
|
|||||||
Reference in New Issue
Block a user