123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- local skynet = require "skynet"
- local codecache = require "skynet.codecache"
- local core = require "skynet.core"
- local socket = require "skynet.socket"
- local snax = require "skynet.snax"
- local memory = require "skynet.memory"
- local httpd = require "http.httpd"
- local sockethelper = require "http.sockethelper"
- local arg = table.pack(...)
- assert(arg.n <= 2)
- local ip = (arg.n == 2 and arg[1] or "127.0.0.1")
- local port = tonumber(arg[arg.n])
- local COMMAND = {}
- local COMMANDX = {}
- local function format_table(t)
- local index = {}
- for k in pairs(t) do
- table.insert(index, k)
- end
- table.sort(index, function(a, b) return tostring(a) < tostring(b) end)
- local result = {}
- for _,v in ipairs(index) do
- table.insert(result, string.format("%s:%s",v,tostring(t[v])))
- end
- return table.concat(result,"\t")
- end
- local function dump_line(print, key, value)
- if type(value) == "table" then
- print(key, format_table(value))
- else
- print(key,tostring(value))
- end
- end
- local function dump_list(print, list)
- local index = {}
- for k in pairs(list) do
- table.insert(index, k)
- end
- table.sort(index, function(a, b) return tostring(a) < tostring(b) end)
- for _,v in ipairs(index) do
- dump_line(print, v, list[v])
- end
- end
- local function split_cmdline(cmdline)
- local split = {}
- for i in string.gmatch(cmdline, "%S+") do
- table.insert(split,i)
- end
- return split
- end
- local function docmd(cmdline, print, fd)
- local split = split_cmdline(cmdline)
- local command = split[1]
- local cmd = COMMAND[command]
- local ok, list
- if cmd then
- ok, list = pcall(cmd, table.unpack(split,2))
- else
- cmd = COMMANDX[command]
- if cmd then
- split.fd = fd
- split[1] = cmdline
- ok, list = pcall(cmd, split)
- else
- print("Invalid command, type help for command list")
- end
- end
- if ok then
- if list then
- if type(list) == "string" then
- print(list)
- else
- dump_list(print, list)
- end
- end
- print("<CMD OK>")
- else
- print(list)
- print("<CMD Error>")
- end
- end
- local function console_main_loop(stdin, print)
- print("Welcome to skynet console")
- skynet.error(stdin, "connected")
- local ok, err = pcall(function()
- while true do
- local cmdline = socket.readline(stdin, "\n")
- if not cmdline then
- break
- end
- if cmdline:sub(1,4) == "GET " then
- -- http
- local code, url = httpd.read_request(sockethelper.readfunc(stdin, cmdline.. "\n"), 8192)
- local cmdline = url:sub(2):gsub("/"," ")
- docmd(cmdline, print, stdin)
- break
- end
- if cmdline ~= "" then
- docmd(cmdline, print, stdin)
- end
- end
- end)
- if not ok then
- skynet.error(stdin, err)
- end
- skynet.error(stdin, "disconnected")
- socket.close(stdin)
- end
- skynet.start(function()
- local listen_socket = socket.listen (ip, port)
- skynet.error("Start debug console at " .. ip .. ":" .. port)
- socket.start(listen_socket , function(id, addr)
- local function print(...)
- local t = { ... }
- for k,v in ipairs(t) do
- t[k] = tostring(v)
- end
- socket.write(id, table.concat(t,"\t"))
- socket.write(id, "\n")
- end
- socket.start(id)
- skynet.fork(console_main_loop, id , print)
- end)
- end)
- function COMMAND.help()
- return {
- help = "This help message",
- list = "List all the service",
- stat = "Dump all stats",
- info = "info address : get service infomation",
- exit = "exit address : kill a lua service",
- kill = "kill address : kill service",
- mem = "mem : show memory status",
- gc = "gc : force every lua service do garbage collect",
- start = "lanuch a new lua service",
- snax = "lanuch a new snax service",
- clearcache = "clear lua code cache",
- service = "List unique service",
- task = "task address : show service task detail",
- inject = "inject address luascript.lua",
- logon = "logon address",
- logoff = "logoff address",
- log = "launch a new lua service with log",
- debug = "debug address : debug a lua service",
- signal = "signal address sig",
- cmem = "Show C memory info",
- shrtbl = "Show shared short string table info",
- ping = "ping address",
- call = "call address ...",
- }
- end
- function COMMAND.clearcache()
- codecache.clear()
- end
- function COMMAND.start(...)
- local ok, addr = pcall(skynet.newservice, ...)
- if ok then
- if addr then
- return { [skynet.address(addr)] = ... }
- else
- return "Exit"
- end
- else
- return "Failed"
- end
- end
- function COMMAND.log(...)
- local ok, addr = pcall(skynet.call, ".launcher", "lua", "LOGLAUNCH", "snlua", ...)
- if ok then
- if addr then
- return { [skynet.address(addr)] = ... }
- else
- return "Failed"
- end
- else
- return "Failed"
- end
- end
- function COMMAND.snax(...)
- local ok, s = pcall(snax.newservice, ...)
- if ok then
- local addr = s.handle
- return { [skynet.address(addr)] = ... }
- else
- return "Failed"
- end
- end
- function COMMAND.service()
- return skynet.call("SERVICE", "lua", "LIST")
- end
- local function adjust_address(address)
- if address:sub(1,1) ~= ":" then
- address = assert(tonumber("0x" .. address), "Need an address") | (skynet.harbor(skynet.self()) << 24)
- end
- return address
- end
- function COMMAND.list()
- return skynet.call(".launcher", "lua", "LIST")
- end
- function COMMAND.stat()
- return skynet.call(".launcher", "lua", "STAT")
- end
- function COMMAND.mem()
- return skynet.call(".launcher", "lua", "MEM")
- end
- function COMMAND.kill(address)
- return skynet.call(".launcher", "lua", "KILL", address)
- end
- function COMMAND.gc()
- return skynet.call(".launcher", "lua", "GC")
- end
- function COMMAND.exit(address)
- skynet.send(adjust_address(address), "debug", "EXIT")
- end
- function COMMAND.inject(address, filename)
- address = adjust_address(address)
- local f = io.open(filename, "rb")
- if not f then
- return "Can't open " .. filename
- end
- local source = f:read "*a"
- f:close()
- local ok, output = skynet.call(address, "debug", "RUN", source, filename)
- if ok == false then
- error(output)
- end
- return output
- end
- function COMMAND.task(address)
- address = adjust_address(address)
- return skynet.call(address,"debug","TASK")
- end
- function COMMAND.info(address, ...)
- address = adjust_address(address)
- return skynet.call(address,"debug","INFO", ...)
- end
- function COMMANDX.debug(cmd)
- local address = adjust_address(cmd[2])
- local agent = skynet.newservice "debug_agent"
- local stop
- local term_co = coroutine.running()
- local function forward_cmd()
- repeat
- -- notice : It's a bad practice to call socket.readline from two threads (this one and console_main_loop), be careful.
- skynet.call(agent, "lua", "ping") -- detect agent alive, if agent exit, raise error
- local cmdline = socket.readline(cmd.fd, "\n")
- cmdline = cmdline and cmdline:gsub("(.*)\r$", "%1")
- if not cmdline then
- skynet.send(agent, "lua", "cmd", "cont")
- break
- end
- skynet.send(agent, "lua", "cmd", cmdline)
- until stop or cmdline == "cont"
- end
- skynet.fork(function()
- pcall(forward_cmd)
- if not stop then -- block at skynet.call "start"
- term_co = nil
- else
- skynet.wakeup(term_co)
- end
- end)
- local ok, err = skynet.call(agent, "lua", "start", address, cmd.fd)
- stop = true
- if term_co then
- -- wait for fork coroutine exit.
- skynet.wait(term_co)
- end
- if not ok then
- error(err)
- end
- end
- function COMMAND.logon(address)
- address = adjust_address(address)
- core.command("LOGON", skynet.address(address))
- end
- function COMMAND.logoff(address)
- address = adjust_address(address)
- core.command("LOGOFF", skynet.address(address))
- end
- function COMMAND.signal(address, sig)
- address = skynet.address(adjust_address(address))
- if sig then
- core.command("SIGNAL", string.format("%s %d",address,sig))
- else
- core.command("SIGNAL", address)
- end
- end
- function COMMAND.cmem()
- local info = memory.info()
- local tmp = {}
- for k,v in pairs(info) do
- tmp[skynet.address(k)] = v
- end
- tmp.total = memory.total()
- tmp.block = memory.block()
- return tmp
- end
- function COMMAND.shrtbl()
- local n, total, longest, space = memory.ssinfo()
- return { n = n, total = total, longest = longest, space = space }
- end
- function COMMAND.ping(address)
- address = adjust_address(address)
- local ti = skynet.now()
- skynet.call(address, "debug", "PING")
- ti = skynet.now() - ti
- return tostring(ti)
- end
- function COMMANDX.call(cmd)
- local address = adjust_address(cmd[2])
- local cmdline = assert(cmd[1]:match("%S+%s+%S+%s(.+)") , "need arguments")
- local args_func = assert(load("return " .. cmdline, "debug console", "t", {}), "Invalid arguments")
- local args = table.pack(pcall(args_func))
- if not args[1] then
- error(args[2])
- end
- local rets = table.pack(skynet.call(address, "lua", table.unpack(args, 2, args.n)))
- return rets
- end
|