WIP: check proxy looks good, still testing
parent
f974ad4428
commit
55900836d4
|
|
@ -1,11 +1,156 @@
|
||||||
// This is a Node.js implementation of status monitoring
|
// This is a Node.js implementation of status monitoring
|
||||||
|
|
||||||
|
const location = ''
|
||||||
|
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
|
const net = require('net')
|
||||||
const app = express()
|
const app = express()
|
||||||
const port = 3000
|
const port = 3000
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
async function getWorkerLocation() {
|
||||||
res.send('Hello World!')
|
const res = await fetch('https://cloudflare.com/cdn-cgi/trace')
|
||||||
|
const text = await res.text()
|
||||||
|
|
||||||
|
const colo = /^colo=(.*)$/m.exec(text)?.[1]
|
||||||
|
return colo
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchTimeout = (url, ms, options = {}) => {
|
||||||
|
const controller = new AbortController()
|
||||||
|
const promise = fetch(url, { signal: controller.signal, ...options })
|
||||||
|
const timeout = setTimeout(() => controller.abort(), ms)
|
||||||
|
return promise.finally(() => clearTimeout(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
function withTimeout(millis, promise) {
|
||||||
|
const timeout = new Promise((resolve, reject) =>
|
||||||
|
setTimeout(() => reject(new Error(`Promise timed out after ${millis}ms`)), millis)
|
||||||
|
)
|
||||||
|
|
||||||
|
return Promise.race([promise, timeout])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: More code reuse here
|
||||||
|
async function getStatus(monitor) {
|
||||||
|
let status = {
|
||||||
|
ping: 0,
|
||||||
|
up: false,
|
||||||
|
err: 'Unknown',
|
||||||
|
}
|
||||||
|
|
||||||
|
const startTime = Date.now()
|
||||||
|
|
||||||
|
if (monitor.method === 'TCP_PING') {
|
||||||
|
// TCP port endpoint monitor
|
||||||
|
try {
|
||||||
|
// This is not a real https connection, but we need to add a dummy `https://` to parse the hostname & port
|
||||||
|
const parsed = new URL("https://" + monitor.target)
|
||||||
|
|
||||||
|
const client = await net.createConnection(
|
||||||
|
{ host: parsed.hostname, port: Number(parsed.port) },
|
||||||
|
() => {
|
||||||
|
console.log(`${monitor.name} connected to ${monitor.target}`)
|
||||||
|
status.ping = Date.now() - startTime
|
||||||
|
status.up = true
|
||||||
|
status.err = ''
|
||||||
|
client.end()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// const socket = connect({ hostname: parsed.hostname, port: Number(parsed.port) })
|
||||||
|
|
||||||
|
// // Now we have an `opened` promise!
|
||||||
|
// // @ts-ignore
|
||||||
|
// await withTimeout(monitor.timeout || 10000, socket.opened)
|
||||||
|
// await socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`${monitor.name} errored with ${e.name}: ${e.message}`)
|
||||||
|
if (e.message.includes('timed out')) {
|
||||||
|
status.ping = monitor.timeout || 10000
|
||||||
|
}
|
||||||
|
status.up = false
|
||||||
|
status.err = e.name + ': ' + e.message
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// HTTP endpoint monitor
|
||||||
|
try {
|
||||||
|
const response = await fetchTimeout(monitor.target, monitor.timeout || 10000, {
|
||||||
|
method: monitor.method,
|
||||||
|
headers: monitor.headers,
|
||||||
|
body: monitor.body,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(`${monitor.name} responded with ${response.status}`)
|
||||||
|
status.ping = Date.now() - startTime
|
||||||
|
|
||||||
|
if (monitor.expectedCodes) {
|
||||||
|
if (!monitor.expectedCodes.includes(response.status)) {
|
||||||
|
console.log(`${monitor.name} expected ${monitor.expectedCodes}, got ${response.status}`)
|
||||||
|
status.up = false
|
||||||
|
status.err = `Expected codes: ${JSON.stringify(monitor.expectedCodes)}, Got: ${response.status
|
||||||
|
}`
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (response.status < 200 || response.status > 299) {
|
||||||
|
console.log(`${monitor.name} expected 2xx, got ${response.status}`)
|
||||||
|
status.up = false
|
||||||
|
status.err = `Expected codes: 2xx, Got: ${response.status}`
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor.responseKeyword || monitor.responseForbiddenKeyword) {
|
||||||
|
// Only read response body if we have a keyword to check
|
||||||
|
const responseBody = await response.text()
|
||||||
|
|
||||||
|
// MUST contain responseKeyword
|
||||||
|
if (monitor.responseKeyword && !responseBody.includes(monitor.responseKeyword)) {
|
||||||
|
console.log(`${monitor.name} expected keyword ${monitor.responseKeyword}, not found in response (truncated to 100 chars): ${responseBody.slice(0, 100)}`)
|
||||||
|
status.up = false
|
||||||
|
status.err = "HTTP response doesn't contain the configured keyword"
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
// MUST NOT contain responseForbiddenKeyword
|
||||||
|
if (monitor.responseForbiddenKeyword && responseBody.includes(monitor.responseForbiddenKeyword)) {
|
||||||
|
console.log(`${monitor.name} forbidden keyword ${monitor.responseForbiddenKeyword}, found in response (truncated to 100 chars): ${responseBody.slice(0, 100)}`)
|
||||||
|
status.up = false
|
||||||
|
status.err = "HTTP response contains the configured forbidden keyword"
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status.up = true
|
||||||
|
status.err = ''
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`${monitor.name} errored with ${e.name}: ${e.message}`)
|
||||||
|
if (e.name === 'AbortError') {
|
||||||
|
status.ping = monitor.timeout || 10000
|
||||||
|
status.up = false
|
||||||
|
status.err = `Timeout after ${status.ping}ms`
|
||||||
|
} else {
|
||||||
|
status.up = false
|
||||||
|
status.err = e.name + ': ' + e.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
app.post('/', (req, res) => {
|
||||||
|
res.json(
|
||||||
|
{
|
||||||
|
location: getWorkerLocation(),
|
||||||
|
status: getStatus(req.body),
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue