#!/usr/bin/env ruby # UptimeRobot dashboard # v1.0 # Sergey Pedan # sergeypedan # Lists your UptimeRobot monitors with their statuses to help you instantly check uptime of your websites. # Ruby 2+ # https://raw.githubusercontent.com/sergeypedan/bitbar-uptime-robot-dashboard/master/screenshot.png # https://github.com/sergeypedan/bitbar-uptime-robot-dashboard require "json" require "net/https" require "uri" module BitBar API_KEY_NAME = "UPTIME_ROBOT_API_KEY".freeze API_ENDPOINT = "https://api.uptimerobot.com/v2/getMonitors".freeze DASHBOARD_URL = "https://uptimerobot.com/dashboard" CONFIG_FILE = "#{`echo $HOME`.chomp}/.config/bitbar.conf" COLOR_DOTS = { gray: "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAAXVBMVEUAAAAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmCynqnaAAAAHnRSTlMAAwYHCQoQEh0fNVBRX2N5fJG+wMfK3O3v8fP3+/37J2BkAAAATklEQVQIHQXBhQHCAADAsA53d1j+P5OkqoaqqmbHr/G8rGr1BuOmmjwB47L2AM51A/CrFwBDFwDf2gI41fAAfObV4gFe66qG3fV9P0yrPxEfCr3MVhkLAAAAAElFTkSuQmCC", green: "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAAXVBMVEUAAAAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmAnrmCynqnaAAAAHnRSTlMAAwYHCQoQEh0fNVBRX2N5fJG+wMfK3O3v8fP3+/37J2BkAAAATklEQVQIHQXBhQHCAADAsA53d1j+P5OkqoaqqmbHr/G8rGr1BuOmmjwB47L2AM51A/CrFwBDFwDf2gI41fAAfObV4gFe66qG3fV9P0yrPxEfCr3MVhkLAAAAAElFTkSuQmCC", orange: "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAAXVBMVEUAAADAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvGu33lAAAAHnRSTlMAAwYHCQoQEh0fNVBRX2N5fJG+wMfK3O3v8fP3+/37J2BkAAAATklEQVQIHQXBhQHCAADAsA53d1j+P5OkqoaqqmbHr/G8rGr1BuOmmjwB47L2AM51A/CrFwBDFwDf2gI41fAAfObV4gFe66qG3fV9P0yrPxEfCr3MVhkLAAAAAElFTkSuQmCC", red: "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAAXVBMVEUAAADAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvAOSvGu33lAAAAHnRSTlMAAwYHCQoQEh0fNVBRX2N5fJG+wMfK3O3v8fP3+/37J2BkAAAATklEQVQIHQXBhQHCAADAsA53d1j+P5OkqoaqqmbHr/G8rGr1BuOmmjwB47L2AM51A/CrFwBDFwDf2gI41fAAfObV4gFe66qG3fV9P0yrPxEfCr3MVhkLAAAAAElFTkSuQmCC" } module Interface def self.write!(status_bar: "", content_lines: [], colophone: "") puts status_bar if status_bar.to_s != "" if content_lines.any? puts "---" content_lines.each do |line| puts line end end if colophone.to_s != "" puts "---" puts colophone end end end module Keys module_function def read_API_key config_file_contents = File.read(CONFIG_FILE) line_with_key = config_file_contents.lines.select { |line| line.include? API_KEY_NAME }.first extract_key_from_config_line(line_with_key) end def extract_key_from_config_line(line) line.to_s.sub(API_KEY_NAME, "").sub("=", "").sub(":", "").gsub("\"", "").gsub(/\s/, "") end end module_function def build_line(text, attributes = {}) str_attributes = stringified_attributes(attributes) return text if str_attributes == "" [text, str_attributes].join(" | ") end def stringified_attributes(hash) return "" if hash.empty? return "" if hash.values.all? { |value| value.to_s == "" } return hash.map { |key, value| "#{key}=#{value}" }.join(" ") end end module NetAccess def self.get_response(api_key:, endpoint:) uri = URI.parse(endpoint) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(uri.request_uri) request["accept"] = "application/json" request["cache-control"] = "no-cache" request["content-type"] = "x-www-form-urlencoded" request.set_form_data({ api_key: api_key, format: "json", logs: 0 }) response = http.request(request) return JSON.parse(response.body) rescue {} end end class UptimeReporter STATUSES = { 0 => { text: "paused", color: "white", image: BitBar::COLOR_DOTS[:gray] }, 1 => { text: "not checked", color: "white", image: BitBar::COLOR_DOTS[:gray] }, 2 => { text: "up", color: "green", image: BitBar::COLOR_DOTS[:green] }, 8 => { text: "seems down", color: "yellow", image: BitBar::COLOR_DOTS[:orange] }, 9 => { text: "down", color: "red", image: BitBar::COLOR_DOTS[:red] } }.freeze def initialize(color_blind: false) @color_blind = color_blind @api_key = BitBar::Keys.read_API_key end def run! monitors = get_monitors write(monitors) end private # @returns Array, like: [3, 5] # for 3 live services out of 5 def count_of_live_servers(monitors) monitors.count { |monitor| server_live? monitor } end def get_monitors uptime_response["monitors"] || [] end # @returns String like "google.com — Up | href='http://google.com' color='green'" def monitor_text(monitor) details = STATUSES[ monitor["status"] ] text = if @color_blind [monitor["friendly_name"], " (", details[:text], ")"].join("") else monitor["friendly_name"] end BitBar.build_line(text, href: monitor["url"], image: details[:image]) end # @returns boolean def server_live?(monitor) monitor["status"] <= 2 end # @returns String def status_bar_text(monitors) "#{count_of_live_servers(monitors)} / #{monitors.size}" end def uptime_response NetAccess.get_response(api_key: @api_key, endpoint: BitBar::API_ENDPOINT) end def write(monitors) BitBar::Interface.write!( status_bar: status_bar_text(monitors), content_lines: monitors.map { |monitor| monitor_text(monitor) }, colophone: BitBar.build_line("Open UptimeRobot", href: BitBar::DASHBOARD_URL) ) end end UptimeReporter.new(color_blind: false).run!