Software /
code /
prosody-modules
Comparison
mod_storage_muconference_readonly/mod_storage_muconference_readonly.lua @ 2222:51596d73157e
mod_storage_muconference_readonly: Initial commit
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Thu, 30 Jun 2016 05:22:12 +0100 |
child | 2245:a0727d23ee65 |
comparison
equal
deleted
inserted
replaced
2221:3d80f8dba886 | 2222:51596d73157e |
---|---|
1 | |
2 -- luacheck: ignore 212/self | |
3 | |
4 local sql = require "util.sql"; | |
5 local xml_parse = require "util.xml".parse; | |
6 local resolve_relative_path = require "util.paths".resolve_relative_path; | |
7 local stanza_preserialize = require "util.stanza".preserialize; | |
8 | |
9 local unpack = unpack | |
10 local function iterator(result) | |
11 return function(result_) | |
12 local row = result_(); | |
13 if row ~= nil then | |
14 return unpack(row); | |
15 end | |
16 end, result, nil; | |
17 end | |
18 | |
19 local default_params = { driver = "MySQL" }; | |
20 | |
21 local engine; | |
22 | |
23 local host = module.host; | |
24 local room, store; | |
25 | |
26 local function get_best_affiliation(a, b) | |
27 if a == 'owner' or b == 'owner' then | |
28 return 'owner'; | |
29 elseif a == 'administrator' or b == 'administrator' then | |
30 return 'administrator'; | |
31 elseif a == 'outcast' or b == 'outcast' then | |
32 return 'outcast'; | |
33 elseif a == 'member' or b == 'member' then | |
34 return 'member'; | |
35 end | |
36 assert(false); | |
37 end | |
38 | |
39 local function keyval_store_get() | |
40 if store == "muc" then | |
41 local room_jid = room.."@"..host; | |
42 local result; | |
43 for row in engine:select("SELECT `name`,`desc`,`topic`,`public`,`secret` FROM `rooms` WHERE `jid`=? LIMIT 1", room_jid or "") do result = row end | |
44 local name = result[1]; | |
45 local desc = result[2]; | |
46 local subject = result[3]; | |
47 local public = result[4]; | |
48 local hidden = public == 0 and true or nil; | |
49 local secret = result[5]; | |
50 if secret == '' then secret = nil end | |
51 local affiliations = {}; | |
52 for row in engine:select("SELECT `jid_user`,`affil` FROM `rooms_lists` WHERE `jid_room`=?", room_jid or "") do | |
53 local jid_user = row[1]; | |
54 local affil = row[2]; | |
55 -- mu-conference has a bug where full JIDs get stored… | |
56 local bare_jid = jid_user:gsub('/.*', ''); | |
57 local old_affil = affiliations[bare_jid]; | |
58 -- mu-conference has a bug where it can record multiple affiliations… | |
59 if old_affil ~= nil and old_affil ~= affil then | |
60 affil = get_best_affiliation(old_affil, affil); | |
61 end | |
62 -- terminology is clearly “admin”, not “administrator”. | |
63 if affil == 'administrator' then | |
64 affil = 'admin'; | |
65 end | |
66 affiliations[bare_jid] = affil; | |
67 end | |
68 return { | |
69 jid = room_jid, | |
70 _data = { | |
71 persistent = true, | |
72 name = name, | |
73 subject = subject, | |
74 password = secret, | |
75 hidden = hidden, | |
76 }, | |
77 _affiliations = affiliations, | |
78 }; | |
79 end | |
80 end | |
81 | |
82 --- Key/value store API (default store type) | |
83 | |
84 local keyval_store = {}; | |
85 keyval_store.__index = keyval_store; | |
86 function keyval_store:get(roomname) | |
87 room, store = roomname, self.store; | |
88 local ok, result = engine:transaction(keyval_store_get); | |
89 if not ok then | |
90 module:log("error", "Unable to read from database %s store for %s: %s", store, roomname or "<host>", result); | |
91 return nil, result; | |
92 end | |
93 return result; | |
94 end | |
95 | |
96 function keyval_store:users() | |
97 local host_length = host:len() + 1; | |
98 local ok, result = engine:transaction(function() | |
99 return engine:select("SELECT SUBSTRING_INDEX(jid, '@', 1) FROM `rooms`"); | |
100 end); | |
101 if not ok then return ok, result end | |
102 return iterator(result); | |
103 end | |
104 | |
105 local stores = { | |
106 keyval = keyval_store; | |
107 }; | |
108 | |
109 --- Implement storage driver API | |
110 | |
111 -- FIXME: Some of these operations need to operate on the archive store(s) too | |
112 | |
113 local driver = {}; | |
114 | |
115 function driver:open(store, typ) | |
116 local store_mt = stores[typ or "keyval"]; | |
117 if store_mt then | |
118 return setmetatable({ store = store }, store_mt); | |
119 end | |
120 return nil, "unsupported-store"; | |
121 end | |
122 | |
123 function driver:stores(roomname) | |
124 local query = "SELECT 'config'"; | |
125 if roomname == true or not roomname then | |
126 roomname = ""; | |
127 end | |
128 local ok, result = engine:transaction(function() | |
129 return engine:select(query, host, roomname); | |
130 end); | |
131 if not ok then return ok, result end | |
132 return iterator(result); | |
133 end | |
134 | |
135 --- Initialization | |
136 | |
137 | |
138 local function normalize_params(params) | |
139 assert(params.driver and params.database, "Configuration error: Both the SQL driver and the database need to be specified"); | |
140 return params; | |
141 end | |
142 | |
143 function module.load() | |
144 if prosody.prosodyctl then return; end | |
145 local engines = module:shared("/*/sql/connections"); | |
146 local params = normalize_params(module:get_option("sql", default_params)); | |
147 engine = engines[sql.db2uri(params)]; | |
148 if not engine then | |
149 module:log("debug", "Creating new engine"); | |
150 engine = sql:create_engine(params); | |
151 engines[sql.db2uri(params)] = engine; | |
152 end | |
153 | |
154 module:provides("storage", driver); | |
155 end |