123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- #define LUA_LIB
- #include "skynet.h"
- #include "lua-seri.h"
- #define KNRM "\x1B[0m"
- #define KRED "\x1B[31m"
- #include <lua.h>
- #include <lauxlib.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <inttypes.h>
- #include <time.h>
- #if defined(__APPLE__)
- #include <sys/time.h>
- #endif
- #include "skynet.h"
- // return nsec
- static int64_t
- get_time() {
- #if !defined(__APPLE__) || defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
- struct timespec ti;
- clock_gettime(CLOCK_MONOTONIC, &ti);
- return (int64_t)1000000000 * ti.tv_sec + ti.tv_nsec;
- #else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (int64_t)1000000000 * tv.tv_sec + tv.tv_usec * 1000;
- #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;
- }
- struct callback_context {
- lua_State *L;
- };
- static int
- _cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
- struct callback_context *cb_ctx = (struct callback_context *)ud;
- lua_State *L = cb_ctx->L;
- int trace = 1;
- int r;
- lua_pushvalue(L,2);
- lua_pushinteger(L, type);
- lua_pushlightuserdata(L, (void *)msg);
- lua_pushinteger(L,sz);
- lua_pushinteger(L, session);
- lua_pushinteger(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;
- };
- lua_pop(L,1);
- return 0;
- }
- static int
- forward_cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
- _cb(context, ud, type, session, source, msg, sz);
- // don't delete msg in forward mode.
- return 1;
- }
- static void
- clear_last_context(lua_State *L) {
- if (lua_getfield(L, LUA_REGISTRYINDEX, "callback_context") == LUA_TUSERDATA) {
- lua_pushnil(L);
- lua_setiuservalue(L, -2, 2);
- }
- lua_pop(L, 1);
- }
- static int
- _cb_pre(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
- struct callback_context *cb_ctx = (struct callback_context *)ud;
- clear_last_context(cb_ctx->L);
- skynet_callback(context, ud, _cb);
- return _cb(context, cb_ctx, type, session, source, msg, sz);
- }
- static int
- _forward_pre(struct skynet_context *context, void *ud, int type, int session, uint32_t source, const void *msg, size_t sz) {
- struct callback_context *cb_ctx = (struct callback_context *)ud;
- clear_last_context(cb_ctx->L);
- skynet_callback(context, ud, forward_cb);
- return forward_cb(context, cb_ctx, type, session, source, msg, sz);
- }
- static int
- lcallback(lua_State *L) {
- struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
- int forward = lua_toboolean(L, 2);
- luaL_checktype(L,1,LUA_TFUNCTION);
- lua_settop(L,1);
- struct callback_context * cb_ctx = (struct callback_context *)lua_newuserdatauv(L, sizeof(*cb_ctx), 2);
- cb_ctx->L = lua_newthread(L);
- lua_pushcfunction(cb_ctx->L, traceback);
- lua_setiuservalue(L, -2, 1);
- lua_getfield(L, LUA_REGISTRYINDEX, "callback_context");
- lua_setiuservalue(L, -2, 2);
- lua_setfield(L, LUA_REGISTRYINDEX, "callback_context");
- lua_xmove(L, cb_ctx->L, 1);
- skynet_callback(context, cb_ctx, (forward)?(_forward_pre):(_cb_pre));
- return 0;
- }
- static int
- lcommand(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
- laddresscommand(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 && result[0] == ':') {
- int i;
- uint32_t addr = 0;
- for (i=1;result[i];i++) {
- int c = result[i];
- if (c>='0' && c<='9') {
- c = c - '0';
- } else if (c>='a' && c<='f') {
- c = c - 'a' + 10;
- } else if (c>='A' && c<='F') {
- c = c - 'A' + 10;
- } else {
- return 0;
- }
- addr = addr * 16 + c;
- }
- lua_pushinteger(L, addr);
- return 1;
- }
- return 0;
- }
- static int
- lintcommand(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;
- char tmp[64]; // for integer parm
- if (lua_gettop(L) == 2) {
- if (lua_isnumber(L, 2)) {
- int32_t n = (int32_t)luaL_checkinteger(L,2);
- sprintf(tmp, "%d", n);
- parm = tmp;
- } else {
- parm = luaL_checkstring(L,2);
- }
- }
- result = skynet_command(context, cmd, parm);
- if (result) {
- char *endptr = NULL;
- lua_Integer r = strtoll(result, &endptr, 0);
- if (endptr == NULL || *endptr != '\0') {
- // may be real number
- double n = strtod(result, &endptr);
- if (endptr == NULL || *endptr != '\0') {
- return luaL_error(L, "Invalid result %s", result);
- } else {
- lua_pushnumber(L, n);
- }
- } else {
- lua_pushinteger(L, r);
- }
- return 1;
- }
- return 0;
- }
- static int
- lgenid(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;
- }
- static const char *
- get_dest_string(lua_State *L, int index) {
- const char * dest_string = lua_tostring(L, index);
- if (dest_string == NULL) {
- luaL_error(L, "dest address type (%s) must be a string or number.", lua_typename(L, lua_type(L,index)));
- }
- return dest_string;
- }
- static int
- send_message(lua_State *L, int source, int idx_type) {
- struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
- uint32_t dest = (uint32_t)lua_tointeger(L, 1);
- const char * dest_string = NULL;
- if (dest == 0) {
- if (lua_type(L,1) == LUA_TNUMBER) {
- return luaL_error(L, "Invalid service address 0");
- }
- dest_string = get_dest_string(L, 1);
- }
- int type = luaL_checkinteger(L, idx_type+0);
- int session = 0;
- if (lua_isnil(L,idx_type+1)) {
- type |= PTYPE_TAG_ALLOCSESSION;
- } else {
- session = luaL_checkinteger(L,idx_type+1);
- }
- int mtype = lua_type(L,idx_type+2);
- switch (mtype) {
- case LUA_TSTRING: {
- size_t len = 0;
- void * msg = (void *)lua_tolstring(L,idx_type+2,&len);
- if (len == 0) {
- msg = NULL;
- }
- if (dest_string) {
- session = skynet_sendname(context, source, dest_string, type, session , msg, len);
- } else {
- session = skynet_send(context, source, dest, type, session , msg, len);
- }
- break;
- }
- case LUA_TLIGHTUSERDATA: {
- void * msg = lua_touserdata(L,idx_type+2);
- int size = luaL_checkinteger(L,idx_type+3);
- if (dest_string) {
- session = skynet_sendname(context, source, dest_string, type | PTYPE_TAG_DONTCOPY, session, msg, size);
- } else {
- session = skynet_send(context, source, dest, type | PTYPE_TAG_DONTCOPY, session, msg, size);
- }
- break;
- }
- default:
- luaL_error(L, "invalid param %s", lua_typename(L, lua_type(L,idx_type+2)));
- }
- if (session < 0) {
- if (session == -2) {
- // package is too large
- lua_pushboolean(L, 0);
- return 1;
- }
- // send to invalid address
- // todo: maybe throw an error would be better
- return 0;
- }
- lua_pushinteger(L,session);
- return 1;
- }
- /*
- uint32 address
- string address
- integer type
- integer session
- string message
- lightuserdata message_ptr
- integer len
- */
- static int
- lsend(lua_State *L) {
- return send_message(L, 0, 2);
- }
- /*
- uint32 address
- string address
- integer source_address
- integer type
- integer session
- string message
- lightuserdata message_ptr
- integer len
- */
- static int
- lredirect(lua_State *L) {
- uint32_t source = (uint32_t)luaL_checkinteger(L,2);
- return send_message(L, source, 3);
- }
- static int
- lerror(lua_State *L) {
- struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
- int n = lua_gettop(L);
- if (n <= 1) {
- lua_settop(L, 1);
- const char * s = luaL_tolstring(L, 1, NULL);
- skynet_error(context, "%s", s);
- return 0;
- }
- luaL_Buffer b;
- luaL_buffinit(L, &b);
- int i;
- for (i=1; i<=n; i++) {
- luaL_tolstring(L, i, NULL);
- luaL_addvalue(&b);
- if (i<n) {
- luaL_addchar(&b, ' ');
- }
- }
- luaL_pushresult(&b);
- skynet_error(context, "%s", lua_tostring(L, -1));
- return 0;
- }
- static int
- ltostring(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
- lharbor(lua_State *L) {
- struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
- uint32_t handle = (uint32_t)luaL_checkinteger(L,1);
- int harbor = 0;
- int remote = skynet_isremote(context, handle, &harbor);
- lua_pushinteger(L,harbor);
- lua_pushboolean(L, remote);
- return 2;
- }
- static int
- lpackstring(lua_State *L) {
- luaseri_pack(L);
- char * str = (char *)lua_touserdata(L, -2);
- int sz = lua_tointeger(L, -1);
- lua_pushlstring(L, str, sz);
- skynet_free(str);
- return 1;
- }
- static int
- ltrash(lua_State *L) {
- int t = lua_type(L,1);
- switch (t) {
- case LUA_TSTRING: {
- break;
- }
- case LUA_TLIGHTUSERDATA: {
- void * msg = lua_touserdata(L,1);
- luaL_checkinteger(L,2);
- skynet_free(msg);
- break;
- }
- default:
- luaL_error(L, "skynet.trash invalid param %s", lua_typename(L,t));
- }
- return 0;
- }
- static int
- lnow(lua_State *L) {
- uint64_t ti = skynet_now();
- lua_pushinteger(L, ti);
- return 1;
- }
- static int
- lhpc(lua_State *L) {
- lua_pushinteger(L, get_time());
- return 1;
- }
- #define MAX_LEVEL 3
- struct source_info {
- const char * source;
- int line;
- };
- /*
- string tag
- string userstring
- thread co (default nil/current L)
- integer level (default nil)
- */
- static int
- ltrace(lua_State *L) {
- struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
- const char * tag = luaL_checkstring(L, 1);
- const char * user = luaL_checkstring(L, 2);
- if (!lua_isnoneornil(L, 3)) {
- lua_State * co = L;
- int level;
- if (lua_isthread(L, 3)) {
- co = lua_tothread (L, 3);
- level = luaL_optinteger(L, 4, 1);
- } else {
- level = luaL_optinteger(L, 3, 1);
- }
- struct source_info si[MAX_LEVEL];
- lua_Debug d;
- int index = 0;
- do {
- if (!lua_getstack(co, level, &d))
- break;
- lua_getinfo(co, "Sl", &d);
- level++;
- si[index].source = d.source;
- si[index].line = d.currentline;
- if (d.currentline >= 0)
- ++index;
- } while (index < MAX_LEVEL);
- switch (index) {
- case 1:
- skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d", tag, get_time(), user, si[0].source, si[0].line);
- break;
- case 2:
- skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d %s:%d", tag, get_time(), user,
- si[0].source, si[0].line,
- si[1].source, si[1].line
- );
- break;
- case 3:
- skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d %s:%d %s:%d", tag, get_time(), user,
- si[0].source, si[0].line,
- si[1].source, si[1].line,
- si[2].source, si[2].line
- );
- break;
- default:
- skynet_error(context, "<TRACE %s> %" PRId64 " %s", tag, get_time(), user);
- break;
- }
- return 0;
- }
- skynet_error(context, "<TRACE %s> %" PRId64 " %s", tag, get_time(), user);
- return 0;
- }
- LUAMOD_API int
- luaopen_skynet_core(lua_State *L) {
- luaL_checkversion(L);
- luaL_Reg l[] = {
- { "send" , lsend },
- { "genid", lgenid },
- { "redirect", lredirect },
- { "command" , lcommand },
- { "intcommand", lintcommand },
- { "addresscommand", laddresscommand },
- { "error", lerror },
- { "harbor", lharbor },
- { "callback", lcallback },
- { "trace", ltrace },
- { NULL, NULL },
- };
- // functions without skynet_context
- luaL_Reg l2[] = {
- { "tostring", ltostring },
- { "pack", luaseri_pack },
- { "unpack", luaseri_unpack },
- { "packstring", lpackstring },
- { "trash" , ltrash },
- { "now", lnow },
- { "hpc", lhpc }, // getHPCounter
- { NULL, NULL },
- };
- lua_createtable(L, 0, sizeof(l)/sizeof(l[0]) + sizeof(l2)/sizeof(l2[0]) -2);
- lua_getfield(L, LUA_REGISTRYINDEX, "skynet_context");
- struct skynet_context *ctx = lua_touserdata(L,-1);
- if (ctx == NULL) {
- return luaL_error(L, "Init skynet context first");
- }
- luaL_setfuncs(L,l,1);
- luaL_setfuncs(L,l2,0);
- return 1;
- }
|