Skip to content

feat: Repeater admin view with login, CLI, and password storage#76

Merged
cwill747 merged 2 commits into
mainfrom
repeater-admin
May 18, 2026
Merged

feat: Repeater admin view with login, CLI, and password storage#76
cwill747 merged 2 commits into
mainfrom
repeater-admin

Conversation

@cwill747
Copy link
Copy Markdown
Owner

Summary

  • Add Admin tab with repeater list, login/logout (admin + guest), and a terminal-style CLI console for sending commands
  • Add RepeaterPasswordStore backed by SQLite (base64-obfuscated) for optional password persistence across sessions
  • Extend MeshcoreService protocol, MeshcoreClient, MockMeshcoreClient, and PyMCCoreSession with repeater admin operations (login, logout, send_repeater_command)
  • Extract _resolve_contact() helper in operations.py to deduplicate contact lookup across all 5 async operations
  • Add TXT_TYPE_CLI_DATA constant to replace magic number
  • New mock CLI responses and an additional mock repeater peer for UI development

Test plan

  • Run uv run pytest — 98 passed, 1 skipped
  • Run in mock mode (MESHCORE_MOCK=1 ./scripts/run-dev.sh), navigate to Admin tab
  • Login to a repeater (admin and guest), verify status indicators
  • Send CLI commands (status, ver, help), verify console output
  • Save/delete repeater password, verify persistence across restarts
  • Logout and verify session cleanup

🤖 Generated with Claude Code

Adds a full repeater administration feature: login/logout to repeaters
(admin or guest), send CLI commands with a terminal-style console, and
optionally persist repeater passwords in the local database.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 03e27c4672

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

contact=contact,
local_identity=node.identity,
message=command,
txt_type=TXT_TYPE_CLI_DATA,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove unsupported txt_type argument from create_text_message

send_repeater_command() passes txt_type=TXT_TYPE_CLI_DATA into PacketBuilder.create_text_message, but the pyMC_core 1.0.10 API for create_text_message only accepts contact, local_identity, message, attempt, message_type, and out_path. On real hardware this call path will raise a TypeError before any packet is sent, so every CLI command from the new Admin view fails at runtime.

Useful? React with 👍 / 👎.

if self._selected_repeater is None:
return
peer_name = self._selected_repeater.display_name
self._service.logout_from_repeater(peer_name)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid blocking GTK main loop during repeater logout

_on_logout_clicked() calls logout_from_repeater() synchronously on the UI thread, and that client method can block for up to 5 seconds while waiting on radio I/O (_run_async(..., timeout=5.0)). If the repeater is slow or unreachable, the whole GTK interface freezes during logout, unlike login/command flows that already use background threads.

Useful? React with 👍 / 👎.

Comment on lines +210 to +212
def _on_response(message_text: str, sender_contact: object) -> None:
response_data["text"] = message_text
response_event.set()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Filter command responses by originating repeater

send_repeater_command() installs a global command-response callback and resolves the wait on the first callback invocation, but _on_response ignores the provided sender_contact. If another repeater emits a command response while this request is in flight, the wrong payload can satisfy the wait and be attributed to peer_name, producing cross-repeater response mixups.

Useful? React with 👍 / 👎.

Comment on lines +651 to +652
label.set_wrap(True)
label.set_wrap_mode(Pango.WrapMode.CHAR)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Constrain console response label width explicitly

The console appends unbounded Gtk.Labels and only enables wrapping; in GTK4, wrapping alone does not make requisition depend on parent width, so long unbroken CLI output can report very large natural widths and force window expansion. This reproduces the known GTK sizing pitfall and can blow out the Admin layout when responses are lengthy.

Useful? React with 👍 / 👎.

Comment on lines +624 to +626
text = result.get("response_text", "")
if text:
self._append_console_response(text)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep command completion scoped to the original repeater

A command request captures peer_name, but the completion handler always appends output to the currently visible console without checking whether the user switched selection while the worker thread was running. If the operator selects repeater B before repeater A’s response arrives, A’s output is rendered under B, which misattributes administrative command results.

Useful? React with 👍 / 👎.

Comment on lines +520 to +522
state = self._service.get_repeater_login_state(peer_name)
self._update_login_ui(state)
self._append_console_response("Login successful")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Ignore stale login completion after selection changes

Login completion updates status widgets unconditionally after the background thread returns. Because row selection remains interactive during login, switching to another repeater before completion lets repeater A’s result drive repeater B’s login banner/buttons, producing incorrect UI state and potentially enabling or disabling controls for the wrong target.

Useful? React with 👍 / 👎.

- Filter command responses by originating repeater public key
- Move logout to background thread to avoid blocking GTK main loop
- Guard login/command completion handlers against stale selection
- Constrain console label width to prevent GTK4 window blowout

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cwill747 cwill747 merged commit eb9699b into main May 18, 2026
9 checks passed
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.

1 participant