Skip to content

Conversation

untitaker
Copy link
Collaborator

@untitaker untitaker commented Jun 2, 2025

Add UI for getting config, setting config, and restarting rayhunter.

The endpoints for config expose JSON instead of TOML for ease of use from JS.

The restart endpoint does not restart the entire process, but rather all threads. In theory this is more portable than trying to restart the entire process. In practice this seems to cause some issues with the diag device, which are worked around with a 5 second sleep.

Only tested on TP-Link M7350, no other devices.

image

@alliraine
Copy link
Collaborator

Amazinggg. I'll get a UI working for this!

@untitaker untitaker force-pushed the restart branch 3 times, most recently from 6e20a3e to d0f2903 Compare June 11, 2025 13:13
@untitaker untitaker marked this pull request as ready for review June 19, 2025 16:41
@untitaker
Copy link
Collaborator Author

untitaker commented Jun 19, 2025

This now has UI and is ready for review. There is a bug where if I have key_input_mode = 1, the shutdown hangs -- I'll file a separate PR for that.

@untitaker untitaker changed the title Config change and restart endpoints Config change and restart UI Jun 19, 2025
untitaker added a commit that referenced this pull request Jun 19, 2025
Discovered in #351 where restart would hang forever.

key_input.rs never properly implemented shutdown because it didn't have
to do anything interesting on shutdown.

Wire up oneshot channels so that it falls in line with other services.

I do wonder though if there's a more clever way of handling this. For
example I could just not use the task_tracker, use tokio::spawn and let
the task get cancelled by tokio.
untitaker added a commit to untitaker/rayhunter that referenced this pull request Jun 19, 2025
Discovered in EFForg#351 where restart would hang forever.

key_input.rs never properly implemented shutdown because it didn't have
to do anything interesting on shutdown.

Wire up oneshot channels so that it falls in line with other services.

I do wonder though if there's a more clever way of handling this. For
example I could just not use the task_tracker, use tokio::spawn and let
the task get cancelled by tokio.
untitaker added a commit to untitaker/rayhunter that referenced this pull request Jun 20, 2025
Discovered in EFForg#351 where restart would hang forever.

key_input.rs never properly implemented shutdown because it didn't have
to do anything interesting on shutdown.

Wire up oneshot channels so that it falls in line with other services.

I do wonder though if there's a more clever way of handling this. For
example I could just not use the task_tracker, use tokio::spawn and let
the task get cancelled by tokio.
Discovered in EFForg#351 where restart would hang forever.

key_input.rs never properly implemented shutdown because it didn't have
to do anything interesting on shutdown.

Wire up oneshot channels so that it falls in line with other services.

I do wonder though if there's a more clever way of handling this. For
example I could just not use the task_tracker, use tokio::spawn and let
the task get cancelled by tokio.
@cooperq
Copy link
Collaborator

cooperq commented Jun 23, 2025

Testing this out, restart worked great the first time but crashed rayhunter the second time. Logs below:

