diff --git a/components/Header.tsx b/components/Header.tsx
index a1c3d51..2b1be33 100644
--- a/components/Header.tsx
+++ b/components/Header.tsx
@@ -1,6 +1,6 @@
import { Container, Group, Text } from '@mantine/core'
import classes from '@/styles/Header.module.css'
-import config from '@/uptime.config'
+import { pageConfig } from '@/uptime.config'
export default function Header() {
const linkToElement = (link: { label: string; link: string; highlight?: boolean }) => {
@@ -38,11 +38,11 @@ export default function Header() {
- {config.page.links.map(linkToElement)}
+ {pageConfig.links.map(linkToElement)}
- {config.page.links.filter((link) => (link as any).highlight).map(linkToElement)}
+ {pageConfig.links.filter((link) => (link as any).highlight).map(linkToElement)}
diff --git a/components/MonitorList.tsx b/components/MonitorList.tsx
index 9070886..fec88f9 100644
--- a/components/MonitorList.tsx
+++ b/components/MonitorList.tsx
@@ -2,7 +2,7 @@ import { MonitorState, MonitorTarget } from '@/uptime.types'
import { Card, Center, Divider } from '@mantine/core'
import MonitorDetail from './MonitorDetail'
-export default function MonitorList({ config, state }: { config: any; state: MonitorState }) {
+export default function MonitorList({ monitors, state }: { monitors: any; state: MonitorState }) {
return (
- {config.monitors.map((monitor: MonitorTarget) => (
+ {monitors.map((monitor: MonitorTarget) => (
diff --git a/pages/index.tsx b/pages/index.tsx
index b2be9b0..587e290 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,9 +1,9 @@
import Head from 'next/head'
import { Inter } from 'next/font/google'
-import { MonitorState } from '@/uptime.types'
+import { MonitorState, MonitorTarget } from '@/uptime.types'
import { KVNamespace } from '@cloudflare/workers-types'
-import config from '@/uptime.config'
+import { pageConfig, workerConfig } from '@/uptime.config'
import OverallStatus from '@/components/OverallStatus'
import Header from '@/components/Header'
import MonitorList from '@/components/MonitorList'
@@ -12,11 +12,17 @@ import { Center, Divider, Text } from '@mantine/core'
export const runtime = 'experimental-edge'
const inter = Inter({ subsets: ['latin'] })
-export default function Home({ state }: { state: MonitorState }) {
+export default function Home({
+ state,
+ monitors,
+}: {
+ state: MonitorState
+ monitors: MonitorTarget[]
+}) {
return (
<>
- {config.page.title}
+ {pageConfig.title}
@@ -33,7 +39,7 @@ export default function Home({ state }: { state: MonitorState }) {
) : (
-
+
)}
@@ -66,5 +72,14 @@ export async function getServerSideProps() {
}
const state = (await UPTIMEFLARE_STATE?.get('state', 'json')) as unknown as MonitorState
- return { props: { state } }
+ // Only present these values to client
+ const monitors = workerConfig.monitors.map((monitor) => {
+ return {
+ id: monitor.id,
+ name: monitor.name,
+ tooltip: monitor.tooltip,
+ }
+ })
+
+ return { props: { state, monitors } }
}
diff --git a/uptime.config.ts b/uptime.config.ts
index 8b90e6c..8d770cd 100644
--- a/uptime.config.ts
+++ b/uptime.config.ts
@@ -1,26 +1,15 @@
-const config = {
- // Your locale for server-side callback. (client-side will always follow browser settings)
- dateLocale: 'zh-CN',
- // Your timezone for server-side callback. (client-side will always follow browser settings)
- timezone: 'Asia/Shanghai',
- page: {
- // Title for your status page
- title: "lyc8503's Status Page",
- // Links shown at the header of your status page, could set `highlight` to `true`
- links: [
- { link: 'https://github.com/lyc8503', label: 'GitHub' },
- { link: 'https://blog.lyc8503.site/', label: 'Blog' },
- { link: 'mailto:me@lyc8503.site', label: 'Email Me', highlight: true },
- ],
- },
- callback: async (statusChangeMsg: string) => {
- // Write any typescript here
- // Example `statusChangeMsg` string:
- // "❌My Blog went down at 2023/11/18 14:08:59 with error Timeout after 10000ms"
- // "✔️My Blog came back up at 2023/11/18 14:10:48 after 2 minutes of downtime"
- // Example:
- // await fetch('https://api.example.com/callback?msg=' + statusChangeMsg)
- },
+const pageConfig = {
+ // Title for your status page
+ title: "lyc8503's Status Page",
+ // Links shown at the header of your status page, could set `highlight` to `true`
+ links: [
+ { link: 'https://github.com/lyc8503', label: 'GitHub' },
+ { link: 'https://blog.lyc8503.site/', label: 'Blog' },
+ { link: 'mailto:me@lyc8503.site', label: 'Email Me', highlight: true },
+ ],
+}
+
+const workerConfig = {
// Define all your monitors here
monitors: [
// Example HTTP Monitor
@@ -50,7 +39,7 @@ const config = {
responseKeyword: 'success',
// [OPTIONAL] if specified, the check will run in your specified region,
// refer to docs https://github.com/lyc8503/UptimeFlare/wiki/Geo-specific-checks-setup before setting this value
- checkLocationWorkerRoute: 'https://xxx.example.com'
+ checkLocationWorkerRoute: 'https://xxx.example.com',
},
// Example TCP Monitor
{
@@ -64,7 +53,43 @@ const config = {
timeout: 5000,
},
],
+ callbacks: {
+ onStatusChange: async (
+ id: string,
+ name: string,
+ isUp: boolean,
+ timeIncidentStart: number,
+ timeNow: number,
+ reason: string
+ ) => {
+ // This callback will be called when any monitor's status changed
+ // Write any Typescript code here
+ // Example implementation:
+ // const timeString = new Date(timeNow * 1000).toLocaleString('zh-CN', {
+ // timeZone: 'Asia/Shanghai',
+ // })
+ // let statusChangeMsg
+ // if (isUp) {
+ // statusChangeMsg = `✔️${name} came back up at ${timeString} after ${Math.round(
+ // (timeNow - timeIncidentStart) / 60
+ // )} minutes of downtime`
+ // } else {
+ // statusChangeMsg = `❌${name} was down at ${timeString} with error ${reason}`
+ // }
+ // await fetch('https://api.example.com/callback?msg=' + statusChangeMsg)
+ },
+ onIncident: async (
+ id: string,
+ name: string,
+ timeIncidentStart: number,
+ timeNow: number,
+ currentError: string
+ ) => {
+ // This callback will be called EVERY 2 MINTUES if there's an on-going incident for any monitor
+ // Write any Typescript code here
+ },
+ },
}
// Don't forget this, otherwise compilation fails.
-export default config
+export { pageConfig, workerConfig }
diff --git a/worker/src/index.ts b/worker/src/index.ts
index e8f38ea..48fdc8d 100644
--- a/worker/src/index.ts
+++ b/worker/src/index.ts
@@ -1,4 +1,4 @@
-import config from '../../uptime.config'
+import { workerConfig } from '../../uptime.config'
import { getWorkerLocation } from './util'
import { MonitorState } from '../../uptime.types'
import { getStatus } from './monitor'
@@ -17,7 +17,7 @@ export default {
}
const targetId = (await request.json<{ target: string }>())['target']
- const target = config.monitors.find((m) => m.id === targetId)
+ const target = workerConfig.monitors.find((m) => m.id === targetId)
if (target === undefined) {
return new Response('Target Not Found', { status: 404 })
@@ -59,9 +59,8 @@ export default {
state.overallUp = 0
// Check each monitor
- // TODO: callback exception handler
// TODO: concurrent status check
- for (const monitor of config.monitors) {
+ for (const monitor of workerConfig.monitors) {
console.log(`[${workerLocation}] Checking ${monitor.name}...`)
let checkLocation = workerLocation
@@ -97,7 +96,6 @@ export default {
status.up ? state.overallUp++ : state.overallDown++
// Update incidents
-
// Create a dummy incident to store the start time of the monitoring and simplify logic
state.incident[monitor.id] = state.incident[monitor.id] || [
{
@@ -108,20 +106,26 @@ export default {
]
// Then lastIncident here must not be undefined
const lastIncident = state.incident[monitor.id].slice(-1)[0]
- const timeString = new Date().toLocaleString(config.dateLocale, {
- timeZone: config.timezone,
- })
if (status.up) {
// Current status is up
// close existing incident if any
if (lastIncident.end === undefined) {
lastIncident.end = currentTimeSecond
- await config.callback(
- `✔️${monitor.name} came back up at ${timeString} after ${Math.round(
- (lastIncident.end - lastIncident.start[0]) / 60
- )} minutes of downtime`
- )
+
+ try {
+ await workerConfig.callbacks.onStatusChange(
+ monitor.id,
+ monitor.name,
+ true,
+ lastIncident.start[0],
+ currentTimeSecond,
+ 'OK'
+ )
+ } catch (e) {
+ console.log('Error calling callback: ')
+ console.log(e)
+ }
}
} else {
// Current status is down
@@ -132,9 +136,20 @@ export default {
end: undefined,
error: [status.err],
})
- await config.callback(
- `❌${monitor.name} went down at ${timeString} with error ${status.err}`
- )
+
+ try {
+ await workerConfig.callbacks.onStatusChange(
+ monitor.id,
+ monitor.name,
+ false,
+ currentTimeSecond,
+ currentTimeSecond,
+ status.err
+ )
+ } catch (e) {
+ console.log('Error calling callback: ')
+ console.log(e)
+ }
} else if (
lastIncident.end === undefined &&
lastIncident.error.slice(-1)[0] !== status.err
@@ -142,9 +157,33 @@ export default {
// append if the error message changes
lastIncident.start.push(currentTimeSecond)
lastIncident.error.push(status.err)
- await config.callback(
- `❌${monitor.name} is still down at ${timeString} with error ${status.err}`
+
+ try {
+ await workerConfig.callbacks.onStatusChange(
+ monitor.id,
+ monitor.name,
+ false,
+ lastIncident.start[0],
+ currentTimeSecond,
+ status.err
+ )
+ } catch (e) {
+ console.log('Error calling callback: ')
+ console.log(e)
+ }
+ }
+
+ try {
+ await workerConfig.callbacks.onIncident(
+ monitor.id,
+ monitor.name,
+ lastIncident.start[0],
+ currentTimeSecond,
+ status.err
)
+ } catch (e) {
+ console.log('Error calling callback: ')
+ console.log(e)
}
}