mirror of
https://github.com/ThisIsBenny/iOS-Widgets.git
synced 2025-04-19 15:27:40 +00:00
184 lines
5.2 KiB
JavaScript
184 lines
5.2 KiB
JavaScript
// Variables used by Scriptable.
|
|
// These must be at the very top of the file. Do not edit.
|
|
// icon-color: deep-brown; icon-glyph: power-off;
|
|
// Version 1.0.0
|
|
|
|
//////////////////////////////////////////////////////
|
|
let fm
|
|
try {
|
|
fm = FileManager.iCloud()
|
|
fm.documentsDirectory()
|
|
} catch (e) {
|
|
console.log(e)
|
|
fm = FileManager.local()
|
|
}
|
|
|
|
const settingsPath = fm.joinPath(fm.documentsDirectory(), 'health-check-settings.json')
|
|
if (!fm.fileExists(settingsPath)) {
|
|
const examplePath = fm.joinPath(fm.documentsDirectory(), 'health-check-settings.example.json')
|
|
fm.writeString(examplePath, JSON.stringify([{
|
|
name: 'Server 1',
|
|
endpoint: 'https://example.com/api/health',
|
|
expectedContentType: 'application/json',
|
|
timeoutInterval: 1,
|
|
notification: true,
|
|
headers: [{key: 'x-customer-header-key',value: 'x-customer-header-value'}]
|
|
}], null, 2))
|
|
|
|
throw new Error('No health-check-settings.json found! Please rename health-check-settings.example.json to health-check-settings.json and add your settings.')
|
|
} else {
|
|
try {
|
|
fm.downloadFileFromiCloud(settingsPath)
|
|
} catch(e) {
|
|
console.error(e)
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////////
|
|
const chooseRandom = (arr, num = 1) => {
|
|
const res = [];
|
|
for(let i = 0; i < num; ){
|
|
const random = Math.floor(Math.random() * arr.length);
|
|
if(res.indexOf(arr[random]) !== -1){
|
|
continue;
|
|
};
|
|
res.push(arr[random]);
|
|
i++;
|
|
};
|
|
return res;
|
|
};
|
|
//////////////////////////////////////////////////////
|
|
const check = async ({ endpoint, headers, timeoutInterval }) => {
|
|
const req = new Request(endpoint)
|
|
req.timeoutInterval = timeoutInterval || 5
|
|
if (headers) {
|
|
let i
|
|
const h = {}
|
|
for (i = 0; i < headers.length; i++) {
|
|
h[headers[i].key] = headers[i].value
|
|
}
|
|
req.headers = h
|
|
}
|
|
|
|
let body, httpStatus, contentType
|
|
try {
|
|
const res = await req.loadString()
|
|
if (req.response.headers['Content-Type'] === 'application/json') {
|
|
body = JSON.parse(res)
|
|
}
|
|
httpStatus = req.response.statusCode
|
|
contentType = req.response.headers['Content-Type']
|
|
} catch (e) {
|
|
httpStatus = 504
|
|
}
|
|
return {
|
|
httpStatus,
|
|
contentType,
|
|
body
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////////
|
|
const settings = JSON.parse(fm.readString(settingsPath))
|
|
|
|
let i
|
|
for (i = 0; i < settings.length; i++) {
|
|
const { httpStatus, contentType } = await check(settings[i])
|
|
if (settings[i].history === undefined) {
|
|
settings[i].history = []
|
|
}
|
|
|
|
let status = 'healthy'
|
|
if (!/^2/.test(httpStatus)) {
|
|
status = 'unhealthy'
|
|
}
|
|
if (settings[i].contentType && settings[i].expectedContentType !== contentType) {
|
|
status = 'unhealthy'
|
|
}
|
|
settings[i].history.push({
|
|
date: new Date().toISOString(),
|
|
status
|
|
})
|
|
settings[i].history = settings[i].history.splice(-40)
|
|
if (settings[i].notification && /^2/.test(httpStatus) === false) {
|
|
const n = new Notification()
|
|
n.body = `🚨 Service '${settings[i].name}' is ${(httpStatus === 504) ? 'slow' : 'unhealthy'}`
|
|
n.schedule()
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////////
|
|
fm.writeString(settingsPath, JSON.stringify(settings, null, 2))
|
|
//////////////////////////////////////////////////////
|
|
|
|
const widget = new ListWidget()
|
|
|
|
const titleStack = widget.addStack()
|
|
titleStack.layoutHorizontally()
|
|
|
|
const widgetTitle = titleStack.addText('Health Check')
|
|
|
|
titleStack.addSpacer()
|
|
|
|
const globalStatus = settings.filter((e) => {
|
|
return e.history[e.history.length - 1].status === 'healthy'
|
|
})
|
|
|
|
const widgetGlobalStatus = titleStack.addText(`${globalStatus.length}/${settings.length} healthy`)
|
|
widgetGlobalStatus.font = Font.regularSystemFont(10)
|
|
|
|
widget.addSpacer(5)
|
|
|
|
const stack = widget.addStack()
|
|
stack.layoutHorizontally()
|
|
|
|
const leftColumn = stack.addStack()
|
|
leftColumn.layoutVertically()
|
|
leftColumn.spacing = 5
|
|
|
|
let rightColumn
|
|
if (config.widgetFamily !== 'small' ) {
|
|
stack.addSpacer(20)
|
|
rightColumn = stack.addStack()
|
|
rightColumn.layoutVertically()
|
|
rightColumn.spacing = 5
|
|
}
|
|
|
|
const maxView = (config.widgetFamily !== 'large') ? 4 : 8
|
|
let toShow
|
|
|
|
if (settings.length > maxView) {
|
|
toShow = chooseRandom(settings, maxView)
|
|
} else {
|
|
toShow = settings
|
|
}
|
|
|
|
for (i = 0; i < toShow.length; i++) {
|
|
const lastCheck = toShow[i].history[toShow[i].history.length - 1]
|
|
const labelText = leftColumn.addText(`${lastCheck.status === 'healthy' ? '🟢' : '⚠️'} ${toShow[i].name}`)
|
|
labelText.font = Font.regularSystemFont(12)
|
|
labelText.lineLimit = 1
|
|
|
|
|
|
if (config.widgetFamily !== 'small' ) {
|
|
let j
|
|
const field = rightColumn.addStack()
|
|
field.layoutHorizontally()
|
|
for (j = 0; j < toShow[i].history.length; j++) {
|
|
const status = field.addText('|')
|
|
status.font = Font.regularSystemFont(12)
|
|
status.textColor = (toShow[i].history[j].status === 'healthy') ? Color.green() : Color.red()
|
|
}
|
|
}
|
|
}
|
|
widget.addSpacer()
|
|
|
|
const widgetUpdate = widget.addText(`Last Check: ${new Date().toLocaleString()}`)
|
|
widgetUpdate.font = Font.regularSystemFont(8)
|
|
widgetUpdate.textColor = Color.lightGray()
|
|
widgetUpdate.centerAlignText()
|
|
|
|
if (!config.runsInWidget) {
|
|
await widget.presentLarge()
|
|
} else {
|
|
// Tell the system to show the widget.
|
|
Script.setWidget(widget)
|
|
Script.complete()
|
|
}
|