badgen.net/libs/badgen-serve.ts

142 wiersze
3.9 KiB
TypeScript
Czysty Zwykły widok Historia

2019-05-13 12:00:56 +00:00
import url from 'url'
import matchRoute from 'my-way'
2019-05-13 12:00:56 +00:00
2019-05-14 02:19:56 +00:00
import serve404 from './serve-404'
import serveBadge from './serve-badge'
2019-06-03 11:12:23 +00:00
import sentry from './sentry'
2019-05-13 12:00:56 +00:00
2019-05-14 01:36:25 +00:00
import { BadgenParams } from './types'
2019-05-13 12:00:56 +00:00
2019-05-26 04:38:30 +00:00
export type BadgenServeMeta = {
2019-05-26 05:09:19 +00:00
title: string
2019-05-26 04:38:30 +00:00
examples: { [url: string]: string }
2019-05-26 05:09:19 +00:00
help?: string
2019-05-26 04:38:30 +00:00
}
2019-05-13 12:00:56 +00:00
export type BadgenServeHandlerArgs = { [key: string]: string }
2019-05-31 02:07:18 +00:00
export type BadgenServeHandlerResult = Promise<BadgenParams | undefined>
export type BadgenServeHandler = (args: BadgenServeHandlerArgs) => BadgenServeHandlerResult
2019-05-13 12:00:56 +00:00
export type BadgenServeHandlers = { [key: string]: BadgenServeHandler }
2019-05-14 01:15:16 +00:00
export function badgenServe (handlers: BadgenServeHandlers): Function {
2019-05-13 12:00:56 +00:00
return async function httpHandler (req, res) {
const { pathname = '/', query } = url.parse(req.url, true)
// serve favicon
if (pathname === '/favicon.ico') {
return res.end()
}
// Lookup handler
let matchedArgs
const matchedScheme = Object.keys(handlers).find(scheme => {
2019-05-15 13:13:07 +00:00
matchedArgs = matchRoute(scheme, decodeURI(pathname))
2019-05-13 12:00:56 +00:00
return matchedArgs !== null
})
2019-05-31 02:07:18 +00:00
const defaultLabel = pathname.split('/')[1]
2019-06-01 01:50:59 +00:00
2019-05-13 12:00:56 +00:00
if (matchedScheme) {
2019-05-14 09:50:57 +00:00
try {
2019-05-31 02:07:18 +00:00
const params = await handlers[matchedScheme](matchedArgs) || {
subject: defaultLabel,
status: 'unknown',
color: 'grey'
}
2019-06-01 01:50:59 +00:00
2019-06-10 15:06:49 +00:00
params.subject = simpleDecode(params.subject)
params.status = simpleDecode(params.status)
2019-06-10 12:10:31 +00:00
2019-06-10 16:13:27 +00:00
if (query.style === undefined) {
if ((req.headers[':authority'] || req.headers.host).startsWith('flat')) {
query.style = 'flat'
}
2019-06-01 01:50:59 +00:00
}
2019-05-14 09:50:57 +00:00
return serveBadge(req, res, { params, query })
} catch (error) {
2019-06-07 13:09:44 +00:00
if (error instanceof BadgenError) {
2019-06-07 13:17:30 +00:00
console.log(`BGE${error.code} "${error.status}" ${req.url}`)
2019-06-07 13:09:44 +00:00
return serveBadge(req, res, {
2019-06-07 13:17:30 +00:00
code: error.code,
2019-06-07 13:09:44 +00:00
sMaxAge: 5,
params: {
subject: defaultLabel,
status: error.status,
color: error.color
}
})
}
2019-06-07 13:17:30 +00:00
// Handle timeout for `got` requests
if (error.code === 'ETIMEDOUT') {
console.error(`E504 ${req.url}`)
2019-06-03 10:44:31 +00:00
// todo: send to google
2019-05-26 07:54:24 +00:00
return serveBadge(req, res, {
2019-06-07 13:17:30 +00:00
code: 504,
2019-06-03 10:44:31 +00:00
sMaxAge: 5,
2019-05-26 07:54:24 +00:00
params: {
2019-05-31 02:07:18 +00:00
subject: defaultLabel,
2019-06-07 13:17:30 +00:00
status: 'timeout',
2019-05-26 07:54:24 +00:00
color: 'grey'
}
})
}
2019-06-07 13:17:30 +00:00
// Handle requests errors from `got`
if (error.statusCode) {
const errorInfo = `${error.url} ${error.statusMessage}`
console.error(`APIE${error.statusCode} ${req.url} ${errorInfo}`)
2019-06-03 10:44:31 +00:00
// todo: send to google
2019-05-31 07:58:51 +00:00
return serveBadge(req, res, {
2019-06-07 13:17:30 +00:00
code: error.statusCode,
2019-06-01 16:21:34 +00:00
sMaxAge: 5,
2019-05-31 07:58:51 +00:00
params: {
subject: defaultLabel,
2019-06-07 13:17:30 +00:00
status: error.statusCode,
2019-06-01 04:43:58 +00:00
color: 'grey'
2019-05-31 07:58:51 +00:00
}
})
}
2019-06-03 11:12:23 +00:00
sentry.configureScope((scope) => {
scope.setTag('path', req.url)
scope.setTag('service', defaultLabel)
})
sentry.captureException(error)
2019-06-10 15:06:49 +00:00
console.error(`E500 ${req.url}`, error.message, error)
2019-05-14 09:50:57 +00:00
return serveBadge(req, res, {
code: 500,
2019-06-01 16:21:34 +00:00
sMaxAge: 5,
2019-05-14 09:50:57 +00:00
params: {
subject: 'badgen',
status: 'error',
2019-06-01 04:43:58 +00:00
color: 'grey'
2019-05-14 09:50:57 +00:00
}
})
}
2019-05-13 12:00:56 +00:00
} else {
return serve404(req, res)
}
}
}
2019-06-07 13:09:44 +00:00
export class BadgenError {
2019-06-07 13:17:30 +00:00
public status: string // error badge param: status (required)
public color: string // error badge param: color
public code: number // status code for response
2019-06-07 13:09:44 +00:00
constructor ({ status, color = 'grey', code = 500 }) {
this.status = status
this.color = color
this.code = code
}
}
2019-06-10 15:06:49 +00:00
function simpleDecode (str: any): string {
return String(str).replace(/%2F/g, '/')
}