Ticket #3022: mod_gamelist.erl

File mod_gamelist.erl, 5.0 KB (added by Josh, 8 years ago)

WIP version of the new module

Line 
1%% Copyright (C) 2016 Wildfire Games.
2%% This file is part of 0 A.D.
3%%
4%% 0 A.D. is free software: you can redistribute it and/or modify
5%% it under the terms of the GNU General Public License as published by
6%% the Free Software Foundation, either version 2 of the License, or
7%% (at your option) any later version.
8%%
9%% 0 A.D. is distributed in the hope that it will be useful,
10%% but WITHOUT ANY WARRANTY; without even the implied warranty of
11%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12%% GNU General Public License for more details.
13%%
14%% You should have received a copy of the GNU General Public License
15%% along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16
17-module(mod_gamelist).
18
19-behaviour(gen_mod).
20
21% Hack to fix build. Ejabberd rewrote the module build system without leaving any
22% instructions on how to upgrade. This is from Stack Overflow
23% (http://stackoverflow.com/questions/32542102/ejabberd-debugging)
24%TODO: Proper version checking
25%-ifndef(LAGER).
26%-define(LAGER, 1).
27%-endif.
28%-ifndef(NO_EXT_LIB).
29%-define(NO_EXT_LIB, 1).
30%-endif.
31
32%% Handy shortcuts to improve readability
33-record(xmlelement, {name = "" :: string(),
34 attrs = [] :: [{string(), string()}],
35 children = [] :: [{xmlcdata, iodata()} | xmlelement()]}).
36-type xmlelement() :: #xmlelement{}.
37% TODO: Evaluate if we actually need dbentry
38-record(dbentry, {key :: jid,
39 value :: xmlelement()}).
40
41-include("ejabberd.hrl").
42-include("jlib.hrl").
43
44-export([start/2, stop/1, process_gamelist_iq/3]).
45
46-define(GAMELIST_NS, "jabber:iq:gamelist").
47
48start(Host, _Opts) ->
49 ?INFO_MSG("Starting mod_gamelist", []),
50 % Create a table named 'games' with the default options
51 mnesia:create_table(games,
52 [{attributes, record_info(fields, dbentry)}, {record_name, dbentry}]),
53 %% Make sure that the table is empty, as create_table won't overwrite an existing
54 %% table
55 mnesia:clear_table(games),
56 %% Handle all stanzas addressed to the server containing the jabberd:iq:gamelist
57 %% namespace with process_gamelist_iq/3 and queue pending stanzas. May be
58 %% interesting to experiment with using parallel execution instead of queued.
59 gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?GAMELIST_NS, ?MODULE,
60 process_gamelist_iq, one_queue).
61
62stop(Host) ->
63 ?INFO_MSG("Stopping mod_gamelist", []),
64 mnesia:delete_table(games),
65 gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?GAMELIST_NS).
66
67% Handle gamelist IQ stanzas
68process_gamelist_iq(From, To, IQ) ->
69 ?INFO_MSG("Gamelist stanza received from ~p: ~n ~p ~n", [From, IQ]),
70 % TODO: Add a checked room field to the message, keep per room databases
71 case IQ#iq.type of
72 set ->
73 % Find and extract the command
74 CommandXml = lists:keyfind("command", 2, IQ#iq.sub_el#xmlelement.children),
75 [{xmlcdata, Command}] = CommandXml#xmlelement.children,
76 ?INFO_MSG("Command: ~p~n", [Command]),
77 % TODO: Something about changestate
78 case Command of
79 <<"register">> ->
80 % Extract game
81 Game = lists:keyfind("game", 2, IQ#iq.sub_el#xmlelement.children),
82 % Get host's (sender's) IP so that client know who to connect to
83 Origin = ejabberd_sm:get_user_ip(From#jid.user, From#jid.server, From#jid.resource),
84 HostIPString = inet_parse:ntoa(element(1, Origin)),
85 % Merge in the IP
86 MergedGameProperties = lists:keyreplace("ip", 1, Game#xmlelement.attrs, {"ip", HostIPString}),
87 MergedGame = Game#xmlelement{attrs = MergedGameProperties},
88 ?INFO_MSG("Attempting to register game: ~p~nFrom: ~p", [MergedGame, From]),
89 % Save the game to the database
90 mnesia:dirty_write(games, {dbentry, From, MergedGame}),
91 % TODO: Multicast new gamelist
92 ?INFO_MSG("'dev' users: ~p", [p1_fsm:sync_send_all_state_event(mnesia:dirty_read(muc_online_room, {"dev", "localhost"}), {get_disco_item, From, "en"}, 100)]),%mod_muc_admin:get_room_occupants("dev", "localhost")]),
93 Room = #jid{user = "dev", server = "localhost", resource = "", luser = "dev", lserver = "localhost", lresource = ""},
94 ejabberd_router:route(To, Room, jlib:iq_to_xml(get_gamelist_result_iq())),
95 % Aknowledge registration
96 IQ#iq{type = result, sub_el = []};
97 <<"unregister">> ->
98 ?INFO_MSG("Attempting to unregister game...", []),
99 mnesia:dirty_delete(games, From),
100 IQ#iq{type = result, sub_el = []};
101 _Else ->
102 IQ#iq{type = error, sub_el = [IQ#iq.sub_el, ?ERR_NOT_ACCEPTABLE]}
103 end;
104 get ->
105 % Dump database
106 ?INFO_MSG("Attempting to send game listings...", []),
107 get_gamelist_result_iq();
108 _Else ->
109 IQ#iq{type = error, sub_el = [IQ#iq.sub_el, ?ERR_NOT_ACCEPTABLE]}
110 end.
111
112get_gamelist_result_iq() ->
113 %% Create a Query List Comprehension handle for the database, and
114 %% evaluate it to get all the database contents
115 {atomic, Games} = mnesia:transaction(fun() -> qlc:eval(mnesia:table(games)) end),
116 ?INFO_MSG("Recieved: ~p from DB.~n", [Games]),
117 GamesXml = lists:map(fun(Game) -> Game#dbentry.value end, Games),
118 SubEl = #xmlelement{name = <<"query">>, attrs = [{<<"xmlns">>, ?GAMELIST_NS}], children = GamesXml},
119 #iq{type = result, xmlns = ?GAMELIST_NS, sub_el = [SubEl]}.