Comparison

plugins/storage/mod_ejabberd.lua @ 3415:5ba0e094a5e2

storage/mod_ejabberd (and associated library): Initial commit.
author Waqas Hussain <waqas20@gmail.com>
date Sat, 31 Jul 2010 13:32:57 +0500
child 3429:8cdb0179371a
comparison
equal deleted inserted replaced
3414:9a1f6239b63c 3415:5ba0e094a5e2
1
2 local setmetatable = setmetatable;
3 local error = error;
4 local unpack = unpack;
5 local module = module;
6 local tostring = tostring;
7 local pairs, next = pairs, next;
8 local prosody = prosody;
9 local assert = assert;
10 local require = require;
11
12 -- connect to db
13 local DBI = require "DBI";
14 local option_datastore_params = module:get_option("datastore_params") or error("Missing option: datastore_params");
15 local database;
16 do
17 local driver, db = unpack(option_datastore_params);
18 module:log("debug", "Opening database: %s", "dbi:"..driver..":"..db);
19 prosody.unlock_globals();
20 local dbh, err = DBI.Connect(unpack(option_datastore_params));
21 prosody.lock_globals();
22 assert(dbh, err);
23 dbh:autocommit(true)
24 database = dbh;
25 end
26
27 -- initialize db
28 local ejabberd_init = module:require("ejabberd_init");
29 ejabberd_init.init(database);
30
31 local st = require "util.stanza";
32 local _parse_xml = module:require("xmlparse");
33 local parse_xml_real = _parse_xml;
34 local function parse_xml(str)
35 local s = _parse_xml(str);
36 if s and not s.gsub then
37 return st.preserialize(s);
38 end
39 end
40 local function unparse_xml(s)
41 return tostring(st.deserialize(s));
42 end
43
44
45 local handlers = {};
46
47 handlers.accounts = {
48 get = function(self, user)
49 local select = self:query("select password from users where username=? and host=?", user, self.host);
50 local row = select and select:fetch();
51 if row then return { password = row[1] }; end
52 end;
53 set = function(self, user, data)
54 if data and data.password then
55 return self:modify("update users set password=? where username=? and host=?", data.password, user, self.host)
56 or self:modify("insert into users (username, host, password) values (?, ?, ?)", user, self.host, data.password);
57 else
58 return self:modify("delete from users where username=? and host=?", user, self.host);
59 end
60 end;
61 };
62 handlers.vcard = {
63 get = function(self, user)
64 local select = self:query("select vcard from vcard where username=? and host=?", user, self.host);
65 local row = select and select:fetch();
66 if row then return parse_xml(row[1]); end
67 end;
68 set = function(self, user, data)
69 if data then
70 data = unparse_xml(data);
71 return self:modify("update vcard set vcard=? where username=? and host=?", data, user, self.host)
72 or self:modify("insert into vcard (username, host, vcard) values (?, ?, ?)", user, self.host, data);
73 else
74 return self:modify("delete from vcard where username=? and host=?", user, self.host);
75 end
76 end;
77 };
78 handlers.private = {
79 get = function(self, user)
80 local select = self:query("select namespace,data from private_storage where username=? and host=?", user, self.host);
81 if select then
82 local data = {};
83 for row in select:rows() do
84 data[row[1]] = parse_xml(row[2]);
85 end
86 return data;
87 end
88 end;
89 set = function(self, user, data)
90 if data then
91 self:modify("delete from private_storage where username=? and host=?", user, self.host);
92 for namespace,text in pairs(data) do
93 self:modify("insert into private_storage (username, host, namespace, data) values (?, ?, ?, ?)", user, self.host, namespace, unparse_xml(text));
94 end
95 return true;
96 else
97 return self:modify("delete from private_storage where username=? and host=?", user, self.host);
98 end
99 end;
100 -- TODO map_set, map_get
101 };
102 local subscription_map = { N = "none", B = "both", F = "from", T = "to" };
103 local subscription_map_reverse = { none = "N", both = "B", from = "F", to = "T" };
104 handlers.roster = {
105 get = function(self, user)
106 local select = self:query("select jid,nick,subscription,ask,server,subscribe,type from rosterusers where username=?", user);
107 if select then
108 local roster = { pending = {} };
109 for row in select:rows() do
110 local jid,nick,subscription,ask,server,subscribe,typ = unpack(row);
111 local item = { groups = {} };
112 if nick == "" then nick = nil; end
113 item.nick = nick;
114 item.subscription = subscription_map[subscription];
115 if ask == "N" then ask = nil;
116 elseif ask == "O" then ask = "subscribe"
117 elseif ask == "I" then roster.pending[jid] = true; ask = nil;
118 elseif ask == "B" then roster.pending[jid] = true; ask = "subscribe";
119 else module:log("debug", "bad roster_item.ask: %s", ask); ask = nil; end
120 item.ask = ask;
121 roster[jid] = item;
122 end
123
124 select = self:query("select jid,grp from rostergroups where username=?", user);
125 if select then
126 for row in select:rows() do
127 local jid,grp = unpack(row);
128 if roster[jid] then roster[jid].groups[grp] = true; end
129 end
130 end
131 select = self:query("select version from roster_version where username=?", user);
132 local row = select and select:fetch();
133 if row then
134 roster[false] = { version = row[1]; };
135 end
136 return roster;
137 end
138 end;
139 set = function(self, user, data)
140 if data and next(data) ~= nil then
141 self:modify("delete from rosterusers where username=?", user);
142 self:modify("delete from rostergroups where username=?", user);
143 self:modify("delete from roster_version where username=?", user);
144 local done = {};
145 local pending = data.pending or {};
146 for jid,item in pairs(data) do
147 if jid and jid ~= "pending" then
148 local subscription = subscription_map_reverse[item.subscription];
149 local ask;
150 if pending[jid] then
151 if item.ask then ask = "B"; else ask = "I"; end
152 else
153 if item.ask then ask = "O"; else ask = "N"; end
154 end
155 local r = self:modify("insert into rosterusers (username,jid,nick,subscription,ask,askmessage,server,subscribe) values (?, ?, ?, ?, ?, '', '', '')", user, jid, item.nick or "", subscription, ask);
156 if not r then module:log("debug", "--- :( %s", tostring(r)); end
157 done[jid] = true;
158 for group in pairs(item.groups) do
159 self:modify("insert into rostergroups (username,jid,grp) values (?, ?, ?)", user, jid, group);
160 end
161 end
162 end
163 for jid in pairs(pending) do
164 if not done[jid] then
165 self:modify("insert into rosterusers (username,jid,nick,subscription,ask,askmessage,server,subscribe) values (?, ?, ?, ?, ?. ''. ''. '')", user, jid, "", "N", "I");
166 end
167 end
168 local version = data[false] and data[false].version;
169 if version then
170 self:modify("insert into roster_version (username,version) values (?, ?)", user, version);
171 end
172 return true;
173 else
174 self:modify("delete from rosterusers where username=?", user);
175 self:modify("delete from rostergroups where username=?", user);
176 self:modify("delete from roster_version where username=?", user);
177 end
178 end;
179 };
180
181 -----------------------------
182 local driver = {};
183 driver.__index = driver;
184
185 function driver:prepare(sql)
186 module:log("debug", "query: %s", sql);
187 local err;
188 if not self.sqlcache then self.sqlcache = {}; end
189 local r = self.sqlcache[sql];
190 if r then return r; end
191 r, err = database:prepare(sql);
192 if not r then error("Unable to prepare SQL statement: "..err); end
193 self.sqlcache[sql] = r;
194 return r;
195 end
196
197 function driver:query(sql, ...)
198 local stmt,err = self:prepare(sql);
199 if not stmt then
200 module:log("error", "Failed to prepare SQL [[%s]], error: %s", sql, err);
201 return nil, err;
202 end
203 local ok, err = stmt:execute(...);
204 if not ok then
205 module:log("error", "Failed to execute SQL [[%s]], error: %s", sql, err);
206 return nil, err;
207 end
208 return stmt;
209 end
210 function driver:modify(sql, ...)
211 local stmt, err = self:query(sql, ...);
212 if stmt and stmt:affected() > 0 then return stmt; end
213 return nil, err;
214 end
215
216 function driver:open(datastore, typ)
217 local instance = setmetatable({}, self);
218 instance.host = module.host;
219 instance.datastore = datastore;
220 local handler = handlers[datastore];
221 if not handler then return nil; end
222 for key,val in pairs(handler) do
223 instance[key] = val;
224 end
225 if instance.init then instance:init(); end
226 return instance;
227 end
228
229 -----------------------------
230
231 module:add_item("data-driver", driver);