#include "skynet.h" #include "lua-seri.h" #include "service_lua.h" #define KNRM "\x1B[0m" #define KRED "\x1B[31m" #include #include #include #include #include static int _cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) { lua_State *L = ud; int trace = 1; int r; int top = lua_gettop(L); if (top == 1) { lua_rawgetp(L, LUA_REGISTRYINDEX, _cb); } else { assert(top == 2); lua_pushvalue(L,2); } lua_pushinteger(L, type); lua_pushlightuserdata(L, (void *)msg); lua_pushinteger(L,sz); lua_pushinteger(L, session); lua_pushnumber(L, source); r = lua_pcall(L, 5, 0 , trace); if (r == LUA_OK) { return 0; } const char * self = skynet_command(context, "REG", NULL); switch (r) { case LUA_ERRRUN: skynet_error(context, "lua call [%x to %s : %d msgsz = %d] error : " KRED "%s" KNRM, source , self, session, sz, lua_tostring(L,-1)); break; case LUA_ERRMEM: skynet_error(context, "lua memory error : [%x to %s : %d]", source , self, session); break; case LUA_ERRERR: skynet_error(context, "lua error in error : [%x to %s : %d]", source , self, session); break; case LUA_ERRGCMM: skynet_error(context, "lua gc error : [%x to %s : %d]", source , self, session); break; }; lua_pop(L,1); return 0; } static int _callback(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); luaL_checktype(L,1,LUA_TFUNCTION); lua_settop(L,1); lua_rawsetp(L, LUA_REGISTRYINDEX, _cb); lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); lua_State *gL = lua_tothread(L,-1); skynet_callback(context, gL, _cb); return 0; } static int _command(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); const char * cmd = luaL_checkstring(L,1); const char * result; const char * parm = NULL; if (lua_gettop(L) == 2) { parm = luaL_checkstring(L,2); } result = skynet_command(context, cmd, parm); if (result) { lua_pushstring(L, result); return 1; } return 0; } static int _genid(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); int session = skynet_send(context, 0, 0, PTYPE_TAG_ALLOCSESSION , 0 , NULL, 0); lua_pushinteger(L, session); return 1; } // copy from _send static int _sendname(lua_State *L, struct skynet_context * context, const char * dest) { int type = luaL_checkinteger(L, 2); int session = 0; if (lua_isnil(L,3)) { type |= PTYPE_TAG_ALLOCSESSION; } else { session = luaL_checkinteger(L,3); } int mtype = lua_type(L,4); switch (mtype) { case LUA_TSTRING: { size_t len = 0; void * msg = (void *)lua_tolstring(L,4,&len); session = skynet_sendname(context, dest, type, session , msg, len); break; } case LUA_TNIL : session = skynet_sendname(context, dest, type, session , NULL, 0); break; case LUA_TLIGHTUSERDATA: { luaL_checktype(L, 4, LUA_TLIGHTUSERDATA); void * msg = lua_touserdata(L,4); int size = luaL_checkinteger(L,5); session = skynet_sendname(context, dest, type | PTYPE_TAG_DONTCOPY, session, msg, size); break; } default: luaL_error(L, "skynet.send invalid param %s", lua_typename(L,lua_type(L,4))); } if (session < 0) { luaL_error(L, "skynet.send session (%d) < 0", session); } lua_pushinteger(L,session); return 1; } /* unsigned address string address integer type integer session string message lightuserdata message_ptr integer len */ static int _send(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); int addr_type = lua_type(L,1); uint32_t dest = 0; switch(addr_type) { case LUA_TNUMBER: dest = lua_tounsigned(L,1); break; case LUA_TSTRING: { const char * addrname = lua_tostring(L,1); if (addrname[0] == '.' || addrname[0] == ':') { dest = skynet_queryname(context, addrname); if (dest == 0) { luaL_error(L, "Invalid name %s", addrname); } } else if ('0' <= addrname[0] && addrname[0] <= '9') { luaL_error(L, "Invalid name %s: must not start with a digit", addrname); } else { return _sendname(L, context, addrname); } break; } default: return luaL_error(L, "address must be number or string, got %s",lua_typename(L,addr_type)); } int type = luaL_checkinteger(L, 2); int session = 0; if (lua_isnil(L,3)) { type |= PTYPE_TAG_ALLOCSESSION; } else { session = luaL_checkinteger(L,3); } int mtype = lua_type(L,4); switch (mtype) { case LUA_TSTRING: { size_t len = 0; void * msg = (void *)lua_tolstring(L,4,&len); if (len == 0) { msg = NULL; } session = skynet_send(context, 0, dest, type, session , msg, len); break; } case LUA_TLIGHTUSERDATA: { void * msg = lua_touserdata(L,4); int size = luaL_checkinteger(L,5); session = skynet_send(context, 0, dest, type | PTYPE_TAG_DONTCOPY, session, msg, size); break; } default: luaL_error(L, "skynet.send invalid param %s", lua_typename(L, lua_type(L,4))); } if (session < 0) { // send to invalid address // todo: maybe throw error is better return 0; } lua_pushinteger(L,session); return 1; } static int _redirect(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); uint32_t dest = luaL_checkunsigned(L,1); uint32_t source = luaL_checkunsigned(L,2); int type = luaL_checkinteger(L,3); int session = luaL_checkinteger(L,4); int mtype = lua_type(L,5); switch (mtype) { case LUA_TSTRING: { size_t len = 0; void * msg = (void *)lua_tolstring(L,5,&len); if (len == 0) { msg = NULL; } session = skynet_send(context, source, dest, type, session , msg, len); break; } case LUA_TLIGHTUSERDATA: { void * msg = lua_touserdata(L,5); int size = luaL_checkinteger(L,6); session = skynet_send(context, source, dest, type | PTYPE_TAG_DONTCOPY, session, msg, size); break; } default: luaL_error(L, "skynet.redirect invalid param %s", lua_typename(L,mtype)); } return 0; } static int _error(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); skynet_error(context, "%s", luaL_checkstring(L,1)); return 0; } static int _tostring(lua_State *L) { if (lua_isnoneornil(L,1)) { return 0; } char * msg = lua_touserdata(L,1); int sz = luaL_checkinteger(L,2); lua_pushlstring(L,msg,sz); return 1; } static int _harbor(lua_State *L) { struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); uint32_t handle = luaL_checkunsigned(L,1); int harbor = 0; int remote = skynet_isremote(context, handle, &harbor); lua_pushinteger(L,harbor); lua_pushboolean(L, remote); return 2; } int luaopen_skynet_c(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { { "send" , _send }, { "genid", _genid }, { "redirect", _redirect }, { "command" , _command }, { "error", _error }, { "tostring", _tostring }, { "harbor", _harbor }, { "pack", _luaseri_pack }, { "unpack", _luaseri_unpack }, { "callback", _callback }, { NULL, NULL }, }; lua_getfield(L, LUA_REGISTRYINDEX, "skynet_lua"); struct snlua *lua = lua_touserdata(L,-1); if (lua == NULL || lua->ctx == NULL) { return luaL_error(L, "Init skynet context first"); } assert(lua->L == L); luaL_newlibtable(L, l); lua_pushlightuserdata(L, lua->ctx); luaL_setfuncs(L,l,1); return 1; }