More work on sockets attempt to get socket command to standard daemon.sock to a running instance. Also, fixed a long standing misspelling in daemon, was deamon, so if your scripts that self-voice or whatever with fenrir no longer work, this is why, please update scripts to the new, correct, daemon.sock.

This commit is contained in:
Storm Dragon
2026-05-20 20:11:21 -04:00
parent 8467bd74c3
commit 4caef89f6b
10 changed files with 461 additions and 96 deletions
+3 -3
View File
@@ -88,12 +88,12 @@ Application-specific menus in `vmenu-profiles/KEY/{app}/`:
## Remote Control ## Remote Control
Unix socket: `/tmp/fenrirscreenreader-deamon.sock` Unix socket: `/tmp/fenrirscreenreader-daemon.sock`
TCP: localhost:22447 TCP: localhost:22447
```bash ```bash
echo "command say Hello" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command say Hello" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#rate=0.8" | nc localhost 22447 echo "setting set speech#rate=0.8" | nc localhost 22447
``` ```
+40 -37
View File
@@ -281,7 +281,7 @@ enable_command_remote=True # allow command execution
### Remote Drivers ### Remote Drivers
1. **unixDriver** (recommended): Uses Unix domain sockets 1. **unixDriver** (recommended): Uses Unix domain sockets
- Socket location: `/tmp/fenrirscreenreader-deamon.sock` for the standard control socket - Socket location: `/tmp/fenrirscreenreader-daemon.sock` for the standard control socket
- `fenrir -x` instances also create private sockets: `/tmp/fenrirscreenreader-<pid>.sock` - `fenrir -x` instances also create private sockets: `/tmp/fenrirscreenreader-<pid>.sock`
- More secure, local-only access - More secure, local-only access
- Works with `socat` - Works with `socat`
@@ -298,99 +298,102 @@ The `socat` command provides the easiest way to send commands to Fenrir:
#### Instance Discovery #### Instance Discovery
```bash ```bash
# List registered Fenrir instances and their socket paths # List registered Fenrir instances and their socket paths
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
In X terminal mode (`fenrir -x`), multiple Fenrir instances can run at the same In X terminal mode (`fenrir -x`), multiple Fenrir instances can run at the same
time. Each instance has a private socket, and one instance may also own the time. Each instance has a private socket, and one instance may also own the
standard control socket. Use `ls` or `command ls` on the standard socket to find standard control socket. Use `ls` or `command ls` on the standard socket to find
the private socket for a specific instance. Untargeted commands sent through a the private socket for a specific instance. Commands sent to the standard socket
shared or broadcast path are claimed by one instance so duplicate instances do are handled by its owner when possible; otherwise they are forwarded to a
not all perform the same action. registered private socket, preferring the sender's Fenrir ancestor when one can
be found. Untargeted commands sent through a shared or broadcast path are
claimed by one instance so duplicate instances do not all perform the same
action.
#### Basic Speech Control #### Basic Speech Control
```bash ```bash
# Interrupt current speech # Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Speak custom text # Speak custom text
echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Temporarily disable speech (until next keystroke) # Temporarily disable speech (until next keystroke)
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
#### Settings Control #### Settings Control
```bash ```bash
# Enable highlight tracking mode # Enable highlight tracking mode
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change speech parameters # Change speech parameters
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change punctuation level (none/some/most/all) # Change punctuation level (none/some/most/all)
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set general#punctuation_level=none" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set general#punctuation_level=none" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Voice and TTS engine control # Voice and TTS engine control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Disable sound temporarily # Disable sound temporarily
echo "setting set sound#enabled=False" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set sound#enabled=False" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set sound#volume=0.5" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set sound#volume=0.5" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Keyboard and input settings # Keyboard and input settings
echo "setting set keyboard#char_echo_mode=1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set keyboard#char_echo_mode=1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set keyboard#word_echo=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set keyboard#word_echo=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Screen control (ignore specific TTYs) # Screen control (ignore specific TTYs)
echo "setting set screen#ignore_screen=1,2,3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set screen#ignore_screen=1,2,3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Multiple settings at once # Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset all settings to defaults # Reset all settings to defaults
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Save current settings # Save current settings
echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting saveas /tmp/my-fenrir-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting saveas /tmp/my-fenrir-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
#### Clipboard Operations #### Clipboard Operations
```bash ```bash
# Place text into clipboard # Place text into clipboard
echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Export clipboard to file # Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
#### Window Management #### Window Management
```bash ```bash
# Define a window area (x1 y1 x2 y2) # Define a window area (x1 y1 x2 y2)
echo "command window 0 0 80 24" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command window 0 0 80 24" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset window to full screen # Reset window to full screen
echo "command resetwindow" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command resetwindow" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
#### VMenu Control #### VMenu Control
```bash ```bash
# Set virtual menu context # Set virtual menu context
echo "command vmenu nano/file" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command vmenu nano/file" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset virtual menu # Reset virtual menu
echo "command resetvmenu" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command resetvmenu" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
#### Application Control #### Application Control
```bash ```bash
# Quit Fenrir # Quit Fenrir
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
### Using TCP Driver ### Using TCP Driver
@@ -590,7 +593,7 @@ Fenrir provides intelligent progress bar detection and audio feedback for variou
To enable progress monitoring: To enable progress monitoring:
1. Add a key binding in your keyboard layout file 1. Add a key binding in your keyboard layout file
2. Or use the remote control system: `echo "command progress_bar_monitor" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock` 2. Or use the remote control system: `echo "command progress_bar_monitor" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock`
### Progress Detection Patterns ### Progress Detection Patterns
@@ -651,7 +654,7 @@ Building...
```bash ```bash
# Enable progress monitoring # Enable progress monitoring
echo "command progress_bar_monitor" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command progress_bar_monitor" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Common scenarios where progress monitoring is useful: # Common scenarios where progress monitoring is useful:
wget https://example.com/large-file.zip # Download progress wget https://example.com/large-file.zip # Download progress
@@ -675,7 +678,7 @@ Progress monitoring can be configured through settings:
#!/bin/bash #!/bin/bash
# notify_fenrir.sh - Send notifications to Fenrir # notify_fenrir.sh - Send notifications to Fenrir
SOCKET="/tmp/fenrirscreenreader-deamon.sock" SOCKET="/tmp/fenrirscreenreader-daemon.sock"
fenrir_say() { fenrir_say() {
echo "command say $1" | socat - UNIX-CLIENT:$SOCKET echo "command say $1" | socat - UNIX-CLIENT:$SOCKET
@@ -698,7 +701,7 @@ import os
def send_fenrir_command(command): def send_fenrir_command(command):
"""Send command to Fenrir via Unix socket""" """Send command to Fenrir via Unix socket"""
socket_path = "/tmp/fenrirscreenreader-deamon.sock" socket_path = "/tmp/fenrirscreenreader-daemon.sock"
if os.path.exists(socket_path): if os.path.exists(socket_path):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try: try:
@@ -731,7 +734,7 @@ send_fenrir_command("setting set speech#rate=0.9")
**Commands not working:** **Commands not working:**
- Verify `enable_command_remote=True` in settings - Verify `enable_command_remote=True` in settings
- Check Fenrir debug logs: `/var/log/fenrir.log` - Check Fenrir debug logs: `/var/log/fenrir.log`
- Test with simple command: `echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock` - Test with simple command: `echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock`
## Command Line Options ## Command Line Options
+16 -13
View File
@@ -321,58 +321,61 @@ enable_command_remote=True
.B Instance Discovery: .B Instance Discovery:
.EX .EX
# List registered Fenrir instances and their socket paths # List registered Fenrir instances and their socket paths
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.EE .EE
In X terminal mode (fenrir -x), multiple Fenrir instances can run at the In X terminal mode (fenrir -x), multiple Fenrir instances can run at the
same time. Each instance has a private socket at same time. Each instance has a private socket at
/tmp/fenrirscreenreader-<pid>.sock, and one instance may also own the /tmp/fenrirscreenreader-<pid>.sock, and one instance may also own the
standard control socket. Use ls or "command ls" on the standard socket to standard control socket. Use ls or "command ls" on the standard socket to
find the private socket for a specific instance. find the private socket for a specific instance. Commands sent to the standard
socket are handled by its owner when possible; otherwise they are forwarded to a
registered private socket, preferring the sender's Fenrir ancestor when one can
be found.
.TP .TP
.B Basic Speech Control: .B Basic Speech Control:
.EX .EX
# Interrupt current speech # Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Speak custom text # Speak custom text
echo "command say Hello, this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command say Hello, this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Temporarily disable speech # Temporarily disable speech
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.EE .EE
.TP .TP
.B Settings Control: .B Settings Control:
.EX .EX
# Enable highlight tracking # Enable highlight tracking
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change speech rate # Change speech rate
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change punctuation level (none/some/most/all) # Change punctuation level (none/some/most/all)
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Voice and TTS control # Voice and TTS control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Multiple settings at once # Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset all settings # Reset all settings
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.EE .EE
.TP .TP
.B Clipboard Operations: .B Clipboard Operations:
.EX .EX
# Add text to clipboard # Add text to clipboard
echo "command clipboard Text to copy" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command clipboard Text to copy" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Export clipboard to file # Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.EE .EE
.SS Command Reference .SS Command Reference
+17 -14
View File
@@ -1278,65 +1278,68 @@ The `+socat+` command provides the easiest way to send commands to Fenrir:
.... ....
# List registered Fenrir instances and their socket paths # List registered Fenrir instances and their socket paths
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.... ....
In X terminal mode (`+fenrir -x+`), multiple Fenrir instances can run at the In X terminal mode (`+fenrir -x+`), multiple Fenrir instances can run at the
same time. Each instance has a private socket at same time. Each instance has a private socket at
`+/tmp/fenrirscreenreader-<pid>.sock+`, and one instance may also own the `+/tmp/fenrirscreenreader-<pid>.sock+`, and one instance may also own the
standard control socket. Use `+ls+` or `+command ls+` on the standard socket to standard control socket. Use `+ls+` or `+command ls+` on the standard socket to
find the private socket for a specific instance. find the private socket for a specific instance. Commands sent to the standard
socket are handled by its owner when possible; otherwise they are forwarded to a
registered private socket, preferring the sender's Fenrir ancestor when one can
be found.
===== Basic Speech Control ===== Basic Speech Control
.... ....
# Interrupt current speech # Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Speak custom text # Speak custom text
echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Temporarily disable speech (until next keystroke) # Temporarily disable speech (until next keystroke)
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.... ....
===== Settings Control ===== Settings Control
.... ....
# Enable highlight tracking mode # Enable highlight tracking mode
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change speech rate # Change speech rate
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change punctuation level (none/some/most/all) # Change punctuation level (none/some/most/all)
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Voice and TTS control # Voice and TTS control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Multiple settings at once # Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset all settings to defaults # Reset all settings to defaults
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.... ....
===== Clipboard Operations ===== Clipboard Operations
.... ....
# Place text into clipboard # Place text into clipboard
echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Export clipboard to file # Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.... ....
===== Application Control ===== Application Control
.... ....
# Quit Fenrir # Quit Fenrir
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.... ....
==== Command Reference ==== Command Reference
+23 -21
View File
@@ -143,68 +143,70 @@ enable_command_remote=True # allow command execution
#### Instance Discovery #### Instance Discovery
```bash ```bash
# List registered Fenrir instances and their socket paths # List registered Fenrir instances and their socket paths
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
In X terminal mode (`fenrir -x`), multiple Fenrir instances can run at the same In X terminal mode (`fenrir -x`), multiple Fenrir instances can run at the same
time. Each instance has a private socket at `/tmp/fenrirscreenreader-<pid>.sock`, time. Each instance has a private socket at `/tmp/fenrirscreenreader-<pid>.sock`,
and one instance may also own the standard control socket. Use `ls` or and one instance may also own the standard control socket. Use `ls` or
`command ls` on the standard socket to find the private socket for a specific `command ls` on the standard socket to find the private socket for a specific
instance. instance. Commands sent to the standard socket are handled by its owner when
possible; otherwise they are forwarded to a registered private socket,
preferring the sender's Fenrir ancestor when one can be found.
#### Speech Control #### Speech Control
```bash ```bash
# Interrupt current speech # Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Speak custom text # Speak custom text
echo "command say Hello, this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command say Hello, this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Temporarily disable speech # Temporarily disable speech
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
#### Settings Control #### Settings Control
```bash ```bash
# Enable highlight tracking # Enable highlight tracking
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change speech parameters # Change speech parameters
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change punctuation level (none/some/most/all) # Change punctuation level (none/some/most/all)
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Voice and TTS control # Voice and TTS control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Multiple settings at once # Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset all settings # Reset all settings
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Save settings # Save settings
echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting saveas /tmp/my-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "setting saveas /tmp/my-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
#### Clipboard Operations #### Clipboard Operations
```bash ```bash
# Add text to clipboard # Add text to clipboard
echo "command clipboard Text to copy" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command clipboard Text to copy" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Export clipboard to file # Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
#### Application Control #### Application Control
```bash ```bash
# Quit Fenrir # Quit Fenrir
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
``` ```
### Command Reference ### Command Reference
@@ -240,7 +242,7 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
#### Bash Helper Function #### Bash Helper Function
```bash ```bash
fenrir_say() { fenrir_say() {
echo "command say $1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo "command say $1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
} }
# Usage # Usage
@@ -253,7 +255,7 @@ import socket
import os import os
def send_fenrir_command(command): def send_fenrir_command(command):
socket_path = "/tmp/fenrirscreenreader-deamon.sock" socket_path = "/tmp/fenrirscreenreader-daemon.sock"
if os.path.exists(socket_path): if os.path.exists(socket_path):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try: try:
+1 -1
View File
@@ -485,7 +485,7 @@ class FenrirManager:
os.unlink(pid_socket_file) os.unlink(pid_socket_file)
# Clean up main socket only if it is stale (not active) # Clean up main socket only if it is stale (not active)
main_socket_file = "/tmp/fenrirscreenreader-deamon.sock" main_socket_file = "/tmp/fenrirscreenreader-daemon.sock"
if os.path.exists(main_socket_file): if os.path.exists(main_socket_file):
try: try:
test_sock = socket.socket( test_sock = socket.socket(
@@ -8,6 +8,7 @@ import os
import os.path import os.path
import select import select
import socket import socket
import struct
import time import time
from fenrirscreenreader.core import debug from fenrirscreenreader.core import debug
@@ -16,7 +17,7 @@ from fenrirscreenreader.core.eventData import FenrirEventType
from fenrirscreenreader.core.remoteDriver import RemoteDriver as remoteDriver from fenrirscreenreader.core.remoteDriver import RemoteDriver as remoteDriver
MAIN_SOCKET_FILE = "/tmp/fenrirscreenreader-deamon.sock" MAIN_SOCKET_FILE = "/tmp/fenrirscreenreader-daemon.sock"
class driver(remoteDriver): class driver(remoteDriver):
@@ -132,6 +133,131 @@ class driver(remoteDriver):
return False return False
return False return False
def _socket_file_for_socket(self, fenrir_sock):
for bound_sock, socket_file in self.bound_sockets:
if bound_sock == fenrir_sock:
return socket_file
return ""
def _get_peer_pid(self, client_sock):
so_peercred = getattr(socket, "SO_PEERCRED", 17)
try:
creds = client_sock.getsockopt(
socket.SOL_SOCKET, so_peercred, struct.calcsize("3i")
)
pid, _uid, _gid = struct.unpack("3i", creds)
return pid
except OSError:
return 0
def _get_parent_pid(self, pid):
try:
with open(f"/proc/{pid}/stat", "r", encoding="utf-8") as proc_file:
stat_text = proc_file.read()
except OSError:
return 0
end_command = stat_text.rfind(")")
if end_command == -1:
return 0
stat_fields = stat_text[end_command + 2 :].split()
if len(stat_fields) < 2:
return 0
try:
return int(stat_fields[1])
except ValueError:
return 0
def _find_ancestor_private_socket(self, pid):
seen_pids = set()
while pid > 1 and pid not in seen_pids:
seen_pids.add(pid)
socket_file = f"/tmp/fenrirscreenreader-{pid}.sock"
if self._is_registered_private_socket(socket_file):
return socket_file
pid = self._get_parent_pid(pid)
return ""
def _is_registered_private_socket(self, socket_file):
for instance in remoteInstanceRegistry.list_instances():
if socket_file in instance.get("socket_files", []):
return True
return False
def _get_registered_private_sockets(self):
socket_files = []
for instance in remoteInstanceRegistry.list_instances():
for socket_file in instance.get("socket_files", []):
if socket_file == MAIN_SOCKET_FILE:
continue
if socket_file in socket_files:
continue
socket_files.append(socket_file)
return socket_files
def _find_available_private_socket(self, preferred_socket=""):
socket_files = self._get_registered_private_sockets()
if preferred_socket and preferred_socket in socket_files:
socket_files.remove(preferred_socket)
socket_files.insert(0, preferred_socket)
for socket_file in socket_files:
if self._is_own_socket_file(socket_file):
return socket_file
if self._is_socket_active(socket_file):
return socket_file
return ""
def _is_own_socket_file(self, socket_file):
return any(
socket_file == bound_socket_file
for _bound_sock, bound_socket_file in self.bound_sockets
)
def _has_own_private_socket(self):
return any(
bound_socket_file != MAIN_SOCKET_FILE
for _bound_sock, bound_socket_file in self.bound_sockets
)
def _forward_remote_to_socket(self, data, socket_file):
forward_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
forward_sock.settimeout(0.2)
forward_sock.connect(socket_file)
forward_sock.sendall((data + "\n").encode("utf-8"))
return True
except OSError as e:
self.env["runtime"]["DebugManager"].write_debug_out(
"unixDriver watch_dog: Error forwarding remote data to "
+ socket_file
+ ": "
+ str(e),
debug.DebugLevel.ERROR,
)
return False
finally:
forward_sock.close()
def _route_main_socket_command(self, data, client_sock, socket_file):
if socket_file != MAIN_SOCKET_FILE:
return False
if not self._has_own_private_socket():
return False
peer_pid = self._get_peer_pid(client_sock)
ancestor_socket = ""
if peer_pid > 1:
ancestor_socket = self._find_ancestor_private_socket(peer_pid)
target_socket = self._find_available_private_socket(ancestor_socket)
if not target_socket:
return False
if self._is_own_socket_file(target_socket):
return False
return self._forward_remote_to_socket(data, target_socket)
def _cleanup(self): def _cleanup(self):
for fenrir_sock in self.fenrirSocks: for fenrir_sock in self.fenrirSocks:
try: try:
@@ -152,7 +278,7 @@ class driver(remoteDriver):
self.bound_sockets = [] self.bound_sockets = []
remoteInstanceRegistry.remove_instance() remoteInstanceRegistry.remove_instance()
def _handle_client(self, client_sock, event_queue): def _handle_client(self, client_sock, event_queue, socket_file=""):
try: try:
rawdata = client_sock.recv(8129) rawdata = client_sock.recv(8129)
except Exception as e: except Exception as e:
@@ -173,6 +299,9 @@ class driver(remoteDriver):
client_sock.sendall((response["message"] + "\n").encode("utf-8")) client_sock.sendall((response["message"] + "\n").encode("utf-8"))
return return
if self._route_main_socket_command(data, client_sock, socket_file):
return
event_queue.put( event_queue.put(
{ {
"Type": FenrirEventType.remote_incomming, "Type": FenrirEventType.remote_incomming,
@@ -188,7 +317,7 @@ class driver(remoteDriver):
def watch_dog(self, active, event_queue): def watch_dog(self, active, event_queue):
# echo "command say this is a test" | socat - # echo "command say this is a test" | socat -
# UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock # UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
for socket_file, optional in self._get_socket_candidates(): for socket_file, optional in self._get_socket_candidates():
fenrir_sock = self._bind_socket(socket_file, optional) fenrir_sock = self._bind_socket(socket_file, optional)
if fenrir_sock is None: if fenrir_sock is None:
@@ -215,10 +344,11 @@ class driver(remoteDriver):
continue continue
for fenrir_sock in r: for fenrir_sock in r:
client_sock, client_addr = fenrir_sock.accept() client_sock, client_addr = fenrir_sock.accept()
socket_file = self._socket_file_for_socket(fenrir_sock)
# Ensure client socket is always closed to prevent resource # Ensure client socket is always closed to prevent resource
# leaks # leaks
try: try:
self._handle_client(client_sock, event_queue) self._handle_client(client_sock, event_queue, socket_file)
finally: finally:
# Always close client socket, even if data processing fails # Always close client socket, even if data processing fails
try: try:
+1 -1
View File
@@ -232,7 +232,7 @@ class TestRemoteDataFormat:
"x11_window_id": "0x123", "x11_window_id": "0x123",
"socket_files": [ "socket_files": [
"/tmp/fenrirscreenreader-123.sock", "/tmp/fenrirscreenreader-123.sock",
"/tmp/fenrirscreenreader-deamon.sock", "/tmp/fenrirscreenreader-daemon.sock",
], ],
} }
], ],
+223
View File
@@ -0,0 +1,223 @@
from unittest.mock import Mock, mock_open, patch
from fenrirscreenreader.remoteDriver import unixDriver
class FakeClientSocket:
def __init__(self, data):
self.data = data
self.sent = b""
def recv(self, _size):
return self.data
def sendall(self, data):
self.sent += data
def test_main_socket_routes_to_ancestor_private_socket(mock_environment):
driver = unixDriver.driver()
driver.env = mock_environment
driver.bound_sockets = [
(Mock(), "/tmp/fenrirscreenreader-999.sock"),
(Mock(), unixDriver.MAIN_SOCKET_FILE),
]
client_sock = FakeClientSocket(b"command say routed")
event_queue = Mock()
with patch.object(driver, "_get_peer_pid", return_value=1234), patch.object(
driver,
"_find_ancestor_private_socket",
return_value="/tmp/fenrirscreenreader-222.sock",
), patch.object(
driver,
"_find_available_private_socket",
return_value="/tmp/fenrirscreenreader-222.sock",
), patch.object(
driver, "_forward_remote_to_socket", return_value=True
) as forward:
driver._handle_client(
client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE
)
forward.assert_called_once_with(
"command say routed", "/tmp/fenrirscreenreader-222.sock"
)
event_queue.put.assert_not_called()
def test_main_socket_routes_to_first_available_private_socket(
mock_environment,
):
driver = unixDriver.driver()
driver.env = mock_environment
driver.bound_sockets = [
(Mock(), "/tmp/fenrirscreenreader-999.sock"),
(Mock(), unixDriver.MAIN_SOCKET_FILE),
]
client_sock = FakeClientSocket(b"command say fallback")
event_queue = Mock()
with patch.object(driver, "_get_peer_pid", return_value=1234), patch.object(
driver,
"_find_ancestor_private_socket",
return_value="",
), patch.object(
driver,
"_find_available_private_socket",
return_value="/tmp/fenrirscreenreader-333.sock",
), patch.object(
driver, "_forward_remote_to_socket", return_value=True
) as forward:
driver._handle_client(
client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE
)
forward.assert_called_once_with(
"command say fallback", "/tmp/fenrirscreenreader-333.sock"
)
event_queue.put.assert_not_called()
def test_main_socket_handles_command_locally_without_available_target(
mock_environment,
):
driver = unixDriver.driver()
driver.env = mock_environment
client_sock = FakeClientSocket(b"command say local")
event_queue = Mock()
with patch.object(driver, "_get_peer_pid", return_value=1234), patch.object(
driver,
"_find_available_private_socket",
return_value="",
):
driver._handle_client(
client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE
)
event_queue.put.assert_called_once_with(
{
"Type": unixDriver.FenrirEventType.remote_incomming,
"data": "command say local",
}
)
def test_vcsa_main_socket_owner_handles_command_locally(mock_environment):
driver = unixDriver.driver()
driver.env = mock_environment
driver.bound_sockets = [(Mock(), unixDriver.MAIN_SOCKET_FILE)]
client_sock = FakeClientSocket(b"command say root")
event_queue = Mock()
with patch.object(driver, "_find_available_private_socket") as find_available:
driver._handle_client(
client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE
)
find_available.assert_not_called()
event_queue.put.assert_called_once_with(
{
"Type": unixDriver.FenrirEventType.remote_incomming,
"data": "command say root",
}
)
def test_private_socket_handles_command_locally(mock_environment):
driver = unixDriver.driver()
driver.env = mock_environment
client_sock = FakeClientSocket(b"command say private")
event_queue = Mock()
driver._handle_client(
client_sock, event_queue, "/tmp/fenrirscreenreader-222.sock"
)
event_queue.put.assert_called_once_with(
{
"Type": unixDriver.FenrirEventType.remote_incomming,
"data": "command say private",
}
)
def test_list_command_still_returns_response_from_main_socket(mock_environment):
driver = unixDriver.driver()
driver.env = mock_environment
mock_environment["runtime"]["RemoteManager"] = Mock()
client_sock = FakeClientSocket(b"command list")
event_queue = Mock()
mock_environment["runtime"][
"RemoteManager"
].handle_remote_incomming_with_response.return_value = {
"success": True,
"message": "pid=1",
}
driver._handle_client(client_sock, event_queue, unixDriver.MAIN_SOCKET_FILE)
assert client_sock.sent == b"pid=1\n"
event_queue.put.assert_not_called()
def test_get_parent_pid_parses_process_names_with_spaces():
driver = unixDriver.driver()
stat_file = mock_open(
read_data="1234 (name with spaces) S 567 1 1 0 -1 0\n"
)
with patch("builtins.open", stat_file):
assert driver._get_parent_pid(1234) == 567
def test_find_available_private_socket_prefers_ancestor_socket(
mock_environment,
):
driver = unixDriver.driver()
driver.env = mock_environment
with patch(
"fenrirscreenreader.remoteDriver.unixDriver.remoteInstanceRegistry.list_instances",
return_value=[
{
"pid": 111,
"socket_files": ["/tmp/fenrirscreenreader-111.sock"],
},
{
"pid": 222,
"socket_files": ["/tmp/fenrirscreenreader-222.sock"],
},
],
), patch.object(driver, "_is_socket_active", return_value=True):
assert (
driver._find_available_private_socket(
"/tmp/fenrirscreenreader-222.sock"
)
== "/tmp/fenrirscreenreader-222.sock"
)
def test_find_available_private_socket_skips_main_socket(
mock_environment,
):
driver = unixDriver.driver()
driver.env = mock_environment
with patch(
"fenrirscreenreader.remoteDriver.unixDriver.remoteInstanceRegistry.list_instances",
return_value=[
{
"pid": 111,
"socket_files": [
unixDriver.MAIN_SOCKET_FILE,
"/tmp/fenrirscreenreader-111.sock",
],
}
],
), patch.object(driver, "_is_socket_active", return_value=True):
assert (
driver._find_available_private_socket()
== "/tmp/fenrirscreenreader-111.sock"
)
+3 -2
View File
@@ -1,8 +1,9 @@
#!/bin/bash #!/bin/bash
# shellcheck disable=SC2329
cleanup() { cleanup() {
# Make sure Fenrir is restored on exit of this script # Make sure Fenrir is restored on exit of this script
echo -n "setting set screen#suspendingScreen=" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo -n "setting set screen#suspendingScreen=" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
} }
# Call the cleanup function on exit of this script # Call the cleanup function on exit of this script
@@ -20,7 +21,7 @@ if ! [[ "$term" =~ ^[1-9]+$ ]]; then
fi fi
# Suspend the current terminal for Fenrir # Suspend the current terminal for Fenrir
echo -n "setting set screen#suspendingScreen=$term" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock echo -n "setting set screen#suspendingScreen=$term" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Start the x session # Start the x session
command startx command startx