do local function prot_url(url) local url, h = string.gsub(url, "http://", "") local url, hs = string.gsub(url, "https://", "") local protocol = "http" if hs == 1 then protocol = "https" end return url, protocol end local function get_base_redis(id, option, extra) local ex = '' if option ~= nil then ex = ex .. ':' .. option if extra ~= nil then ex = ex .. ':' .. extra end end return 'isup:' .. id .. ex end local function print_cron(id) local uhash = get_base_redis(id) local subs = redis:smembers(uhash) local text = id .. ' prüft folgende Webseiten:\n---------\n' for k,v in pairs(subs) do text = text .. k .. ") " .. v .. '\n' end return text end local function save_cron(id, url) local url = string.lower(url) local baseurl, protocol = prot_url(url) local prothash = get_base_redis(baseurl, "protocol") local checkhash = get_base_redis(baseurl, "check") local uhash = get_base_redis(id) if redis:sismember(uhash, baseurl) then return url..' wird bereits geprüft.' end print('Saving...') redis:set(prothash, protocol) redis:sadd(checkhash, id) redis:sadd(uhash, baseurl) return url.." wird jetzt alle fünf Minuten geprüft!" end local function delete_cron(id, n) n = tonumber(n) local uhash = get_base_redis(id) local subs = redis:smembers(uhash) if n < 1 or n > #subs then return "ID zu hoch!" end local sub = subs[n] local lhash = get_base_redis(sub, "check") redis:srem(uhash, sub) redis:srem(lhash, id) local left = redis:smembers(lhash) if #left < 1 then -- no one subscribed, remove it local prothash = get_base_redis(sub, "protocol") local downhash = get_base_redis(sub, "down") redis:del(prothash) redis:del(downhash) end return sub.." wird nicht mehr geprüft." end local function is_up_socket(ip, port) print('Connect to', ip, port) local c = socket.try(socket.tcp()) c:settimeout(3) local conn = c:connect(ip, port) if not conn then return false else c:close() return true end end local function is_up_http(url) -- Parse URL from input, default to http local parsed_url = URL.parse(url, { scheme = 'http', authority = '' }) -- Fix URLs without subdomain not parsed properly if not parsed_url.host and parsed_url.path then parsed_url.host = parsed_url.path parsed_url.path = "" end -- Re-build URL local url = URL.build(parsed_url) local protocols = { ["https"] = https, ["http"] = http } local options = { url = url, redirect = false, method = "GET" } local response = { protocols[parsed_url.scheme].request(options) } local code = tonumber(response[2]) if code == nil or code >= 400 then return false end return true end local function isup(url) local pattern = '^(%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?):?(%d?%d?%d?%d?%d?)$' local ip,port = string.match(url, pattern) local result = nil -- !isup 8.8.8.8:53 if ip then port = port or '80' result = is_up_socket(ip, port) else result = is_up_http(url) end return result end local function cron() local keys = redis:keys(get_base_redis("*", "check")) for k,v in pairs(keys) do local base = string.match(v, "isup:(.+):check") -- Get the URL base print('ISUP: '..base) local prot = redis:get(get_base_redis(base, "protocol")) local url = prot .. "://" .. base local hash = 'isup:'..base..':down' local isdown = redis:get(hash) if not isup(url) then if isdown ~= 'true' then redis:set(hash, 'true') local text = url..' ist DOWN! ❌' for e, receiver in pairs(redis:smembers(v)) do send_msg(receiver, text, ok_cb, false) end else print(base..' ist immer noch down') end else if isdown == 'true' then redis:set(hash, 'false') local text = url..' ist wieder UP! ✅' for e, receiver in pairs(redis:smembers(v)) do send_msg(receiver, text, ok_cb, false) end end end end end local function run(msg, matches) local id = "user#id" .. msg.from.id if is_chat_msg(msg) then id = "chat#id" .. msg.to.id end if matches[1] == 'cron show' then if not is_sudo(msg) then return 'Du darfst diesen Befehl nicht benutzen!' end return print_cron(id) elseif matches[1] == 'cron check' then if not is_sudo(msg) then return 'Du darfst diesen Befehl nicht benutzen!' end return cron() elseif matches[1] == 'cron delete' then if not is_sudo(msg) then return 'Du darfst diesen Befehl nicht benutzen!' end return delete_cron(id, matches[2]) elseif matches[1] == 'cron' then if not is_sudo(msg) then return 'Du darfst diesen Befehl nicht benutzen!' end return save_cron(id, matches[2]) elseif isup(matches[1]) then return matches[1]..' ist UP! ✅' else return matches[1]..' ist DOWN! ❌' end end return { description = "Checkt, ob eine Webseite up ist.", usage = { "/isup [Host]: Checkt, ob die Seite up ist", "/isup cron [Host]: Checkt diese Seite alle 5 Minuten (nur Superuser)", "/isup cron check: Prüfe alle Seiten jetzt", "/isup cron show: Listet alle zu prüfenden Seiten auf", "/isup cron delete [ID]: Checkt diese Seite nicht mehr" }, patterns = { "^/isup (cron check)$", "^/isup (cron show)$", "^/isup (cron delete) (%d+)$", "^/isup (cron) (.*)$", "^/isup (.*)$", "^/ping (.*)$" }, run = run, cron = cron } end