split src/devices/input into src/devices/input/{raw,wrap}

master
bel 2023-03-24 19:51:38 -06:00
parent ab673a81f0
commit 38b00e55b0
16 changed files with 161 additions and 159 deletions

View File

@ -2,63 +2,16 @@ package input
import (
"context"
"os"
"strconv"
"syscall"
"mayhem-party/src/device/input/raw"
"mayhem-party/src/device/input/wrap"
)
type Input interface {
Read() []Button
Read() []wrap.Button
Close()
}
func New(ctx context.Context) Input {
return newNew(ctx)()
}
func newNew(ctx context.Context) func() Input {
maker := newSourceFunc()
if os.Getenv("INPUT_BUFFERED") == "true" {
oldMaker := maker
maker = func() Input {
return NewBuffered(ctx, oldMaker())
}
}
if p := os.Getenv("INPUT_REMAP_FILE"); p != "" {
oldMaker := maker
maker = func() Input {
return NewRemapFromFile(oldMaker(), p)
}
}
if os.Getenv("INPUT_REFRESH_ON_SIGUSR1") != "" {
oldMaker := maker
c := NewRefreshCh(syscall.SIGUSR1)
maker = func() Input {
return NewRefresh(oldMaker, c)
}
}
return maker
}
func newSourceFunc() func() Input {
if os.Getenv("INPUT_KEYBOARD") == "true" {
singletonKeyboard := NewKeyboard()
return func() Input {
return singletonKeyboard
}
}
if port, _ := strconv.Atoi(os.Getenv("INPUT_UDP")); port != 0 {
singletonUDP := NewUDP(port)
return func() Input {
return singletonUDP
}
}
return func() Input {
generator := randomCharFromRange('a', 'g')
if p, ok := os.LookupEnv("INPUT_RANDOM_WEIGHT_FILE"); ok && len(p) > 0 {
generator = randomCharFromWeightFile(p)
}
return NewRandom(generator)
}
src := raw.New(ctx)
return wrap.New(ctx, src)
}

View File

@ -30,11 +30,11 @@ func TestNewRemapped(t *testing.T) {
t.Fatal(err)
}
os.Setenv("INPUT_REMAP_FILE", remap)
os.Setenv("INPUT_RANDOM_WEIGHT_FILE", rand)
os.Setenv("WRAP_REMAP_FILE", remap)
os.Setenv("RAW_RANDOM_WEIGHT_FILE", rand)
t.Cleanup(func() {
os.Unsetenv("INPUT_REMAP_FILE")
os.Unsetenv("INPUT_RANDOM_WEIGHT_FILE")
os.Unsetenv("WRAP_REMAP_FILE")
os.Unsetenv("RAW_RANDOM_WEIGHT_FILE")
})
r := input.New(context.Background())
@ -50,9 +50,9 @@ func TestNewRemapped(t *testing.T) {
}
func TestNewBuffered(t *testing.T) {
os.Setenv("INPUT_BUFFERED", "true")
os.Setenv("WRAP_BUFFERED", "true")
t.Cleanup(func() {
os.Unsetenv("INPUT_BUFFERED")
os.Unsetenv("WRAP_BUFFERED")
})
r := input.New(context.Background())
@ -71,9 +71,9 @@ func TestNewRandomWeightFile(t *testing.T) {
t.Fatal(err)
}
os.Setenv("INPUT_RANDOM_WEIGHT_FILE", p)
os.Setenv("RAW_RANDOM_WEIGHT_FILE", p)
t.Cleanup(func() {
os.Unsetenv("INPUT_RANDOM_WEIGHT_FILE")
os.Unsetenv("RAW_RANDOM_WEIGHT_FILE")
})
r := input.New(context.Background())

View File

@ -1,33 +0,0 @@
package input
import (
"context"
"os"
"testing"
)
func TestInput(t *testing.T) {
var _ Input = &Random{}
var _ Input = Keyboard{}
var _ Input = &Buffered{}
var _ Input = Remap{}
var _ Input = &Refresh{}
var _ Input = UDP{}
}
func TestNewNew(t *testing.T) {
t.Run("refreshing", func(t *testing.T) {
ctx, can := context.WithCancel(context.Background())
defer can()
os.Setenv("INPUT_BUFFERED", "true")
os.Setenv("INPUT_REFRESH_ON_SIGUSR1", "true")
foo := New(ctx)
if refresh, ok := foo.(*Refresh); !ok {
t.Errorf("%T", foo)
} else if buffered, ok := refresh.input.(*Buffered); !ok {
t.Errorf("%T", refresh.input)
} else if _, ok := buffered.input.(*Random); !ok {
t.Errorf("%T", buffered.input)
}
})
}

View File

@ -1,4 +1,4 @@
package input
package raw
import (
"io"
@ -44,25 +44,14 @@ func (kb Keyboard) Close() {
}
}
func (kb Keyboard) Read() []Button {
func (kb Keyboard) Read() []byte {
b := make([]byte, 5)
n, err := os.Stdin.Read(b)
if err != nil && err != io.EOF {
panic(err)
}
down := true
result := make([]Button, 0, n)
for i := 0; i < n; i++ {
if b[i] == '!' {
down = false
} else if b[i] != '\n' {
result = append(result, Button{Char: b[i], Down: down})
down = true
}
}
if os.Getenv("DEBUG") == "true" {
log.Printf("input.Keyboard.Read() %s => %+v", b[:n], result)
log.Printf("raw.Keyboard.Read() %s", b[:n])
}
return result
return b[:n]
}

View File

@ -1,4 +1,4 @@
package input
package raw
import (
"bytes"
@ -12,14 +12,9 @@ import (
"github.com/go-yaml/yaml"
)
type Button struct {
Char byte
Down bool
}
type Random struct {
generator func() byte
down []Button
down []byte
}
func NewRandom(generator func() byte) *Random {
@ -30,19 +25,8 @@ func NewRandom(generator func() byte) *Random {
func (r *Random) Close() {
}
func (r *Random) Read() []Button {
if len(r.down) > 0 && rand.Int()%2 == 0 {
was := r.down
for i := range was {
was[i].Down = false
}
r.down = r.down[:0]
return was
} else {
c := Button{Char: r.generator(), Down: true}
r.down = append(r.down, c)
return []Button{c}
}
func (r *Random) Read() []byte {
return []byte{r.generator()}
}
func randomCharFromRange(start, stop byte) func() byte {

View File

@ -1,4 +1,4 @@
package input
package raw
import (
"strings"

View File

@ -0,0 +1,26 @@
package raw
import (
"context"
"os"
"strconv"
)
type Raw interface {
Read() []byte
Close()
}
func New(ctx context.Context) Raw {
if os.Getenv("RAW_KEYBOARD") == "true" {
return NewKeyboard()
}
if port, _ := strconv.Atoi(os.Getenv("RAW_UDP")); port != 0 {
return NewUDP(port)
}
generator := randomCharFromRange('a', 'g')
if p, ok := os.LookupEnv("RAW_RANDOM_WEIGHT_FILE"); ok && len(p) > 0 {
generator = randomCharFromWeightFile(p)
}
return NewRandom(generator)
}

View File

@ -0,0 +1,9 @@
package raw
import "testing"
func TestRaw(t *testing.T) {
var _ Raw = &Random{}
var _ Raw = UDP{}
var _ Raw = Keyboard{}
}

View File

@ -1,7 +1,9 @@
package input
package raw
import (
"log"
"net"
"os"
"strconv"
)
@ -19,26 +21,17 @@ func NewUDP(port int) UDP {
}
}
func (udp UDP) Read() []Button {
func (udp UDP) Read() []byte {
panic("NEEDS TO BE IN BG THREAD SO WE CAN SHUT DOWN WITHOUT BLOCKING ON READ OR AT LEAST BE RESPONSIVE")
buff := make([]byte, 1024)
n, _, err := udp.conn.ReadFrom(buff)
if err != nil {
panic(err)
}
buttons := make([]Button, 0, n)
down := true
for i := range buff[:n] {
if buff[i] == '!' {
down = false
} else {
if buff[i] != '\n' {
buttons = append(buttons, Button{Char: buff[i], Down: down})
}
down = true
}
if os.Getenv("DEBUG") == "true" {
log.Printf("raw.UDP.Read() => %s", buff[:n])
}
return buttons
return buff[:n]
}
func (udp UDP) Close() {

View File

@ -1,4 +1,4 @@
package input
package wrap
import (
"context"
@ -12,15 +12,15 @@ type Buffered struct {
can context.CancelFunc
lock sync.Mutex
keys map[byte]int64
input Input
input Wrap
listenInterval time.Duration
expirationInterval time.Duration
}
func NewBuffered(ctx context.Context, input Input) *Buffered {
func NewBuffered(ctx context.Context, input Wrap) *Buffered {
ctx, can := context.WithCancel(ctx)
expirationInterval := time.Millisecond * 125
if d, err := time.ParseDuration(os.Getenv("INPUT_BUFFERED_STICKY_DURATION")); err == nil {
if d, err := time.ParseDuration(os.Getenv("WRAP_BUFFERED_STICKY_DURATION")); err == nil {
expirationInterval = d
}
result := &Buffered{

View File

@ -0,0 +1,6 @@
package wrap
type Button struct {
Char byte
Down bool
}

View File

@ -1,4 +1,4 @@
package input
package wrap
import (
"context"
@ -9,7 +9,7 @@ import (
type Refresh struct {
can context.CancelFunc
input Input
input Wrap
}
func NewRefreshCh(sig os.Signal) <-chan os.Signal {
@ -18,11 +18,11 @@ func NewRefreshCh(sig os.Signal) <-chan os.Signal {
return c
}
func NewRefresh(newInput func() Input, ch <-chan os.Signal) *Refresh {
func NewRefresh(newWrap func() Wrap, ch <-chan os.Signal) *Refresh {
ctx, can := context.WithCancel(context.Background())
result := &Refresh{
can: can,
input: newInput(),
input: newWrap(),
}
go func() {
defer log.Println("refreshing done")
@ -32,7 +32,7 @@ func NewRefresh(newInput func() Input, ch <-chan os.Signal) *Refresh {
return
case sig := <-ch:
log.Println("refreshing for", sig)
result.input = newInput()
result.input = newWrap()
}
}
}()

View File

@ -1,6 +1,7 @@
package input
package wrap
import (
"mayhem-party/src/device/input/raw"
"os"
"syscall"
"testing"
@ -9,9 +10,9 @@ import (
func TestRefresh(t *testing.T) {
b := byte('a')
generator := func() Input {
generator := func() Wrap {
b += byte(1)
return NewRandom(func() byte { return b })
return explicit{src: raw.NewRandom(func() byte { return b })}
}
ch := make(chan os.Signal, 1)
defer close(ch)

View File

@ -1,4 +1,4 @@
package input
package wrap
import (
"os"
@ -7,11 +7,11 @@ import (
)
type Remap struct {
input Input
input Wrap
m map[byte]byte
}
func NewRemapFromFile(input Input, p string) Remap {
func NewRemapFromFile(input Wrap, p string) Remap {
b, err := os.ReadFile(p)
if err != nil {
panic(err)
@ -30,7 +30,7 @@ func NewRemapFromFile(input Input, p string) Remap {
return NewRemap(input, remap)
}
func NewRemap(input Input, m map[byte]byte) Remap {
func NewRemap(input Wrap, m map[byte]byte) Remap {
return Remap{
input: input,
m: m,

View File

@ -0,0 +1,64 @@
package wrap
import (
"context"
"mayhem-party/src/device/input/raw"
"os"
"syscall"
)
type Wrap interface {
Read() []Button
Close()
}
func New(ctx context.Context, src raw.Raw) Wrap {
maker := func() Wrap {
return explicit{src: src}
}
if os.Getenv("WRAP_BUFFERED") == "true" {
oldMaker := maker
maker = func() Wrap {
return NewBuffered(ctx, oldMaker())
}
}
if p := os.Getenv("WRAP_REMAP_FILE"); p != "" {
oldMaker := maker
maker = func() Wrap {
return NewRemapFromFile(oldMaker(), p)
}
}
if os.Getenv("WRAP_REFRESH_ON_SIGUSR1") != "" {
oldMaker := maker
c := NewRefreshCh(syscall.SIGUSR1)
maker = func() Wrap {
return NewRefresh(oldMaker, c)
}
}
return maker()
}
type explicit struct {
src raw.Raw
}
func (e explicit) Close() {
e.src.Close()
}
func (e explicit) Read() []Button {
b := e.src.Read()
buttons := make([]Button, 0, len(b))
down := true
for i := range b {
if b[i] == '!' {
down = false
} else {
if b[i] != '\n' {
buttons = append(buttons, Button{Char: b[i], Down: down})
}
down = true
}
}
return buttons
}

View File

@ -0,0 +1,10 @@
package wrap
import "testing"
func TestWrap(t *testing.T) {
var _ Wrap = explicit{}
var _ Wrap = &Refresh{}
var _ Wrap = &Buffered{}
var _ Wrap = &Remap{}
}