[2025-06-23T17:00:14Z WARN  asn1_codecs::per::common::decode] Skipped decoding 1 Extensions.
[2025-06-23T17:00:14Z INFO  rayhunter_daemon] Closing current QMDL entry...
[2025-06-23T17:00:14Z INFO  rayhunter_daemon] Done!
[2025-06-23T17:00:14Z INFO  rayhunter_daemon] Server received shutdown signal, exiting...
[2025-06-23T17:00:14Z INFO  rayhunter_daemon::diag] Diag reader thread exiting...
[2025-06-23T17:00:15Z INFO  rayhunter_daemon::display::generic_framebuffer] received UI shutdown
[2025-06-23T17:00:15Z INFO  rayhunter_daemon] see you space cowboy...
Restarting Rayhunter. Waiting for 5 seconds...
R A Y H U N T E R 🐳
[2025-06-23T17:00:20Z INFO  rayhunter::diag_device] retrieving diag logging capabilities...
[2025-06-23T17:00:20Z WARN  rayhunter::diag] warning: 329 leftover bytes when parsing Message
[2025-06-23T17:00:20Z INFO  rayhunter::diag_device] enabled logging for log type 1
[2025-06-23T17:00:20Z WARN  rayhunter::diag] warning: 298 leftover bytes when parsing Message
[2025-06-23T17:00:20Z INFO  rayhunter::diag_device] enabled logging for log type 4
[2025-06-23T17:00:20Z WARN  rayhunter::diag] warning: 140 leftover bytes when parsing Message
[2025-06-23T17:00:20Z INFO  rayhunter::diag_device] enabled logging for log type 5
[2025-06-23T17:00:20Z WARN  rayhunter::diag] warning: 168 leftover bytes when parsing Message
[2025-06-23T17:00:20Z INFO  rayhunter::diag_device] enabled logging for log type 7
[2025-06-23T17:00:20Z WARN  rayhunter::diag] warning: 122 leftover bytes when parsing Message
[2025-06-23T17:00:20Z INFO  rayhunter::diag_device] enabled logging for log type 10
[2025-06-23T17:00:20Z WARN  rayhunter::diag] warning: 73 leftover bytes when parsing Message
[2025-06-23T17:00:20Z INFO  rayhunter::diag_device] enabled logging for log type 11
[2025-06-23T17:00:20Z WARN  rayhunter::diag] warning: 72 leftover bytes when parsing Message
[2025-06-23T17:00:20Z INFO  rayhunter::diag_device] enabled logging for log type 13
[2025-06-23T17:00:20Z INFO  rayhunter_daemon] Starting Diag Thread
[2025-06-23T17:00:20Z INFO  rayhunter_daemon] Starting UI
[2025-06-23T17:00:20Z INFO  rayhunter_daemon] Starting Key Input service
[2025-06-23T17:00:20Z INFO  rayhunter_daemon] create shutdown thread
[2025-06-23T17:00:20Z INFO  rayhunter_daemon] spinning up server
[2025-06-23T17:00:20Z INFO  rayhunter_daemon] The orca is hunting for stingrays...
[2025-06-23T17:00:26Z WARN  asn1_codecs::per::common::decode] Skipping Extensions Decoding....
[2025-06-23T17:00:26Z WARN  asn1_codecs::per::common::decode] Skipped decoding 1 Extensions.
[2025-06-23T17:00:26Z WARN  asn1_codecs::per::common::decode] Skipping Extensions Decoding....
[2025-06-23T17:00:26Z WARN  asn1_codecs::per::common::decode] Skipped decoding 1 Extensions.
[2025-06-23T17:00:26Z WARN  asn1_codecs::per::common::decode] Skipping Extensions Decoding....
[2025-06-23T17:00:26Z WARN  asn1_codecs::per::common::decode] Skipped decoding 3 Extensions.
[2025-06-23T17:00:45Z WARN  asn1_codecs::per::common::decode] Skipping Extensions Decoding....
[2025-06-23T17:00:45Z WARN  asn1_codecs::per::common::decode] Skipped decoding 2 Extensions.
[2025-06-23T17:00:45Z WARN  asn1_codecs::per::common::decode] Skipping Extensions Decoding....
[2025-06-23T17:00:45Z WARN  asn1_codecs::per::common::decode] Skipped decoding 2 Extensions.
[2025-06-23T17:00:46Z WARN  asn1_codecs::per::common::decode] Skipping Extensions Decoding....
[2025-06-23T17:00:46Z WARN  asn1_codecs::per::common::decode] Skipped decoding 1 Extensions.
[2025-06-23T17:00:46Z WARN  asn1_codecs::per::common::decode] Skipping Extensions Decoding....
[2025-06-23T17:00:46Z WARN  asn1_codecs::per::common::decode] Skipped decoding 1 Extensions.
[2025-06-23T17:00:46Z WARN  asn1_codecs::per::common::decode] Skipping Extensions Decoding....
[2025-06-23T17:00:46Z WARN  asn1_codecs::per::common::decode] Skipped decoding 3 Extensions.
[2025-06-23T17:01:20Z INFO  rayhunter_daemon] Closing current QMDL entry...
[2025-06-23T17:01:20Z INFO  rayhunter_daemon] Done!
[2025-06-23T17:01:20Z INFO  rayhunter_daemon] Server received shutdown signal, exiting...
[2025-06-23T17:01:20Z INFO  rayhunter_daemon::key_input] received key input shutdown
[2025-06-23T17:01:20Z INFO  rayhunter_daemon::diag] Diag reader thread exiting...
[2025-06-23T17:01:21Z INFO  rayhunter_daemon::display::generic_framebuffer] received UI shutdown
[2025-06-23T17:01:21Z INFO  rayhunter_daemon] see you space cowboy...
Restarting Rayhunter. Waiting for 5 seconds...
R A Y H U N T E R 🐳
Error: DiagInitError(InitializationFailed("DIAG_IOCTL_SWITCH_LOGGING ioctl failed with error code -1"))

