refactor(controller): apply controller settings by rebuilding the channel set
Giving each controller a Reload method worked for the notification pipes, which only hold values, but not for the two bot channels: the NapCat client is stopped through a sync.Once and the Telegram polling context is created with the controller, so neither can be re-pointed once running. It also meant five bespoke implementations of the same idea. Replace the whole set instead. Manager.ReplaceAll swaps in a freshly built set under the registry lock, stops the outgoing controllers outside it, and starts the incoming ones off the calling goroutine so a slow handshake does not hold the settings request open. ReplaceAll is now the only way controllers are installed: Register is gone, because a lone registration would slip a controller in without recording the settings it was built from, which is what NeedsRebuild compares against. The rebuild runs from the reload hook and only fires when the controllerMethod section actually changed, so saving a message template or a webhook endpoint leaves the channels alone. NeedsRebuild compares the whole section by value, and a test pins that reloading a file reproduces it exactly — a default applied inconsistently would make every save look like a controller change and tear down every channel. With controllers immutable after construction and replaced wholesale, the atomic pointers and Reload methods have no writers left, so they are gone and the pipes return to plain fields. notifyReload now serializes hook execution for the same reason: a hook mutates process-wide state, and two overlapping settings updates would otherwise each decide to rebuild from their own view of what was applied. Kept from that work: applyEmailProxy restores gomail's default dialer when networkUseProxy is turned off. The old constructor only ever installed the proxy dialer, so switching the flag back left SMTP tunnelled through a proxy with no way to undo it short of a restart. Documents the resulting behaviour in the README under "What applies without a restart".
This commit is contained in:
@@ -294,6 +294,18 @@ Admins and trusted groups are defined **per bot channel** and map a member ID to
|
||||
| `{{ list.offlineServers }}` | Formatted list of offline servers |
|
||||
| `{{ softwareVersion }}`, `{{ softwareBuildVer }}`, `{{ softwareCommitHash }}`, `{{ softwareBuildType }}`, `{{ softwareBuildTime }}`, `{{ softwareDeveloper }}`, `{{ softwareDescription }}` | Build metadata (commit hash and build time are injected at compile time) |
|
||||
|
||||
### What applies without a restart
|
||||
|
||||
Saving settings applies most of them immediately. How each group takes effect:
|
||||
|
||||
| Settings | How it applies |
|
||||
|---|---|
|
||||
| `controllerMethod` (all five channels) | Every channel is **rebuilt**: the running controllers are stopped and a fresh set is built from the new settings. A channel that owns a connection reconnects — Telegram re-runs its `getMe` handshake, NapCat opens a new WebSocket — so notifications sent during the swap are lost. The rebuild only happens when this section actually changed; saving a message template does not disturb the channels. |
|
||||
| `controllerMessage`, `debug`, `bot_user_config.json`, `bot_node_config.json`, `webhook.endpoints` | Picked up as they are used; nothing is restarted. |
|
||||
| `system.debugMode` | Applies to both behavior and log filtering. |
|
||||
| `system.networkProxy` | Applies to connections opened afterwards. Channels that were built with `networkUseProxy` capture the proxy when they connect, so the address is only re-read on the next rebuild; the controller rebuild above does that. |
|
||||
| `system.listenAddr` / `listenPort`, `webhook.enabled` / `listenAddr` / `listenPort`, `dataPath`, `dbPath`, `komari.dashboardURL` | **Applied at startup only.** Saving them changes the file and the in-memory configuration but not the running listener, database or Komari client — restart to apply. |
|
||||
|
||||
## API
|
||||
|
||||
Success responses follow the envelope `{"success": true, "message": "...", "data": {...}}`, with the payload nested under a single `data` key. Error responses use `{"success": false, "message": "..."}`. `message` may be omitted on success when there is nothing to report.
|
||||
@@ -322,7 +334,7 @@ Browser WebSocket handshakes cannot carry custom headers, so `/api/system/getLog
|
||||
| `/api/server/getStatus` | GET | admin | Live server status (mirrors the Bot's `/status`). Query `?uuid=<uuid>` (or `all`). Returns `data: {<uuid>: {uuid, name, online, report}}`; `report` is `null` when the node has not reported yet. `404` for an unknown single uuid. |
|
||||
| `/api/server/exec` | POST | bot / admin | Execute a command. Body `{uuid: [<uuid>...], command}`. Dispatches a Komari task and polls until completion (or timeout). Returns `data: {taskID, results}`. |
|
||||
| `/api/settings/get` | GET | admin | `?type=global\|bot_user_config\|bot_node_config` | Returns `data: {config}`, where `config` is the selected config file's content (same layout as the JSON file). |
|
||||
| `/api/settings/set` | POST | admin | `?type=<same types>` + JSON body of partial updates, e.g. `{"system":{"debugMode":true}}` | Deep-merges the body into the selected config file, persists it, and reloads it in memory. Only the given keys change; arrays replace. |
|
||||
| `/api/settings/set` | POST | admin | `?type=<same types>` + JSON body of partial updates, e.g. `{"system":{"debugMode":true}}` | Deep-merges the body into the selected config file, persists it, and reloads it in memory. Only the given keys change; arrays replace. See [What applies without a restart](#what-applies-without-a-restart). |
|
||||
| `/api/webhook/add` | POST | admin | Add an incoming webhook endpoint. Body `{name, enabled?, token?, notifyPipes?}` — only the fields given are stored, the rest start at their defaults. `409` when the name is already configured. |
|
||||
| `/api/webhook/modify` | POST | admin | Change an existing endpoint. Body `{name, ...}` — the fields given are the fields that change (same partial-update rule as `/api/settings/set`, but scoped to one endpoint). `404` for an unknown name, `400` when no other field is given. |
|
||||
| `/api/webhook/delete` | POST | admin | Remove an endpoint. Body `{name}`. `404` for an unknown name. |
|
||||
|
||||
Reference in New Issue
Block a user