| 1 | local error, type = error, type; |
| 2 | local setmetatable = setmetatable; |
| 3 | |
| 4 | local config = require "core.configmanager"; |
| 5 | local datamanager = require "util.datamanager"; |
| 6 | local modulemanager = require "core.modulemanager"; |
| 7 | local multitable = require "util.multitable"; |
| 8 | local hosts = hosts; |
| 9 | local log = require "util.logger".init("storagemanager"); |
| 10 | |
| 11 | local olddm = {}; -- maintain old datamanager, for backwards compatibility |
| 12 | for k,v in pairs(datamanager) do olddm[k] = v; end |
| 13 | local prosody = prosody; |
| 14 | |
| 15 | module("storagemanager") |
| 16 | |
| 17 | local default_driver_mt = { name = "internal" }; |
| 18 | default_driver_mt.__index = default_driver_mt; |
| 19 | function default_driver_mt:open(store) |
| 20 | return setmetatable({ host = self.host, store = store }, default_driver_mt); |
| 21 | end |
| 22 | function default_driver_mt:get(user) return olddm.load(user, self.host, self.store); end |
| 23 | function default_driver_mt:set(user, data) return olddm.store(user, self.host, self.store, data); end |
| 24 | |
| 25 | local stores_available = multitable.new(); |
| 26 | |
| 27 | function initialize_host(host) |
| 28 | local host_session = hosts[host]; |
| 29 | host_session.events.add_handler("item-added/data-driver", function (event) |
| 30 | local item = event.item; |
| 31 | stores_available:set(host, item.name, item); |
| 32 | end); |
| 33 | |
| 34 | host_session.events.add_handler("item-removed/data-driver", function (event) |
| 35 | local item = event.item; |
| 36 | stores_available:set(host, item.name, nil); |
| 37 | end); |
| 38 | end |
| 39 | prosody.events.add_handler("host-activated", initialize_host, 101); |
| 40 | |
| 41 | local function load_driver(host, driver_name) |
| 42 | if not driver_name then |
| 43 | return; |
| 44 | end |
| 45 | local driver = stores_available:get(host, driver_name); |
| 46 | if driver then return driver; end |
| 47 | if driver_name ~= "internal" then |
| 48 | local ok, err = modulemanager.load(host, "storage_"..driver_name); |
| 49 | if not ok then |
| 50 | log("error", "Failed to load storage driver plugin %s: %s", driver_name, err); |
| 51 | end |
| 52 | return stores_available:get(host, driver_name); |
| 53 | else |
| 54 | return setmetatable({host = host}, default_driver_mt); |
| 55 | end |
| 56 | end |
| 57 | |
| 58 | function open(host, store, typ) |
| 59 | local storage = config.get(host, "core", "storage"); |
| 60 | local driver_name; |
| 61 | local option_type = type(storage); |
| 62 | if option_type == "string" then |
| 63 | driver_name = storage; |
| 64 | elseif option_type == "table" then |
| 65 | driver_name = storage[store]; |
| 66 | end |
| 67 | |
| 68 | local driver = load_driver(host, driver_name); |
| 69 | if not driver then |
| 70 | driver_name = config.get(host, "core", "default_storage"); |
| 71 | driver = load_driver(host, driver_name); |
| 72 | if not driver then |
| 73 | if driver_name or (type(storage) == "string" |
| 74 | or type(storage) == "table" and storage[store]) then |
| 75 | log("warn", "Falling back to default driver for %s storage on %s", store, host); |
| 76 | end |
| 77 | driver_name = "internal"; |
| 78 | driver = load_driver(host, driver_name); |
| 79 | end |
| 80 | end |
| 81 | |
| 82 | local ret, err = driver:open(store, typ); |
| 83 | if not ret then |
| 84 | if err == "unsupported-store" then |
| 85 | log("debug", "Storage driver %s does not support store %s (%s), falling back to internal driver", |
| 86 | driver_name, store, typ); |
| 87 | ret = setmetatable({ host = host, store = store }, default_driver_mt); -- default to default driver |
| 88 | err = nil; |
| 89 | end |
| 90 | end |
| 91 | return ret, err; |
| 92 | end |
| 93 | |
| 94 | function datamanager.load(username, host, datastore) |
| 95 | return open(host, datastore):get(username); |
| 96 | end |
| 97 | function datamanager.store(username, host, datastore, data) |
| 98 | return open(host, datastore):set(username, data); |
| 99 | end |
| 100 | |
| 101 | return _M; |