WIP: http
parent
1d12cf0b3e
commit
820d460512
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from 'chart.js'
|
||||
import 'chartjs-adapter-moment'
|
||||
import { MonitorState, MonitorTarget } from '@/types/config'
|
||||
import { iataToCountry } from '@/util/iata'
|
||||
import { codeToCountry } from '@/util/iata'
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
|
|
@ -66,7 +66,7 @@ export default function DetailChart({
|
|||
callbacks: {
|
||||
label: (item: any) => {
|
||||
if (item.parsed.y) {
|
||||
return `${item.parsed.y}ms (${iataToCountry(item.raw.loc)})`
|
||||
return `${item.parsed.y}ms (${codeToCountry(item.raw.loc)})`
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
10
util/iata.ts
10
util/iata.ts
File diff suppressed because one or more lines are too long
|
|
@ -1,6 +1,142 @@
|
|||
import { MonitorTarget } from '../../types/config'
|
||||
import { withTimeout, fetchTimeout } from './util'
|
||||
|
||||
|
||||
async function httpResponseBasicCheck(monitor: MonitorTarget, code: number, bodyReader: () => Promise<string>): Promise<string | null> {
|
||||
if (monitor.expectedCodes) {
|
||||
if (!monitor.expectedCodes.includes(code)) {
|
||||
console.log(`${monitor.name} expected ${monitor.expectedCodes}, got ${code}`)
|
||||
return `Expected codes: ${JSON.stringify(monitor.expectedCodes)}, Got: ${code}`
|
||||
}
|
||||
} else {
|
||||
if (code < 200 || code > 299) {
|
||||
console.log(`${monitor.name} expected 2xx, got ${code}`)
|
||||
return `Expected codes: 2xx, Got: ${code}`
|
||||
}
|
||||
}
|
||||
|
||||
if (monitor.responseKeyword || monitor.responseForbiddenKeyword) {
|
||||
// Only read response body if we have a keyword to check
|
||||
const responseBody = await bodyReader()
|
||||
|
||||
// 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)}`
|
||||
)
|
||||
return "HTTP response doesn't contain the configured keyword"
|
||||
}
|
||||
|
||||
// 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)}`
|
||||
)
|
||||
return 'HTTP response contains the configured forbidden keyword'
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
export async function getStatusWithGlobalPing(monitor: MonitorTarget): Promise<{ location: string; status: { ping: number; up: boolean; err: string } }> {
|
||||
if (monitor.checkProxy === undefined) {
|
||||
throw 'empty check proxy for globalping, shouldn\'t call this method'
|
||||
}
|
||||
|
||||
const gpUrl = new URL(monitor.checkProxy)
|
||||
if (gpUrl.protocol !== 'globalping:') {
|
||||
throw 'incorrect check proxy protocol for globalping, got: ' + gpUrl.protocol
|
||||
}
|
||||
|
||||
const token = gpUrl.hostname
|
||||
let globalPingRequest = {}
|
||||
|
||||
if (monitor.method === 'TCP_PING') {
|
||||
|
||||
} else {
|
||||
const targetUrl = new URL(monitor.target)
|
||||
globalPingRequest = {
|
||||
type: 'http',
|
||||
target: targetUrl.hostname,
|
||||
measurementOptions: {
|
||||
request: {
|
||||
method: monitor.method,
|
||||
path: targetUrl.pathname,
|
||||
query: targetUrl.search,
|
||||
headers: monitor.headers
|
||||
},
|
||||
port: targetUrl.port
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const startTime = Date.now()
|
||||
console.log(`Requesting the Global Ping API, payload: ${globalPingRequest}`)
|
||||
const measurement = await fetchTimeout('https://api.globalping.io/v1/measurements', 5000, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token
|
||||
},
|
||||
body: JSON.stringify(globalPingRequest)
|
||||
})
|
||||
const measurementResponse = (await measurement.json() as any)
|
||||
|
||||
if (measurement.status !== 202) {
|
||||
throw measurementResponse.error.message
|
||||
}
|
||||
|
||||
const measurementId = measurementResponse.id
|
||||
console.log(`Measurement created successfully, id: ${measurementId}, time elapsed: ${Date.now() - startTime}ms`)
|
||||
|
||||
const pollStart = Date.now()
|
||||
let measurementResult: any
|
||||
while (true) {
|
||||
if (Date.now() - pollStart > (monitor.timeout ?? 10000) + 2000) {
|
||||
throw 'api polling timeout'
|
||||
}
|
||||
|
||||
measurementResult = await(await fetchTimeout(`https://api.globalping.io/v1/measurements/${measurementId}`, 5000)).json() as any
|
||||
if (measurementResult.status !== 'in-progress') {
|
||||
break
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
|
||||
console.log(`Measurement ${measurementId} finished with response: ${measurementResult}`)
|
||||
|
||||
const time = measurementResult.results[0].result.timings.total
|
||||
const code = measurementResult.results[0].result.statusCode
|
||||
const body = measurementResult.results[0].result.rawBody
|
||||
|
||||
const country = measurementResult.results[0].probe.country
|
||||
|
||||
const err = await httpResponseBasicCheck(monitor, code, () => body)
|
||||
if (err !== null) {
|
||||
console.log(`${monitor.name} didn't pass response check: ${err}`)
|
||||
}
|
||||
// TODO: missing headers
|
||||
return {
|
||||
location: country,
|
||||
status: { // TODO TLS err
|
||||
ping: time,
|
||||
up: err === null,
|
||||
err: err ?? ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function getStatus(
|
||||
monitor: MonitorTarget
|
||||
): Promise<{ ping: number; up: boolean; err: string }> {
|
||||
|
|
@ -56,58 +192,12 @@ export async function getStatus(
|
|||
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
|
||||
}
|
||||
const err = await httpResponseBasicCheck(monitor, response.status, response.text)
|
||||
if (err !== null) {
|
||||
console.log(`${monitor.name} didn't pass response check: ${err}`)
|
||||
}
|
||||
|
||||
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 = ''
|
||||
status.up = err === null
|
||||
status.err = err ?? ''
|
||||
} catch (e: any) {
|
||||
console.log(`${monitor.name} errored with ${e.name}: ${e.message}`)
|
||||
if (e.name === 'AbortError') {
|
||||
|
|
|
|||
Loading…
Reference in New Issue