plugins/factoids.lua

changeset 90
dd8172982299
child 121
d68a4ae37f4a
equal deleted inserted replaced
89:5a573f1d7592 90:dd8172982299
1 local storage_backends = {};
2 function riddim.plugins.factoids(bot)
3 local factoids = {};
4 local conf_backend = bot.config.factoid_backend;
5 local backend;
6
7 -- if backend == nil then forget everything on restart
8
9 if conf_backend and storage_backends[conf_backend] then
10 backend = storage_backends[conf_backend](bot, factoids);
11 end
12
13 bot:hook("unhandled-command", function(cmd)
14 local name, param = cmd.command, cmd.param;
15 local factoid = factoids[name];
16 if factoid then
17 return factoid;
18 elseif param and #param > 4 and param:match("^is ") then
19 factoids[name] = param:sub(4);
20 return "I'll remember that.";
21 end
22 end);
23 bot:hook("commands/forget", function(cmd)
24 local name = cmd.param;
25 local factoid = factoids[name];
26 if factoid then
27 factoids[name] = nil;
28 if backend and backend.del then
29 backend.del(name);
30 end
31 return ("Okay, I'll forget that %s is %s"):format(name, factoid);
32 end
33 end);
34 end
35
36 -- A simple file backend
37 function storage_backends.file(bot, factoids)
38 local factoids_file = bot.config.factoids_file or "./factoids.txt";
39 local function format_line(k, v)
40 return ("%s=%s\n"):format(k, v)
41 end
42 local actions = {
43 load = function()
44 local fd = io.open(factoids_file, "r");
45 if fd then
46 for line in fd:lines() do
47 local k, v = line:match("^(.+)=(.*)$");
48 if k and v then
49 factoids[k] = v;
50 end
51 end
52 fd:close();
53 end
54 end,
55 save = function()
56 local fd = io.open(factoids_file, "w");
57 if fd then
58 for k,v in pairs(factoids) do
59 fd:write(format_line(k, v));
60 end
61 fd:close();
62 end
63 end,
64 add = function(k, v)
65 local fd = io.open(factoids_file, "a");
66 fd:write(format_line(k, v));
67 fd:close();
68 end,
69 };
70 function actions.del(...) actions.save(); end
71 actions.load();
72 setmetatable(factoids, {
73 __newindex = function(t, k, v)
74 v = v:gsub("\n"," ");
75 rawset(t, k, v);
76 actions.add(k, v);
77 end,
78 });
79 return actions;
80 end
81
82 -- A variant of the above except serializing lua code
83 function storage_backends.lua(bot, factoids)
84 local factoids_file = bot.config.factoids_file or "./factoids.dat";
85 local function format_line(k, v)
86 return ("_G[%q] = %q;\n"):format(k, v);
87 end
88 local actions = {
89 load = function()
90 local chunk, err = loadfile(factoids_file);
91 if chunk then
92 local old_mt = getmetatable(factoids);
93 setmetatable(factoids, {
94 __newindex = function (...) rawset(...); print(...) end
95 });
96 setfenv(chunk, {_G = factoids} );
97 chunk();
98 setmetatable(factoids, old_mt);
99 else
100 print(err);
101 end
102 end,
103 save = function()
104 local fd, err = io.open(factoids_file, "w");
105 if err then print(err) end
106 if fd then
107 for k,v in pairs(factoids) do
108 fd:write(format_line(k, v));
109 end
110 fd:close();
111 end
112 end,
113 add = function(k,v)
114 local fd, err = io.open(factoids_file, "a");
115 if err then print(err) end
116 if fd then
117 fd:write(format_line(k, v));
118 fd:close();
119 end
120 end,
121 del = function(k)
122 local fd, err = io.open(factoids_file, "a");
123 if err then print(err) end
124 if fd then
125 fd:write(("_G[%q] = nil;\n"):format(k));
126 fd:close();
127 end
128 end,
129 }
130 actions.load();
131 setmetatable(factoids, {
132 __newindex = function(t, k, v)
133 print("__newindex", t, k, v);
134 rawset(t, k, v);
135 actions.add(k, v);
136 end,
137 });
138 return actions;
139 end
140
141 -- Yet another variant, using util.serialization
142 function storage_backends.serialize(bot, factoids)
143 local serialize = require "util.serialization".serialize;
144 local deserialize = require "util.serialization".deserialize;
145 local factoids_file = bot.config.factoids_file or "./factoids.dat";
146 local actions = {
147 load = function()
148 local fd = io.open(factoids_file, "r");
149 if fd then
150 local old_mt = getmetatable(factoids);
151 setmetatable(factoids, {});
152 factoids = deserialize(fd:read("*a"));
153 setmetatable(factoids, old_mt);
154 df:close();
155 end
156 end,
157 save = function()
158 local fd, err = io.open(factoids_file, "w");
159 if err then print(err) end
160 if fd then
161 fd:write(serialize(factoids));
162 fd:close();
163 end
164 end,
165 }
166 function actions.add(...) actions.save(); end
167 function actions.del(...) actions.save(); end
168 actions.load();
169 setmetatable(factoids, {
170 __newindex = function(t, k, v)
171 print("__newindex", t, k, v);
172 rawset(t, k, v);
173 actions.add(k, v);
174 end,
175 });
176 return actions;
177 end
178
179 -- A backend using XEP 49 storage
180 function storage_backends.iq_private(bot, factoids)
181 bot.stream:add_plugin("private");
182 local factoids_node = "factoids";
183 local factoids_xmlns = "http://code.zash.se/riddim/plugins/factoids";
184 local actions = {
185 load = function()
186 bot.stream:private_get(factoids_node, factoids_xmlns, function (storage)
187 if storage then
188 local old_mt = getmetatable(factoids);
189 setmetatable(factoids, {
190 __newindex = function (...) rawset(...); print(...) end
191 });
192 for factoid in storage:children() do
193 factoids[factoid.attr.name or "something-invalid"] = factoid:get_text();
194 end
195 setmetatable(factoids, old_mt);
196 end
197 end);
198 end,
199 save = function()
200 local st = verse.stanza(factoids_node, { xmlns = factoids_xmlns });
201 for name, text in pairs(factoids) do
202 st:tag("factoid", { name = name }):text(text):up();
203 end
204 bot.stream:private_set(factoids_node, factoids_xmlns, st);
205 end,
206 }
207 function actions.add(...) actions.save(); end
208 function actions.del(...) actions.save(); end
209 bot:hook("started", function()
210 actions.load();
211 setmetatable(factoids, {
212 __newindex = function(t, k, v)
213 print("__newindex", t, k, v);
214 rawset(t, k, v);
215 actions.add(k, v);
216 end,
217 });
218 end);
219 return actions;
220 end

mercurial