Fix Fenrir Unix socket ownership reporting
This commit is contained in:
128
AGENTS.md
Normal file
128
AGENTS.md
Normal file
@@ -0,0 +1,128 @@
|
||||
## Development Philosophy
|
||||
|
||||
**Clean code over backward compatibility.** Breaking changes are acceptable in major versions.
|
||||
|
||||
- PEP8 compliance (snake_case for all variables/functions/settings)
|
||||
- Remove deprecated code completely - no compatibility hacks
|
||||
- Trust users to update configs when upgrading
|
||||
|
||||
**Exception**: Never break core accessibility (speech output, basic navigation).
|
||||
|
||||
## Core Architecture
|
||||
|
||||
### Drivers
|
||||
- **Screen**: `vcsaDriver` (TTY), `ptyDriver` (terminal emulation)
|
||||
- **Input**: `evdevDriver` (evdev), `x11Driver` (X11 terminal mode)
|
||||
- **Speech**: `speechdDriver` (speech-dispatcher), `genericDriver` (subprocess)
|
||||
- **Sound**: `gstreamerDriver` (GStreamer), `genericDriver` (Sox subprocess)
|
||||
- **Remote**: `unixDriver` (Unix sockets), `tcpDriver`
|
||||
|
||||
### Command System
|
||||
Commands in trigger folders execute automatically:
|
||||
- `onKeyInput/`, `onCursorChange/`, `onScreenUpdate/`, `onScreenChanged/`, `onHeartBeat/`
|
||||
- Numeric prefixes control priority (lower = higher priority): `15000-char_echo.py`
|
||||
- Manual commands in `commands/commands/`
|
||||
|
||||
### Core Managers (in `src/fenrirscreenreader/core/`)
|
||||
`fenrirManager.py`, `commandManager.py`, `eventManager.py`, `screenManager.py`, `inputManager.py`, `outputManager.py`
|
||||
|
||||
### Configuration
|
||||
- Main: `config/settings/settings.conf`
|
||||
- Keyboards: `config/keyboard/` (desktop.conf, laptop.conf)
|
||||
- Sounds: `config/sound/`
|
||||
- Punctuation: `config/punctuation/`
|
||||
|
||||
## 🚨 CRITICAL: Files to NEVER Modify
|
||||
|
||||
**These are timing-critical - only fix critical bugs, never refactor:**
|
||||
- `evdevDriver.py` - Input event processing
|
||||
- `vcsaDriver.py` - Screen monitoring
|
||||
|
||||
Symptoms of breakage: echo changes, input lag, missing screen updates, sync issues.
|
||||
|
||||
## Development Commands
|
||||
|
||||
```bash
|
||||
# Run from source (requires root)
|
||||
cd src/ && sudo ./fenrir -f -d # foreground with debug
|
||||
|
||||
# Validation before commit
|
||||
python3 tools/validate_syntax.py --fix
|
||||
python3 tools/validate_release.py --quick
|
||||
|
||||
# Tests
|
||||
pytest tests/
|
||||
pytest tests/ --cov=src/fenrirscreenreader --cov-report=html
|
||||
```
|
||||
|
||||
**Note**: Standard TTY Fenrir blocks - only one instance at a time. `fenrir -x`
|
||||
can run multiple foreground X terminal instances. Ask user to run tests that
|
||||
need real Fenrir instances or root access.
|
||||
|
||||
## Creating Commands
|
||||
|
||||
Use `commands/command_template.py` as base. Required methods:
|
||||
- `initialize(self, environment)`, `shutdown()`, `run()`, `get_description()`
|
||||
|
||||
### Import Pattern (Required)
|
||||
Fenrir's command loader doesn't support relative imports:
|
||||
```python
|
||||
import os, importlib.util
|
||||
_base_path = os.path.join(os.path.dirname(__file__), 'base_file.py')
|
||||
_spec = importlib.util.spec_from_file_location("base_module", _base_path)
|
||||
_module = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(_module)
|
||||
BaseClass = _module.BaseClass
|
||||
```
|
||||
|
||||
### Consolidated Base Classes
|
||||
- **Bookmarks**: `bookmark_base.py` - `BookmarkCommand(id, 'read'|'set'|'clear')`
|
||||
- **Adjustments**: `adjustment_base.py` - `AdjustmentCommand('speech'|'sound', 'rate'|'pitch'|'volume', 'inc'|'dec')`
|
||||
- **VMenu Search**: `vmenu_search_base.py` - `VMenuSearchCommand('a'-'z')`
|
||||
|
||||
## VMenu System
|
||||
|
||||
Application-specific menus in `vmenu-profiles/KEY/{app}/`:
|
||||
- Directories = submenus, `.py` files = actions
|
||||
- Activate: `Fenrir+F10`, navigate with arrows, Enter to execute
|
||||
|
||||
## Remote Control
|
||||
|
||||
Unix socket: `/tmp/fenrirscreenreader-deamon.sock`
|
||||
TCP: localhost:22447
|
||||
|
||||
```bash
|
||||
echo "command say Hello" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
echo "setting set speech#rate=0.8" | nc localhost 22447
|
||||
```
|
||||
|
||||
In `fenrir -x`, each instance has a private socket:
|
||||
`/tmp/fenrirscreenreader-<pid>.sock`. One instance may also own the standard
|
||||
socket. Use `ls`/`list` on the standard socket to discover registered instances
|
||||
and their socket paths. Untargeted remote commands use a short cross-process
|
||||
claim lock so only one instance handles the same broadcast command; direct
|
||||
commands to a private instance socket still run on that instance.
|
||||
|
||||
Disable in untrusted environments: `[remote] enable=False`
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
- Commands via `command_mod.command()` instantiation
|
||||
- Bookmark structure: `env['commandBuffer']['bookMarks'][ID][app]['1'/'2']`
|
||||
- VMenu search: `env['runtime']['vmenuManager'].searchEntry(char)`
|
||||
|
||||
## Recent Fixes (Reference)
|
||||
|
||||
- Enhanced application detection for screen/tmux sessions
|
||||
- Table navigation consistency (sound feedback)
|
||||
- Blank line detection in 22 command files
|
||||
- Character/space review during navigation
|
||||
|
||||
## Safe vs Risky Changes
|
||||
|
||||
**Safe**: Commands, VMenu profiles, config handling, sound/speech drivers, docs
|
||||
|
||||
**Risky (extra testing)**: Core managers, event processing
|
||||
|
||||
**Avoid**: evdevDriver, vcsaDriver, timing-critical code
|
||||
@@ -5,4 +5,4 @@
|
||||
# By Chrys, Storm Dragon, and contributors.
|
||||
|
||||
version = "2026.05.07"
|
||||
code_name = "testing"
|
||||
code_name = "master"
|
||||
|
||||
@@ -115,14 +115,22 @@ class driver(remoteDriver):
|
||||
|
||||
def _socket_file_matches_socket(self, fenrir_sock, socket_file):
|
||||
try:
|
||||
socket_stat = os.stat(socket_file)
|
||||
if os.stat(socket_file).st_uid != os.getuid():
|
||||
return False
|
||||
fd_stat = os.fstat(fenrir_sock.fileno())
|
||||
socket_inode = str(fd_stat.st_ino)
|
||||
with open("/proc/net/unix", "r", encoding="utf-8") as proc_file:
|
||||
for line in proc_file:
|
||||
line_parts = line.split()
|
||||
if (
|
||||
len(line_parts) >= 8
|
||||
and line_parts[6] == socket_inode
|
||||
and line_parts[7] == socket_file
|
||||
):
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
return (
|
||||
socket_stat.st_dev == fd_stat.st_dev
|
||||
and socket_stat.st_ino == fd_stat.st_ino
|
||||
)
|
||||
return False
|
||||
|
||||
def _cleanup(self):
|
||||
for fenrir_sock in self.fenrirSocks:
|
||||
|
||||
Reference in New Issue
Block a user