-- Load vhosts from DB on startup of Prosody XMPP server. -- Copyright (C) 2013-2015 Sipwise GmbH -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- module:set_global(); local DBI = require "DBI" local nameprep = require "util.encodings".stringprep.nameprep; local hostmanager = require "core.hostmanager"; local configmanager = require "core.configmanager"; local ut = require "ngcp.utils"; local set = require "util.set"; local connection; local params = module:get_option("auth_sql", module:get_option("sql")); local prosody = _G.prosody; local vhosts = set.new(); local function test_connection() module:log("debug", "test_connection"); if not connection then return nil; end if connection:ping() then module:log("debug", "test_connection ok"); return true; else module:log("debug", "Database connection closed"); connection = nil; end end local function connect() module:log("debug", "connect"); if not test_connection() then prosody.unlock_globals(); local dbh, err = DBI.Connect( params.driver, params.database, params.username, params.password, params.host, params.port ); prosody.lock_globals(); if not dbh then module:log("debug", "Database connection failed: %s", tostring(err)); return nil, err; end module:log("debug", "Successfully connected to database"); dbh:autocommit(true); -- don't run in transaction connection = dbh; return connection; end end do -- process options to get a db connection params = params or { driver = "SQLite3" }; if params.driver == "SQLite3" then params.database = configmanager.resolve_relative_path( prosody.paths.data or ".", params.database or "prosody.sqlite"); end assert(params.driver and params.database, "Both the SQL driver and the database need to be specified"); assert(connect()); end local function getsql(sql, ...) if params.driver == "PostgreSQL" then sql = sql:gsub("`", "\""); end if not test_connection() then connect(); end -- do prepared statement stuff local stmt, err = connection:prepare(sql); if not stmt and not test_connection() then error("connection failed"); end if not stmt then module:log("error", "QUERY FAILED: %s %s", err, debug.traceback()); return nil, err; end -- run query local ok ok, err = stmt:execute(...); if not ok and not test_connection() then error("connection failed"); end if not ok then return nil, err; end return stmt; end local function activate_search(host) module:log("debug", "activate implicit search.%s", host); configmanager.set("search."..host, "component_module", "sipwise_vjud"); local search_config = configmanager.getconfig()["search."..host]; hostmanager.activate("search."..host, search_config); end local function activate_muc(host) local host_modules = configmanager.get(host, "modules_enabled"); local conference_modules = {}; module:log("debug", "modules_enabled[%s]: %s", host, ut.table.tostring(host_modules)); configmanager.set("conference."..host, "component_module", "muc"); if ut.table.contains(host_modules, "shard") then ut.table.add(conference_modules, "sipwise_redis_mucs"); ut.table.add(conference_modules, "shard"); end if ut.table.contains(host_modules, "sipwise_pushd") then ut.table.add(conference_modules, "sipwise_pushd"); end if ut.table.contains(host_modules, "mam") then ut.table.add(conference_modules, "muc_mam"); end module:log("debug", "conference_modules[%s]: %s", "conference."..host, ut.table.tostring(host_modules)); configmanager.set("conference."..host, "modules_enabled", conference_modules); local conference_config = configmanager.getconfig()["conference."..host]; conference_config['restrict_room_creation'] = 'local'; hostmanager.activate("conference."..host, conference_config); module:log("debug", "modules_enabled[%s]: %s", "conference."..host, ut.table.tostring(conference_config['modules_enabled'])); end local function add_vhost(host) local host_config = { enable = true }; module:log("debug", "activate host %s", host); vhosts:add(host); hostmanager.activate(host, host_config); activate_search(host); activate_muc(host); end local function load_vhosts_from_db() local stmt, _ = getsql("SELECT `domain` FROM `domain`"); if stmt then for row in stmt:rows(true) do local host = nameprep(row.domain); add_vhost(host); end end end local function check_vhosts(host) if ut.string.starts(host, 'search.') or ut.string.starts(host, 'conference.') or vhosts:contains(host) then module:log("debug", "%s activated, nothing to do", host); return end module:log("info", "%s activate subdomains", host); activate_search(host); activate_muc(host); vhosts:add(host); end local function deactivate_vhost(host) if ut.string.starts(host, 'search.') or ut.string.starts(host, 'conference.') or not vhosts:contains(host) then module:log("debug", "%s deactivated, nothing to do", host); return end module:log("info", "%s deactivate subdomains", host); hostmanager.deactivate("search."..host, 'main domain deactivated'); hostmanager.deactivate("conference."..host, 'main domain deactivated'); vhosts:remove(host); end module:hook("server-started", load_vhosts_from_db); module:hook("host-activated", check_vhosts); module:hook("host-deactivated", deactivate_vhost);