Diff

mod_statistics/prosodytop.lua @ 1072:4dbdb1b465e8

mod_statistics: Initial version, and a rough 'prosodyctl mod_statistics top'
author Matthew Wild <mwild1@gmail.com>
date Sat, 15 Jun 2013 19:08:34 +0100
child 1085:56fc7a86eb20
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_statistics/prosodytop.lua	Sat Jun 15 19:08:34 2013 +0100
@@ -0,0 +1,148 @@
+local curses = require "curses";
+local server = require "net.server_select";
+local timer = require "util.timer";
+
+assert(curses.timeout, "Incorrect version of curses library. Try 'sudo luarocks install luaposix'");
+
+local top = require "top";
+
+function main()
+	local stdscr = curses.stdscr()  -- it's a userdatum
+	--stdscr:clear();
+	local view = top.new({
+		stdscr = stdscr;
+		prosody = { up_since = os.time() };
+		conn_list = {};
+	});
+	
+	timer.add_task(0.01, function ()
+		local ch = stdscr:getch();
+		if ch then
+			if stdscr:getch() == 410 then
+				view:resized();
+			else
+				curses.ungetch(ch);
+			end
+		end
+		return 0.2;
+	end);
+	
+	timer.add_task(0, function ()
+		view:draw();
+		return 1;
+	end);
+	
+	--[[
+	posix.signal(28, function ()
+		table.insert(view.conn_list, { jid = "WINCH" });
+		--view:draw();
+	end);
+	]]
+	
+	-- Fake socket object around stdin
+	local stdin = {
+        	getfd = function () return 0; end;
+        	dirty = function (self) return false; end;
+        	settimeout = function () end;
+        	send = function (_, d) return #d, 0; end;
+        	close = function () end;
+        	receive = function (_, patt)
+        		local ch = stdscr:getch();
+        		if ch >= 0 and ch <=255 then
+        			return string.char(ch);
+        		elseif ch == 410 then
+        			view:resized();
+        		else
+        			table.insert(view.conn_list, { jid = tostring(ch) }); --FIXME
+        		end
+        		return "";
+        	end
+	};
+	local function on_incoming(stdin, text)
+		-- TODO: Handle keypresses
+		if text:lower() == "q" then os.exit(); end
+	end
+	stdin = server.wrapclient(stdin, "stdin", 0, {
+		onincoming = on_incoming, ondisconnect = function () end
+	}, "*a");
+	
+	local function handle_line(line)
+		local e = {
+			STAT = function (name) return function (value)
+				view:update_stat(name, value);
+			end end;
+			SESS = function (id) return function (jid) return function (stats)
+				view:update_session(id, jid, stats);
+			end end end;
+		};
+		local chunk = assert(loadstring(line));
+		setfenv(chunk, e);
+		chunk();
+	end
+	
+	local stats_listener = {};
+	
+	function stats_listener.onconnect(conn)
+		--stdscr:mvaddstr(6, 0, "CONNECTED");
+	end
+	
+	local partial;
+	function stats_listener.onincoming(conn, data)
+		--print("DATA", data)
+		if partial then
+			partial, data = nil, partial..data;
+		end
+		if not data:match("\n") then
+			partial = data;
+			return;
+		end
+		local lastpos = 1;
+		for line, pos in data:gmatch("([^\n]+)\n()") do
+			lastpos = pos;
+			handle_line(line);
+		end
+		if lastpos == #data then
+			partial = nil;
+		else
+			partial = data:sub(lastpos+1);
+		end
+	end
+	
+	function stats_listener.ondisconnect(conn, err)
+		stdscr:mvaddstr(6, 0, "DISCONNECTED: "..(err or "unknown"));
+	end
+	
+	local conn = require "socket".tcp();
+	assert(conn:connect("localhost", 5782));
+	handler = server.wrapclient(conn, "localhost", 5279, stats_listener, "*a");
+end
+
+return {
+	run = function ()
+		--os.setlocale("UTF-8", "all")
+
+		curses.initscr()
+		curses.cbreak()
+		curses.echo(false)  -- not noecho !
+		curses.nl(false)    -- not nonl !
+		curses.timeout(0);
+
+		local ok, err = pcall(main);
+
+		--while true do stdscr:getch() end
+		--stdscr:endwin()
+
+		if ok then
+			ok, err = xpcall(server.loop, debug.traceback);
+		end
+
+		curses.endwin();
+
+		--stdscr:refresh();
+		if not ok then
+			print(err);
+		end
+
+		print"DONE"
+	end;
+};