-
Notifications
You must be signed in to change notification settings - Fork 0
Experiment: auto reload settings #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,28 +1,38 @@ | ||||||||||
| import log from "loglevel"; | ||||||||||
| import { type Runtime, runtime } from "webextension-polyfill"; | ||||||||||
| import { ArrayQueue, ConstantBackoff, WebsocketBuilder } from "websocket-ts"; | ||||||||||
|
|
||||||||||
| import { defaultSettings, loadSettings, type Settings } from "#/settings"; | ||||||||||
| import { type Runtime, runtime, storage } from "webextension-polyfill"; | ||||||||||
| import { ArrayQueue, WebsocketBuilder } from "websocket-ts"; | ||||||||||
| import { | ||||||||||
| defaultSettings, | ||||||||||
| getEndpoint, | ||||||||||
| loadSettings, | ||||||||||
| type Settings, | ||||||||||
| } from "#/settings"; | ||||||||||
| import { | ||||||||||
| resetConnectionState, | ||||||||||
| setConnectionState, | ||||||||||
| setupConnectionStateListener, | ||||||||||
| } from "./connectionState"; | ||||||||||
| import { startHeartbeat } from "./heartbeat"; | ||||||||||
| import { updateIcon } from "./utils"; | ||||||||||
|
|
||||||||||
| // init on load | ||||||||||
| (async () => init())(); | ||||||||||
|
|
||||||||||
| let settings: Settings = defaultSettings; | ||||||||||
|
|
||||||||||
| const activeConnections: Map<number, { close: () => void }> = new Map(); | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Loads the current settings, and listens for incoming connections (from the injected contentscript) | ||||||||||
| */ | ||||||||||
| async function init() { | ||||||||||
| startHeartbeat(); | ||||||||||
| settings = await loadSettings(); | ||||||||||
| log.setLevel(settings.logLevel); | ||||||||||
| updateIcon(settings.devMode); | ||||||||||
|
|
||||||||||
| setupConnectionStateListener(); | ||||||||||
| setupSettingsChangeListener(); | ||||||||||
|
|
||||||||||
| // handle each incoming content script connection | ||||||||||
| runtime.onConnect.addListener((port: Runtime.Port) => { | ||||||||||
|
|
@@ -38,6 +48,43 @@ async function init() { | |||||||||
| }); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Listen for settings changes and reconnect all active connections when endpoint changes | ||||||||||
| */ | ||||||||||
| function setupSettingsChangeListener() { | ||||||||||
| storage.onChanged.addListener((changes, areaName) => { | ||||||||||
| if (areaName !== "sync") return; | ||||||||||
|
|
||||||||||
| if (changes.logLevel?.newValue) { | ||||||||||
| settings.logLevel = changes.logLevel.newValue as Settings["logLevel"]; | ||||||||||
| log.setLevel(settings.logLevel); | ||||||||||
| log.debug("Log level changed to", settings.logLevel); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (changes.devMode?.newValue !== undefined) { | ||||||||||
| settings.devMode = changes.devMode.newValue as boolean; | ||||||||||
| log.debug( | ||||||||||
| "Dev mode changed to", | ||||||||||
| settings.devMode, | ||||||||||
| "- endpoint:", | ||||||||||
| getEndpoint(settings), | ||||||||||
| ); | ||||||||||
|
|
||||||||||
| // Update icon color | ||||||||||
| updateIcon(settings.devMode); | ||||||||||
|
|
||||||||||
| // Reset connection state to trigger fresh check | ||||||||||
| resetConnectionState(); | ||||||||||
|
|
||||||||||
| // Close all active connections - they will reconnect with new endpoint on next message | ||||||||||
| for (const [tabId, conn] of activeConnections) { | ||||||||||
| log.debug(`Closing connection for tab ${tabId}`); | ||||||||||
| conn.close(); | ||||||||||
| } | ||||||||||
|
||||||||||
| } | |
| } | |
| // Clear the map to avoid repeatedly closing the same connections if settings change again | |
| activeConnections.clear(); |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intentionalClose flag could have a race condition. If a WebSocket close event happens naturally (due to network issues) at the same time as settings are changed, the flag might be set to true but then the natural close event could reset it to false (line 177), causing the next settings-triggered close to be treated as an error. Consider using a more robust approach, such as checking a timestamp or having separate handling for settings changes that doesn't rely on a boolean flag that can be affected by concurrent events.
| intentionalClose = false; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { action } from "webextension-polyfill"; | ||
|
|
||
| export function updateIcon(devMode: boolean) { | ||
| const color = devMode ? "purple" : "black"; | ||
| action.setIcon({ | ||
| path: { | ||
| 16: `/icons/ethui-${color}-16.png`, | ||
| 48: `/icons/ethui-${color}-48.png`, | ||
| 96: `/icons/ethui-${color}-96.png`, | ||
| 128: `/icons/ethui-${color}-128.png`, | ||
| }, | ||
| }); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -24,8 +24,13 @@ | |||||
| </div> | ||||||
|
|
||||||
| <div class="form-section"> | ||||||
| <label class="label">Endpoint</label> | ||||||
| <input type="text" id="endpoint" /> | ||||||
| <label> | ||||||
| <input type="checkbox" id="dev-mode" /> | ||||||
| Developer Mode | ||||||
| </label> | ||||||
| <p style="font-size: 12px; color: #666;"> | ||||||
| Connects to port ethui's debug build instead of release. Meant for developers and contributors only. | ||||||
|
||||||
| Connects to port ethui's debug build instead of release. Meant for developers and contributors only. | |
| Connects to ethui's debug build instead of the release build. Meant for developers and contributors only. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for devMode changes using
!== undefined(line 64) is more lenient than the check for logLevel which uses truthy checking (line 58). This means setting devMode to false will correctly trigger the handler, but setting logLevel to an empty string (which shouldn't happen but could due to corruption) would not trigger the handler. For consistency and robustness, consider using!== undefinedfor logLevel as well, or add validation to ensure logLevel is one of the valid values.