cstar / modular_muc

Refactoring of ejabberd's mod_muc, with flexible storage and chatroom handling.

This URL has Read+Write access

modular_muc / src / s3_muc_storage.erl
100644 93 lines (80 sloc) 2.704 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
%% @doc Multi User Chatroom persistent storage on S3.
%% You need to specify the s3_bucket option in the ejabberd.cfg mod_muc options
%% And set {storage, s3_muc_storage}.
%% You'll need to have the <a href="http://github.com/cstar/erls3/">erls3 application</a> installed.
-module(s3_muc_storage).
-author('eric@ohmforce.com').
 
-behaviour(gen_muc_storage).
 
 
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("mod_muc.hrl").
-export([init/3,
         store_room/5,
         restore_room/3,
         forget_room/3,
         fetch_all_rooms/2
         ]).
 
 
 
% @spec (Host, ServerHost, Opts)-> ok | {error, Reason}
% @doc called by {@link mod_muc:init/2}.
%
init(_Host, _ServerHost, Opts)->
    ?DEBUG("init S3", []),
    case gen_mod:get_opt(s3_bucket, Opts, none) of
        none -> {error, "s3_bucket option not set in ejabberd.cfg for mod_muc"};
        B ->
            ets:new(s3_muc, [set, named_table, public]),
            ets:insert(s3_muc, {bucket, B}),
            s3:start(),
            ok
    end.
% @spec (Host,ServerHost, Name, Type, Opts)-> ok | {error, Reason}
% @doc Stores room.
% Called on configuration change when MUC is persistent.
store_room(Host,ServerHost, Name, Type, Opts)->
    Bucket = get_bucket(),
    Key = build_key(Host, Name),
    Data = {Type, Opts},
    Res = s3:write_term(Bucket, Key, Data),
    Res.
    
 
% @spec (Host,ServerHost, Name)-> {Handler, Config}
% @doc restores room from storage
restore_room(Host,ServerHost, Name)->
    ?DEBUG("restore_room S3", []),
    case s3:read_object(get_bucket(), build_key(Host, Name)) of
     {ok, {Conf, _H}}->
      binary_to_term(list_to_binary(Conf));
     _ ->
      error
    end.
% @spec (Host, ServerHost, Name)-> ok
% @doc removes room from storage
forget_room(Host, ServerHost, Name) ->
    ?DEBUG("forget_room muc_s3", []),
     s3:delete_object(get_bucket(), build_key(Host, Name)).
 
% @spec (Host,ServerHost)-> [MucRoom]
% MucRoom = #muc_room{}
% @doc Used for disco
fetch_all_rooms(Host, ServerHost)->
    ?DEBUG("fetch_all_rooms muc_s3", []),
    case s3:get_objects(get_bucket(),[{prefix,build_key(Host,"")}] ) of
{'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]),
[];
{error, timeout} ->
?ERROR_MSG("Timeout on S3", []),
[];
Rs->
lists:map(fun({Key, Value, Headers})->
{Type, Opts} = binary_to_term(list_to_binary(Value)),
#muc_room{name_host = split_key(Key), opts=Opts, type=Type}
end, Rs)
end.
    
    
%%%INTERNAL
get_bucket()->
     [{bucket, Bucket}] = ets:lookup(s3_muc, bucket),
     Bucket.
     
build_key(Host, Name)->
    "muc@"++Host++"@"++Name.
 
split_key(Key)->
    [_, Host, Name] = string:tokens(Key, "@"),
    {Name, Host}.