From cc1427882f4278eac86d26317c4be1341e4c75fe Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Sat, 30 Mar 2024 02:53:51 -0400 Subject: [PATCH] feat: watch config file for external edits --- app/root.tsx | 3 ++- app/utils/config.ts | 20 +++++++++++++++++--- package.json | 1 + pnpm-lock.yaml | 3 +++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/root.tsx b/app/root.tsx index 9f5a19c..bcc3497 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -10,7 +10,7 @@ import { import { ErrorPopup } from '~/components/Error' import Toaster from '~/components/Toaster' import stylesheet from '~/tailwind.css?url' -import { getContext } from '~/utils/config' +import { getContext, registerConfigWatcher } from '~/utils/config' export const meta: MetaFunction = () => [ { title: 'Headplane' }, @@ -23,6 +23,7 @@ export const links: LinksFunction = () => [ export async function loader() { await getContext() + registerConfigWatcher() if (!process.env.HEADSCALE_URL) { throw new Error('The HEADSCALE_URL environment variable is required') diff --git a/app/utils/config.ts b/app/utils/config.ts index 6948c2f..eb57271 100644 --- a/app/utils/config.ts +++ b/app/utils/config.ts @@ -1,6 +1,7 @@ -import { access, constants, readFile, stat, writeFile } from 'node:fs/promises' +import { access, constants, readFile, writeFile } from 'node:fs/promises' import { resolve } from 'node:path' +import { type FSWatcher, watch } from 'chokidar' import { type Document, parseDocument } from 'yaml' type Duration = `${string}s` | `${string}h` | `${string}m` | `${string}d` | `${string}y` @@ -120,8 +121,8 @@ type Config = { let config: Document -export async function getConfig() { - if (!config) { +export async function getConfig(force = false) { + if (!config || force) { const path = resolve(process.env.CONFIG_FILE ?? '/etc/headscale/config.yaml') const data = await readFile(path, 'utf8') config = parseDocument(data) @@ -140,6 +141,19 @@ export async function patchConfig(partial: Record) { await writeFile(path, config.toString(), 'utf8') } +let watcher: FSWatcher + +export function registerConfigWatcher() { + if (watcher) { + return + } + + const path = resolve(process.env.CONFIG_FILE ?? '/etc/headscale/config.yaml') + watcher = watch(path).on('change', async () => { + await getConfig(true) + }) +} + type Context = { hasDockerSock: boolean; hasConfig: boolean; diff --git a/package.json b/package.json index f2b5eb0..5a881ab 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@remix-run/node": "^2.8.1", "@remix-run/react": "^2.8.1", "@remix-run/serve": "^2.8.1", + "chokidar": "^3.6.0", "clsx": "^2.1.0", "isbot": "^4.1.0", "oauth4webapi": "^2.10.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b744b87..623c5d7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ dependencies: '@remix-run/serve': specifier: ^2.8.1 version: 2.8.1(typescript@5.4.3) + chokidar: + specifier: ^3.6.0 + version: 3.6.0 clsx: specifier: ^2.1.0 version: 2.1.0