Rewrite [uptimerobot] (#1891)
This commit is contained in:
@@ -1466,21 +1466,6 @@ const allBadgeExamples = [
|
||||
keywords: ['website'],
|
||||
documentation: websiteDoc,
|
||||
},
|
||||
{
|
||||
title: 'Uptime Robot status',
|
||||
previewUri:
|
||||
'/uptimerobot/status/m778918918-3e92c097147760ee39d02d36.svg',
|
||||
},
|
||||
{
|
||||
title: 'Uptime Robot ratio (30 days)',
|
||||
previewUri:
|
||||
'/uptimerobot/ratio/m778918918-3e92c097147760ee39d02d36.svg',
|
||||
},
|
||||
{
|
||||
title: 'Uptime Robot ratio (7 days)',
|
||||
previewUri:
|
||||
'/uptimerobot/ratio/7/m778918918-3e92c097147760ee39d02d36.svg',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
132
server.js
132
server.js
@@ -6682,138 +6682,6 @@ cache(function(data, match, sendBadge, request) {
|
||||
});
|
||||
}));
|
||||
|
||||
// Uptime Robot status integration.
|
||||
// API documentation : https://uptimerobot.com/api
|
||||
camp.route(/^\/uptimerobot\/status\/(.*)\.(svg|png|gif|jpg|json)$/,
|
||||
cache(function(data, match, sendBadge, request) {
|
||||
var monitorApiKey = match[1]; // eg, m778918918-3e92c097147760ee39d02d36
|
||||
var format = match[2];
|
||||
var badgeData = getBadgeData('status', data);
|
||||
var options = {
|
||||
method: 'POST',
|
||||
json: true,
|
||||
body: {
|
||||
"api_key": monitorApiKey,
|
||||
"format": "json",
|
||||
},
|
||||
uri: 'https://api.uptimerobot.com/v2/getMonitors',
|
||||
};
|
||||
// A monitor API key must start with "m"
|
||||
if (monitorApiKey.substring(0, "m".length) !== "m") {
|
||||
badgeData.text[1] = 'must use a monitor key';
|
||||
sendBadge(format, badgeData);
|
||||
return;
|
||||
}
|
||||
request(options, function(err, res, json) {
|
||||
if (err !== null || res.statusCode >= 500 || typeof json !== 'object') {
|
||||
badgeData.text[1] = 'inaccessible';
|
||||
sendBadge(format, badgeData);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (json.stat === 'fail') {
|
||||
badgeData.text[1] = 'vendor error';
|
||||
if (json.error && typeof json.error.message === 'string') {
|
||||
badgeData.text[1] = json.error.message;
|
||||
}
|
||||
badgeData.colorscheme = 'lightgrey';
|
||||
sendBadge(format, badgeData);
|
||||
return;
|
||||
}
|
||||
var status = json.monitors[0].status;
|
||||
if (status === 0) {
|
||||
badgeData.text[1] = 'paused';
|
||||
badgeData.colorscheme = 'yellow';
|
||||
} else if (status === 1) {
|
||||
badgeData.text[1] = 'not checked yet';
|
||||
badgeData.colorscheme = 'yellowgreen';
|
||||
} else if (status === 2) {
|
||||
badgeData.text[1] = 'up';
|
||||
badgeData.colorscheme = 'brightgreen';
|
||||
} else if (status === 8) {
|
||||
badgeData.text[1] = 'seems down';
|
||||
badgeData.colorscheme = 'orange';
|
||||
} else if (status === 9) {
|
||||
badgeData.text[1] = 'down';
|
||||
badgeData.colorscheme = 'red';
|
||||
} else {
|
||||
badgeData.text[1] = 'invalid';
|
||||
badgeData.colorscheme = 'lightgrey';
|
||||
}
|
||||
sendBadge(format, badgeData);
|
||||
} catch(e) {
|
||||
badgeData.text[1] = 'invalid';
|
||||
sendBadge(format, badgeData);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
// Uptime Robot ratio integration.
|
||||
// API documentation : https://uptimerobot.com/api
|
||||
camp.route(/^\/uptimerobot\/ratio(\/[^/]+)?\/(.*)\.(svg|png|gif|jpg|json)$/,
|
||||
cache(function(data, match, sendBadge, request) {
|
||||
var numberOfDays = match[1]; // eg, 7, null if querying 30
|
||||
var monitorApiKey = match[2]; // eg, m778918918-3e92c097147760ee39d02d36
|
||||
var format = match[3];
|
||||
var badgeData = getBadgeData('uptime', data);
|
||||
if (numberOfDays) {
|
||||
numberOfDays = numberOfDays.slice(1);
|
||||
} else {
|
||||
numberOfDays = '30';
|
||||
}
|
||||
var options = {
|
||||
method: 'POST',
|
||||
json: true,
|
||||
body: {
|
||||
"api_key": monitorApiKey,
|
||||
"custom_uptime_ratios": numberOfDays,
|
||||
"format": "json",
|
||||
},
|
||||
uri: 'https://api.uptimerobot.com/v2/getMonitors',
|
||||
};
|
||||
// A monitor API key must start with "m"
|
||||
if (monitorApiKey.substring(0, "m".length) !== "m") {
|
||||
badgeData.text[1] = 'must use a monitor key';
|
||||
sendBadge(format, badgeData);
|
||||
return;
|
||||
}
|
||||
request(options, function(err, res, json) {
|
||||
if (err !== null || res.statusCode >= 500 || typeof json !== 'object') {
|
||||
badgeData.text[1] = 'inaccessible';
|
||||
sendBadge(format, badgeData);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (json.stat === 'fail') {
|
||||
badgeData.text[1] = 'vendor error';
|
||||
if (json.error && typeof json.error.message === 'string') {
|
||||
badgeData.text[1] = json.error.message;
|
||||
}
|
||||
badgeData.colorscheme = 'lightgrey';
|
||||
sendBadge(format, badgeData);
|
||||
return;
|
||||
}
|
||||
var percent = parseFloat(json.monitors[0].custom_uptime_ratio);
|
||||
badgeData.text[1] = percent + '%';
|
||||
if (percent <= 10) {
|
||||
badgeData.colorscheme = 'red';
|
||||
} else if (percent <= 30) {
|
||||
badgeData.colorscheme = 'yellow';
|
||||
} else if (percent <= 50) {
|
||||
badgeData.colorscheme = 'yellowgreen';
|
||||
} else if (percent <= 70) {
|
||||
badgeData.colorscheme = 'green';
|
||||
} else {
|
||||
badgeData.colorscheme = 'brightgreen';
|
||||
}
|
||||
sendBadge(format, badgeData);
|
||||
} catch (e) {
|
||||
badgeData.text[1] = 'invalid';
|
||||
sendBadge(format, badgeData);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
// Discord integration
|
||||
camp.route(/^\/discord\/([^/]+)\.(svg|png|gif|jpg|json)$/,
|
||||
cache((data, match, sendBadge, request) => {
|
||||
|
||||
97
services/uptimerobot/uptimerobot-base.js
Normal file
97
services/uptimerobot/uptimerobot-base.js
Normal file
@@ -0,0 +1,97 @@
|
||||
'use strict'
|
||||
|
||||
const Joi = require('joi')
|
||||
const BaseJsonService = require('../base-json')
|
||||
const { InvalidParameter, InvalidResponse } = require('../errors')
|
||||
|
||||
// https://uptimerobot.com/api
|
||||
// POST getMonitors
|
||||
const errorResponse = Joi.object({
|
||||
stat: Joi.equal('fail').required(),
|
||||
error: Joi.object({
|
||||
message: Joi.string(),
|
||||
}).default({}),
|
||||
}).required()
|
||||
|
||||
const monitor = Joi.object({
|
||||
status: Joi.equal(0, 1, 2, 8, 9).required(),
|
||||
})
|
||||
|
||||
const monitorWithUptime = monitor.keys({
|
||||
custom_uptime_ratio: Joi.string()
|
||||
.regex(/^\d*\.\d{3}$/)
|
||||
.required(),
|
||||
})
|
||||
|
||||
const singleMonitorResponse = Joi.alternatives(
|
||||
errorResponse,
|
||||
Joi.object({
|
||||
stat: Joi.equal('ok').required(),
|
||||
monitors: Joi.array()
|
||||
.length(1)
|
||||
.items(monitor)
|
||||
.required(),
|
||||
}).required()
|
||||
)
|
||||
|
||||
const singleMonitorResponseWithUptime = Joi.alternatives(
|
||||
errorResponse,
|
||||
Joi.object({
|
||||
stat: Joi.equal('ok').required(),
|
||||
monitors: Joi.array()
|
||||
.length(1)
|
||||
.items(monitorWithUptime)
|
||||
.required(),
|
||||
}).required()
|
||||
)
|
||||
|
||||
module.exports = class UptimeRobotBase extends BaseJsonService {
|
||||
static get category() {
|
||||
return 'monitoring'
|
||||
}
|
||||
|
||||
static ensureIsMonitorApiKey(value) {
|
||||
// A monitor API key must start with "m".
|
||||
if (!value.startsWith('m')) {
|
||||
throw new InvalidParameter({
|
||||
prettyMessage: 'must use a monitor-specific api key',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ monitorApiKey, numberOfDays }) {
|
||||
this.constructor.ensureIsMonitorApiKey(monitorApiKey)
|
||||
|
||||
let opts, schema
|
||||
if (numberOfDays) {
|
||||
opts = { custom_uptime_ratios: numberOfDays }
|
||||
schema = singleMonitorResponseWithUptime
|
||||
} else {
|
||||
opts = {}
|
||||
schema = singleMonitorResponse
|
||||
}
|
||||
const { stat, error, monitors } = await this._requestJson({
|
||||
schema,
|
||||
url: 'https://api.uptimerobot.com/v2/getMonitors',
|
||||
options: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'cache-control': 'no-cache',
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
form: {
|
||||
api_key: monitorApiKey,
|
||||
format: 'json',
|
||||
...opts,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (stat === 'fail') {
|
||||
const { message } = error
|
||||
throw new InvalidResponse({ prettyMessage: message || 'service error' })
|
||||
}
|
||||
|
||||
return { monitors }
|
||||
}
|
||||
}
|
||||
48
services/uptimerobot/uptimerobot-ratio.service.js
Normal file
48
services/uptimerobot/uptimerobot-ratio.service.js
Normal file
@@ -0,0 +1,48 @@
|
||||
'use strict'
|
||||
|
||||
const { colorScale } = require('../../lib/color-formatters')
|
||||
const UptimeRobotBase = require('./uptimerobot-base')
|
||||
|
||||
const ratioColor = colorScale([10, 30, 50, 70])
|
||||
|
||||
module.exports = class UptimeRobotRatio extends UptimeRobotBase {
|
||||
static get defaultBadgeData() {
|
||||
return {
|
||||
label: 'uptime',
|
||||
}
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'uptimerobot/ratio',
|
||||
format: '(?:([\\d+])/)?(.*)',
|
||||
capture: ['numberOfDays', 'monitorApiKey'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Uptime Robot ratio (30 days)',
|
||||
previewUrl: 'm778918918-3e92c097147760ee39d02d36',
|
||||
},
|
||||
{
|
||||
title: 'Uptime Robot ratio (7 days)',
|
||||
previewUrl: '7/m778918918-3e92c097147760ee39d02d36',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
static async render({ ratio }) {
|
||||
return {
|
||||
message: `${ratio}%`,
|
||||
color: ratioColor(ratio),
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ numberOfDays = 30, monitorApiKey }) {
|
||||
const { monitors } = await this.fetch({ monitorApiKey, numberOfDays })
|
||||
const ratio = Number.parseFloat(monitors[0].custom_uptime_ratio)
|
||||
return this.constructor.render({ ratio })
|
||||
}
|
||||
}
|
||||
51
services/uptimerobot/uptimerobot-status.service.js
Normal file
51
services/uptimerobot/uptimerobot-status.service.js
Normal file
@@ -0,0 +1,51 @@
|
||||
'use strict'
|
||||
|
||||
const UptimeRobotBase = require('./uptimerobot-base')
|
||||
|
||||
module.exports = class UptimeRobotStatus extends UptimeRobotBase {
|
||||
static get defaultBadgeData() {
|
||||
return {
|
||||
label: 'status',
|
||||
}
|
||||
}
|
||||
|
||||
static get url() {
|
||||
return {
|
||||
base: 'uptimerobot/status',
|
||||
format: '(.*)',
|
||||
capture: ['monitorApiKey'],
|
||||
}
|
||||
}
|
||||
|
||||
static get examples() {
|
||||
return [
|
||||
{
|
||||
title: 'Uptime Robot status',
|
||||
previewUrl: 'm778918918-3e92c097147760ee39d02d36',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
static async render({ status }) {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return { message: 'paused', color: 'yellow' }
|
||||
case 1:
|
||||
return { message: 'not checked yet', color: 'yellowgreen' }
|
||||
case 2:
|
||||
return { message: 'up', color: 'brightgreen' }
|
||||
case 8:
|
||||
return { message: 'seems down', color: 'orange' }
|
||||
case 9:
|
||||
return { message: 'down', color: 'red' }
|
||||
default:
|
||||
throw Error('Should not get here due to validation')
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ monitorApiKey }) {
|
||||
const { monitors } = await this.fetch({ monitorApiKey })
|
||||
const { status } = monitors[0]
|
||||
return this.constructor.render({ status })
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,12 @@
|
||||
const Joi = require('joi')
|
||||
const ServiceTester = require('../service-tester')
|
||||
|
||||
const isUptimeStatus = Joi.string().regex(
|
||||
/^(paused|not checked yet|up|seems down|down)$/
|
||||
const isUptimeStatus = Joi.string().valid(
|
||||
'paused',
|
||||
'not checked yet',
|
||||
'up',
|
||||
'seems down',
|
||||
'down'
|
||||
)
|
||||
const { isPercentage } = require('../test-validators')
|
||||
const { invalidJSON } = require('../response-fixtures')
|
||||
@@ -27,7 +31,7 @@ t.create('Uptime Robot: Status (invalid, correct format)')
|
||||
|
||||
t.create('Uptime Robot: Status (invalid, incorrect format)')
|
||||
.get('/status/not-a-service.json')
|
||||
.expectJSON({ name: 'status', value: 'must use a monitor key' })
|
||||
.expectJSON({ name: 'status', value: 'must use a monitor-specific api key' })
|
||||
|
||||
t.create('Uptime Robot: Status (unspecified error)')
|
||||
.get('/status/m778918918-3e92c097147760ee39d02d36.json')
|
||||
@@ -36,7 +40,7 @@ t.create('Uptime Robot: Status (unspecified error)')
|
||||
.post('/v2/getMonitors')
|
||||
.reply(200, '{"stat": "fail"}')
|
||||
)
|
||||
.expectJSON({ name: 'status', value: 'vendor error' })
|
||||
.expectJSON({ name: 'status', value: 'service error' })
|
||||
|
||||
t.create('Uptime Robot: Status (connection error)')
|
||||
.get('/status/m778918918-3e92c097147760ee39d02d36.json')
|
||||
@@ -59,7 +63,7 @@ t.create('Uptime Robot: Status (unexpected response, valid json)')
|
||||
.post('/v2/getMonitors')
|
||||
.reply(200, '[]')
|
||||
)
|
||||
.expectJSON({ name: 'status', value: 'invalid' })
|
||||
.expectJSON({ name: 'status', value: 'invalid json response' })
|
||||
|
||||
t.create('Uptime Robot: Status (unexpected response, invalid json)')
|
||||
.get('/status/m778918918-3e92c097147760ee39d02d36.json')
|
||||
@@ -68,7 +72,7 @@ t.create('Uptime Robot: Status (unexpected response, invalid json)')
|
||||
.post('/v2/getMonitors')
|
||||
.reply(invalidJSON)
|
||||
)
|
||||
.expectJSON({ name: 'status', value: 'inaccessible' })
|
||||
.expectJSON({ name: 'status', value: 'unparseable json response' })
|
||||
|
||||
t.create('Uptime Robot: Percentage (valid)')
|
||||
.get('/ratio/m778918918-3e92c097147760ee39d02d36.json')
|
||||
@@ -94,7 +98,7 @@ t.create('Uptime Robot: Percentage (invalid, correct format)')
|
||||
|
||||
t.create('Uptime Robot: Percentage (invalid, incorrect format)')
|
||||
.get('/ratio/not-a-service.json')
|
||||
.expectJSON({ name: 'uptime', value: 'must use a monitor key' })
|
||||
.expectJSON({ name: 'uptime', value: 'must use a monitor-specific api key' })
|
||||
|
||||
t.create('Uptime Robot: Percentage (unspecified error)')
|
||||
.get('/ratio/m778918918-3e92c097147760ee39d02d36.json')
|
||||
@@ -103,7 +107,7 @@ t.create('Uptime Robot: Percentage (unspecified error)')
|
||||
.post('/v2/getMonitors')
|
||||
.reply(200, '{"stat": "fail"}')
|
||||
)
|
||||
.expectJSON({ name: 'uptime', value: 'vendor error' })
|
||||
.expectJSON({ name: 'uptime', value: 'service error' })
|
||||
|
||||
t.create('Uptime Robot: Percentage (connection error)')
|
||||
.get('/ratio/m778918918-3e92c097147760ee39d02d36.json')
|
||||
@@ -126,7 +130,7 @@ t.create('Uptime Robot: Percentage (unexpected response, valid json)')
|
||||
.post('/v2/getMonitors')
|
||||
.reply(200, '[]')
|
||||
)
|
||||
.expectJSON({ name: 'uptime', value: 'invalid' })
|
||||
.expectJSON({ name: 'uptime', value: 'invalid json response' })
|
||||
|
||||
t.create('Uptime Robot: Percentage (unexpected response, invalid json)')
|
||||
.get('/ratio/m778918918-3e92c097147760ee39d02d36.json')
|
||||
@@ -135,4 +139,4 @@ t.create('Uptime Robot: Percentage (unexpected response, invalid json)')
|
||||
.post('/v2/getMonitors')
|
||||
.reply(invalidJSON)
|
||||
)
|
||||
.expectJSON({ name: 'uptime', value: 'inaccessible' })
|
||||
.expectJSON({ name: 'uptime', value: 'unparseable json response' })
|
||||
|
||||
Reference in New Issue
Block a user