@cooperq
Copy link
Collaborator

cooperq commented Jun 23, 2025

was able to reproduce this crash, sometimes it happens on the second config change, last time it took until the 3rd or 4th config change. Possibly a race condition?

@untitaker
Copy link
Collaborator Author

yes i saw this on tplink too. i worked around it with the sleep 5 in code, and haven't encountered it since. probably have to dig a bit deeper. if that investigation doesn't bring anything up, how about opening the diag device with exponential backoff?

Copy link
Collaborator

@wgreenberg wgreenberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like this approach a lot, thanks for all the work on it. got a couple questions/comments

Comment on lines 113 to 118
let config = parse_config(&state.config_path).await.map_err(|err| {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("failed to read config file: {}", err),
)
})?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess this is a broader API question, but should GET /api/config return the currently loaded config, or the current state of the config file (as implemented here)? i'm leaning towards the former, since that's what'd be most helpful for the user i think, but i could go either way

Copy link
Collaborator Author

@untitaker untitaker Jun 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we say the only valid flow is "get config, set config, restart" then i'd take the currently loaded config. but i think there are valid reasons one may want to postpone the restart and instead make a change to the config, then later make another change.

but yeah it makes it hard to reason about what the currently loaded config is. i can add some marker that tells the user the currently saved config is out of sync with the daemon's loaded config. what do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a marker here is right, but I also wonder if we should just have one botton that both saves the config and reloads the daemon instead of having two steps

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, a dirty_config flag or something to mark that the config is written but not active yet would be great

Comment on lines 273 to 277
{:else}
<div class="text-center py-4 text-red-600">
Failed to load configuration. Please try reloading the page.
</div>
{/if}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm indentation seems a bit wonky here

untitaker and others added 3 commits June 23, 2025 21:03
@untitaker
Copy link
Collaborator Author

I removed all advanced and disabled options now to make the UI simpler. If somebody really wants to change the storage path, port or dummy analyzer mode then we can put effort into that and deal with the UI complexity then.

@untitaker
Copy link
Collaborator Author

@cooperq i couldn't figure out what the error is about. if it happens on orbic then i suspect we are using the diag interface wrong. i added an exponential backoff instead of static 5 second sleep, hope it helps with orbic too.

@cooperq
Copy link
Collaborator

cooperq commented Jun 23, 2025

New version works much better, I think exponential backoff was the way to go here.


pub async fn set_config(
State(state): State<Arc<ServerState>>,
Json(config): Json<Config>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to double-check my assumption, since we're saying this is a JSON-serialized Config struct, axon handles invalid input such as config.ui_level = "foo" right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes it'll just return a 400 or similar

@untitaker
Copy link
Collaborator Author

I think everything is addressed. There's only just one "Save and apply" button now.

wgreenberg
wgreenberg previously approved these changes Jun 23, 2025
Copy link
Collaborator

@cooperq cooperq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems to work great, merging!

@untitaker untitaker merged commit 542aff4 into EFForg:main Jun 24, 2025
18 checks passed
@untitaker untitaker deleted the restart branch July 30, 2025 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants