gosmartkeyboard/Client.md

206 lines
4.2 KiB
Markdown
Raw Normal View History

2023-01-01 01:23:52 +00:00
# GoSmartKeyboard Client
When the GoSmartKeyboard client is started, it does the following:
2023-01-01 01:23:52 +00:00
1. Load the connection URL from the first CLI argument.
2. Load the auth token from the environment variable `KEYBOARD_AUTH` or stdin if it does not exist.
2023-01-01 21:25:32 +00:00
3. Connect to the server.
4 Send the auth token to the server.
5. If the server responds with "authenticated", we start reading keys from stdin and sending them to the server until EOF.
5.1 If the environment variable `KEYBOARD_FIFO` is set, we read from the path specified there instead as a named pipe.
5.2 Regardless, each message is sent to the server with the prefix `@{payload delimiter}`.
2023-01-01 01:23:52 +00:00
2023-01-22 00:55:58 +00:00
``` go
2023-01-02 07:24:35 +00:00
--- handle client command
if len(os.Args) > 1 {
2023-03-03 03:20:34 +00:00
@{get client fifo input file from environment}
2023-01-22 03:28:56 +00:00
@{setup client}
2023-03-03 03:20:34 +00:00
if clientFifoInputFileEnvExists {
2023-01-22 03:28:56 +00:00
@{start client with fifo}
os.Exit(0)
}
@{start client with stdin}
2023-01-02 07:24:35 +00:00
os.Exit(0)
}
---
2023-01-22 00:55:58 +00:00
```
2023-01-02 07:24:35 +00:00
2023-01-01 21:25:32 +00:00
## Connecting
The base64 authentication token is loaded from the environment variable `KEYBOARD_AUTH`, if it does not exist we read it from stdin (base64 encoded), ended with a newline.
2023-01-01 01:23:52 +00:00
``` go
2023-01-22 03:28:56 +00:00
--- setup client
2023-01-01 01:23:52 +00:00
@{handle version command}
2023-01-01 21:25:32 +00:00
@{load connection URL from second CLI argument}
@{get authTokenInput from environment}
@{add xdotool if non qwerty function}
2023-01-01 21:25:32 +00:00
if !authTokenInputExists {
fmt.Print("Enter authentication token: ")
_, err := fmt.Scanln(&authTokenInput)
if err != nil {
log.Fatal(err)
}
}
client, _, err := websocket.DefaultDialer.Dial(connectionURL, nil)
if err != nil {
log.Fatal("dial:", err)
}
defer client.Close()
err = client.WriteMessage(websocket.TextMessage, []byte(authTokenInput))
if err != nil {
log.Fatal("write:", err)
}
_, authResponse, err := client.ReadMessage()
if err != nil {
log.Fatal("read:", err)
}
2023-01-02 07:24:35 +00:00
if string(authResponse) == "authenticated" {
fmt.Println("authenticated")
} else {
2023-01-01 21:25:32 +00:00
log.Fatal("authentication failed")
}
---
--- load connection URL from second CLI argument --- noWeave
2023-01-27 23:22:02 +00:00
if len(os.Args) < 2 {
2023-01-01 21:25:32 +00:00
log.Fatal("missing connection URL")
}
2023-01-01 01:23:52 +00:00
2023-01-27 23:22:02 +00:00
connectionURL := os.Args[1]
2023-01-01 21:25:32 +00:00
if !strings.HasPrefix(connectionURL, "ws://") && !strings.HasPrefix(connectionURL, "wss://") {
log.Fatal("connection URL must start with ws:// or wss://")
}
2023-01-01 01:23:52 +00:00
---
2023-01-01 21:25:32 +00:00
```
2023-01-22 03:28:56 +00:00
## Sending keys from a named pipe
We create a fifo and then continuously read from it in a loop.
2023-01-22 03:28:56 +00:00
``` go
--- start client with fifo
2023-03-03 03:20:34 +00:00
syscall.Mkfifo(clientFifoInputFile, syscall.S_IFIFO|0666)
inputString := ""
2023-01-22 03:28:56 +00:00
for {
readData, err := ioutil.ReadFile(clientFifoInputFile)
2023-01-22 03:28:56 +00:00
if err != nil {
log.Fatal(err)
}
inputString = addXDoToolIfNonQWERTY(string(readData))
2023-03-14 03:25:04 +00:00
input := []byte(inputString)
2023-01-22 03:28:56 +00:00
if len(input) > 0 {
err = client.WriteMessage(websocket.TextMessage, input)
if err != nil {
log.Fatal("write:", err)
}
}
}
---
```
## Sending keys from stdin
2023-01-01 21:25:32 +00:00
2023-01-27 23:22:02 +00:00
We read keys from stdin and send them to the server until we get EOF.
We specify xdotool if the key is not a QWERTY key or if KEYBOARD_ALWAYS_XDOTOOL is set to true.
2023-01-01 21:25:32 +00:00
``` go
2023-01-22 03:28:56 +00:00
--- start client with stdin
2023-01-01 21:25:32 +00:00
2023-01-22 00:55:58 +00:00
reader := bufio.NewReader(os.Stdin)
2023-01-01 21:25:32 +00:00
for {
var key string
2023-01-22 00:55:58 +00:00
rune, _, err := reader.ReadRune() //:= fmt.Scan(&key)
key = addXDoToolIfNonQWERTY(string(rune))
2023-01-01 21:25:32 +00:00
if err != nil {
if err == io.EOF {
break
}
log.Fatal(err)
}
2023-03-14 03:25:04 +00:00
err = client.WriteMessage(websocket.TextMessage, []byte(key))
2023-01-01 21:25:32 +00:00
if err != nil {
log.Fatal("write:", err)
}
}
---
2023-01-01 01:23:52 +00:00
```
# Handling unicode outside of the ASCII set
``` go
--- add xdotool if non qwerty function --- noWeave
addXDoToolIfNonQWERTY := func(message string)(string) {
2023-01-27 23:22:02 +00:00
if strings.HasPrefix(message, "@{use xdotool cmd}") {
return message
}
for _, char := range message {
if char < 32 || char > 126 {
if char != 8 && char != 9 && char != 10 {
return "@{use xdotool cmd}" + message
}
}
}
return message
}
---
```
``` go
--- /client/main-client.go
package main
import (
"strings"
"io/ioutil"
2023-03-03 03:20:34 +00:00
"syscall"
"io"
"bufio"
"log"
"fmt"
"os"
@{gorilla/websocket import string}
)
func main(){@{handle client command}}
---
```