📄 ejabberd_web_admin.erl
字号:
[{"xmlns", ?NS_ROSTER}], [{xmlelement, "item", [{"jid", jlib:jid_to_string(JID)}, {"subscription", "remove"}], []}]}}), throw(submitted); false -> ok end end end, Items), nothing.get_nodes(Lang) -> RunningNodes = mnesia:system_info(running_db_nodes), StoppedNodes = lists:usort(mnesia:system_info(db_nodes) ++ mnesia:system_info(extra_db_nodes)) -- RunningNodes, FRN = if RunningNodes == [] -> ?CT("None"); true -> ?XE("ul", lists:map( fun(N) -> S = atom_to_list(N), ?LI([?AC("../node/" ++ S ++ "/", S)]) end, lists:sort(RunningNodes))) end, FSN = if StoppedNodes == [] -> ?CT("None"); true -> ?XE("ul", lists:map( fun(N) -> S = atom_to_list(N), ?LI([?C(S)]) end, lists:sort(StoppedNodes))) end, [?XCT("h1", "Nodes"), ?XCT("h3", "Running Nodes"), FRN, ?XCT("h3", "Stopped Nodes"), FSN].search_running_node(SNode) -> search_running_node(SNode, mnesia:system_info(running_db_nodes)).search_running_node(_, []) -> false;search_running_node(SNode, [Node | Nodes]) -> case atom_to_list(Node) of SNode -> Node; _ -> search_running_node(SNode, Nodes) end.get_node(Node, [], Query, Lang) -> Res = node_parse_query(Node, Query), [?XC("h1", ?T("Node ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; nothing -> [] end ++ [?XE("ul", [?LI([?ACT("db/", "DB Management")]), ?LI([?ACT("backup/", "Backup Management")]), ?LI([?ACT("ports/", "Listened Ports Management")]), ?LI([?ACT("stats/", "Statistics")]) ]), ?XAE("form", [{"method", "post"}], [?INPUTT("submit", "restart", "Restart"), ?C(" "), ?INPUTT("submit", "stop", "Stop")]) ];get_node(Node, ["db"], Query, Lang) -> case rpc:call(Node, mnesia, system_info, [tables]) of {badrpc, _Reason} -> [?XCT("h1", "RPC call error")]; Tables -> Res = node_db_parse_query(Node, Tables, Query), STables = lists:sort(Tables), Rows = lists:map( fun(Table) -> STable = atom_to_list(Table), TInfo = case rpc:call(Node, mnesia, table_info, [Table, all]) of {badrpc, _} -> []; I -> I end, {Type, Size, Memory} = case {lists:keysearch(storage_type, 1, TInfo), lists:keysearch(size, 1, TInfo), lists:keysearch(memory, 1, TInfo)} of {{value, {storage_type, T}}, {value, {size, S}}, {value, {memory, M}}} -> {T, S, M}; _ -> {unknown, 0, 0} end, ?XE("tr", [?XC("td", STable), ?XE("td", [db_storage_select( STable, Type, Lang)]), ?XAC("td", [{"class", "alignright"}], integer_to_list(Size)), ?XAC("td", [{"class", "alignright"}], integer_to_list(Memory)) ]) end, STables), [?XC("h1", ?T("DB Tables at ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; nothing -> [] end ++ [?XAE("form", [{"method", "post"}], [?XAE("table", [], [?XE("thead", [?XE("tr", [?XCT("td", "Name"), ?XCT("td", "Storage Type"), ?XCT("td", "Size"), ?XCT("td", "Memory") ])]), ?XE("tbody", Rows ++ [?XE("tr", [?XAE("td", [{"colspan", "4"}, {"class", "alignright"}], [?INPUTT("submit", "submit", "Submit")]) ])] )])])] end;get_node(Node, ["backup"], Query, Lang) -> Res = node_backup_parse_query(Node, Query), [?XC("h1", ?T("Backup Management at ") ++ atom_to_list(Node)), ?XAE("form", [{"method", "post"}], [?XAE("table", [], [?XE("tbody", [?XE("tr", [?XCT("td", "Store a backup in a file"), ?XE("td", [?INPUT("text", "storepath", "ejabberd.backup")]), ?XE("td", [?INPUTT("submit", "store", "OK")]) ]), ?XE("tr", [?XCT("td", "Restore a backup from a file"), ?XE("td", [?INPUT("text", "restorepath", "ejabberd.backup")]), ?XE("td", [?INPUTT("submit", "restore", "OK")]) ]), ?XE("tr", [?XCT("td", "Install a database fallback from a file"), ?XE("td", [?INPUT("text", "fallbackpath", "ejabberd.backup")]), ?XE("td", [?INPUTT("submit", "fallback", "OK")]) ]), ?XE("tr", [?XCT("td", "Dump a database in a text file"), ?XE("td", [?INPUT("text", "dumppath", "ejabberd.dump")]), ?XE("td", [?INPUTT("submit", "dump", "OK")]) ]), ?XE("tr", [?XCT("td", "Restore a database from a text file"), ?XE("td", [?INPUT("text", "loadpath", "ejabberd.dump")]), ?XE("td", [?INPUTT("submit", "load", "OK")]) ]) ]) ])])];get_node(Node, ["ports"], Query, Lang) -> Ports = rpc:call(Node, ejabberd_config, get_local_option, [listen]), Res = case catch node_ports_parse_query(Node, Ports, Query) of submitted -> ok; {'EXIT', _Reason} -> error; _ -> nothing end, NewPorts = lists:sort( rpc:call(Node, ejabberd_config, get_local_option, [listen])), [?XC("h1", ?T("Listened Ports at ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("submitted"), ?P]; error -> [?CT("bad format"), ?P]; nothing -> [] end ++ [?XAE("form", [{"method", "post"}], [node_ports_to_xhtml(NewPorts, Lang)]) ];get_node(Node, ["stats"], Query, Lang) -> UpTime = rpc:call(Node, erlang, statistics, [wall_clock]), UpTimeS = io_lib:format("~.3f", [element(1, UpTime)/1000]), CPUTime = rpc:call(Node, erlang, statistics, [runtime]), CPUTimeS = io_lib:format("~.3f", [element(1, CPUTime)/1000]), Users = length( rpc:call(Node, ejabberd_sm, dirty_get_my_sessions_list, [])), TransactionsCommited = rpc:call(Node, mnesia, system_info, [transaction_commits]), TransactionsAborted = rpc:call(Node, mnesia, system_info, [transaction_failures]), TransactionsRestarted = rpc:call(Node, mnesia, system_info, [transaction_restarts]), TransactionsLogged = rpc:call(Node, mnesia, system_info, [transaction_log_writes]), [?XC("h1", io_lib:format(?T("~p statistics"), [Node])), ?XAE("table", [], [?XE("tbody", [?XE("tr", [?XCT("td", "Uptime"), ?XAC("td", [{"class", "alignright"}], UpTimeS)]), ?XE("tr", [?XCT("td", "CPU Time"), ?XAC("td", [{"class", "alignright"}], CPUTimeS)]), ?XE("tr", [?XCT("td", "Authentificated users"), ?XAC("td", [{"class", "alignright"}], integer_to_list(Users))]), ?XE("tr", [?XCT("td", "Transactions commited"), ?XAC("td", [{"class", "alignright"}], integer_to_list(TransactionsCommited))]), ?XE("tr", [?XCT("td", "Transactions aborted"), ?XAC("td", [{"class", "alignright"}], integer_to_list(TransactionsAborted))]), ?XE("tr", [?XCT("td", "Transactions restarted"), ?XAC("td", [{"class", "alignright"}], integer_to_list(TransactionsRestarted))]), ?XE("tr", [?XCT("td", "Transactions logged"), ?XAC("td", [{"class", "alignright"}], integer_to_list(TransactionsLogged))]) ]) ])];get_node(Node, NPath, Query, Lang) -> [?XCT("h1", "Not found")].node_parse_query(Node, Query) -> case lists:keysearch("restart", 1, Query) of {value, _} -> case rpc:call(Node, init, restart, []) of {badrpc, _Reason} -> error; _ -> ok end; _ -> case lists:keysearch("stop", 1, Query) of {value, _} -> case rpc:call(Node, init, stop, []) of {badrpc, _Reason} -> error; _ -> ok end; _ -> nothing end end.db_storage_select(ID, Opt, Lang) -> ?XAE("select", [{"name", "table" ++ ID}], lists:map( fun({O, Desc}) -> Sel = if O == Opt -> [{"selected", "selected"}]; true -> [] end, ?XACT("option", Sel ++ [{"value", atom_to_list(O)}], Desc) end, [{ram_copies, "RAM copy"}, {disc_copies, "RAM and disc copy"}, {disc_only_copies, "Disc only copy"}, {unknown, "Remote copy"}])).node_db_parse_query(Node, Tables, Query) -> lists:foreach( fun(Table) -> STable = atom_to_list(Table), case lists:keysearch("table" ++ STable, 1, Query) of {value, {_, SType}} -> Type = case SType of "unknown" -> unknown; "ram_copies" -> ram_copies; "disc_copies" -> disc_copies; "disc_only_copies" -> disc_only_copies; _ -> false end, if Type == false -> ok; Type == unknown -> mnesia:del_table_copy(Table, Node); true -> case mnesia:add_table_copy(Table, Node, Type) of {aborted, _} -> mnesia:change_table_copy_type( Table, Node, Type); _ -> ok end end; _ -> ok end end, Tables), ok.node_backup_parse_query(Node, Query) -> lists:foldl( fun(Action, nothing) -> case lists:keysearch(Action, 1, Query) of {value, _} -> case lists:keysearch(Action ++ "path", 1, Query) of {value, {_, Path}} -> Res = case Action of "store" -> rpc:call(Node, mnesia, backup, [Path]); "restore" -> rpc:call(Node, mnesia, restore, [Path, [{default_op, keep_tables}]]); "fallback" -> rpc:call(Node, mnesia, install_fallback, [Path]); "dump" -> rpc:call(Node, mnesia, dump_to_textfile, [Path]); "load" -> rpc:call(Node, mnesia, load_textfile, [Path]) end, case Res of {error, _Reason} -> error; {badrpc, _Reason} -> error; _ -> ok end; _ -> error end; _ -> nothing end; (_Action, Res) -> Res end, nothing, ["store", "restore", "fallback", "dump", "load"]).node_ports_to_xhtml(Ports, Lang) -> ?XAE("table", [], [?XE("thead", [?XE("tr", [?XCT("td", "Port"), ?XCT("td", "Module"), ?XCT("td", "Options") ])]), ?XE("tbody", lists:map( fun({Port, Module, Opts} = E) -> SPort = integer_to_list(Port), SModule = atom_to_list(Module), ID = term_to_id(E), ?XE("tr", [?XC("td", SPort), ?XE("td", [?INPUT("text", "module" ++ SPort, SModule)]), ?XE("td", [?INPUTS("text", "opts" ++ SPort, term_to_string(Opts), "40")]), ?XE("td", [?INPUTT("submit", "add" ++ SPort, "Update")]), ?XE("td", [?INPUTT("submit", "delete" ++ SPort, "Delete")]) ] ) end, Ports) ++ [?XE("tr", [?XE("td", [?INPUTS("text", "portnew", "", "6")]), ?XE("td", [?INPUT("text", "modulenew", "")]), ?XE("td", [?INPUTS("text", "optsnew", "", "40")]), ?XAE("td", [{"colspan", "2"}], [?INPUTT("submit", "addnew", "Add New")]) ] )] )]).node_ports_parse_query(Node, Ports, Query) -> lists:foreach( fun({Port, _Module1, _Opts1}) -> SPort = integer_to_list(Port), case lists:keysearch("add" ++ SPort, 1, Query) of {value, _} -> {{value, {_, SModule}}, {value, {_, SOpts}}} = {lists:keysearch("module" ++ SPort, 1, Query), lists:keysearch("opts" ++ SPort, 1, Query)}, Module = list_to_atom(SModule), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), ejabberd_listener:delete_listener(Port), ejabberd_listener:add_listener(Port, Module, Opts), throw(submitted); _ -> case lists:keysearch("delete" ++ SPort, 1, Query) of {value, _} -> ejabberd_listener:delete_listener(Port), throw(submitted); _ -> ok end end end, Ports), case lists:keysearch("addnew", 1, Query) of {value, _} -> {{value, {_, SPort}}, {value, {_, SModule}}, {value, {_, SOpts}}} = {lists:keysearch("portnew", 1, Query), lists:keysearch("modulenew", 1, Query), lists:keysearch("optsnew", 1, Query)}, Port = list_to_integer(SPort), Module = list_to_atom(SModule), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), ejabberd_listener:add_listener(Port, Module, Opts), throw(submitted); _ -> ok end.pretty_print(El) -> lists:flatten(pretty_print(El, "")).pretty_print({xmlcdata, CData}, Prefix) -> [Prefix, CData, $\n];pretty_print({xmlelement, Name, Attrs, Els}, Prefix) -> [Prefix, $<, Name, case Attrs of [] -> []; [{Attr, Val} | RestAttrs] -> AttrPrefix = [Prefix, string:copies(" ", length(Name) + 2)], [$\s, Attr, $=, $', xml:crypt(Val), $' | lists:map(fun({Attr1, Val1}) -> [$\n, AttrPrefix, Attr1, $=, $', xml:crypt(Val1), $'] end, RestAttrs)] end, if Els == [] -> "/>\n"; true -> OnlyCData = lists:all(fun({xmlcdata, _}) -> true; ({xmlelement, _, _, _}) -> false end, Els), if OnlyCData -> [$>, xml:get_cdata(Els), $<, $/, Name, $>, $\n ]; true -> [$>, $\n, lists:map(fun(E) -> pretty_print(E, [Prefix, " "]) end, Els), Prefix, $<, $/, Name, $>, $\n ] end end].
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -