164 lines
3.0 KiB
Go
164 lines
3.0 KiB
Go
package button
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"mayhem-party/src/device/input/raw"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
var (
|
|
FlagDebug = os.Getenv("DEBUG") == "true"
|
|
FlagButtonV01Config = os.Getenv("BUTTON_V01_CONFIG")
|
|
)
|
|
|
|
type (
|
|
V01 struct {
|
|
ctx context.Context
|
|
can context.CancelFunc
|
|
src raw.Raw
|
|
cfg v01Cfg
|
|
}
|
|
v01Msg struct {
|
|
T int64
|
|
U string
|
|
Y string
|
|
N string
|
|
}
|
|
v01Cfg struct {
|
|
Feedback struct {
|
|
Addr string
|
|
}
|
|
Users map[string]struct {
|
|
Player int
|
|
Message string
|
|
}
|
|
Players []struct {
|
|
Transformation v01Transformation
|
|
}
|
|
}
|
|
v01Transformation map[string]string
|
|
)
|
|
|
|
func NewV01(ctx context.Context, src raw.Raw) *V01 {
|
|
var cfg v01Cfg
|
|
b, _ := ioutil.ReadFile(FlagButtonV01Config)
|
|
yaml.Unmarshal(b, &cfg)
|
|
ctx, can := context.WithCancel(ctx)
|
|
result := &V01{
|
|
ctx: ctx,
|
|
can: can,
|
|
src: src,
|
|
cfg: cfg,
|
|
}
|
|
go result.listen()
|
|
return result
|
|
}
|
|
|
|
func (v01 *V01) listen() {
|
|
if v01.cfg.Feedback.Addr == "" {
|
|
return
|
|
}
|
|
s := &http.Server{
|
|
Addr: v01.cfg.Feedback.Addr,
|
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodGet {
|
|
r = r.WithContext(v01.ctx)
|
|
user, ok := v01.cfg.Users[r.URL.Query().Get("user")]
|
|
if !ok {
|
|
user = v01.cfg.Users["broadcast"]
|
|
}
|
|
w.Write([]byte(user.Message))
|
|
} else if r.URL.Path == "/broadcast" {
|
|
b, _ := io.ReadAll(r.Body)
|
|
v := v01.cfg.Users["broadcast"]
|
|
v.Message = string(b)
|
|
v01.cfg.Users["broadcast"] = v
|
|
}
|
|
}),
|
|
}
|
|
go func() {
|
|
<-v01.ctx.Done()
|
|
log.Println("closing v01 server")
|
|
s.Close()
|
|
}()
|
|
log.Println("starting v01 server")
|
|
if err := s.ListenAndServe(); err != nil && v01.ctx.Err() == nil {
|
|
log.Println("err with v01 server", err)
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (v01 *V01) CloseWrap() raw.Raw {
|
|
v01.can()
|
|
return v01.src
|
|
}
|
|
|
|
func (v01 *V01) Close() {
|
|
v01.can()
|
|
v01.src.Close()
|
|
}
|
|
|
|
func (v01 *V01) Read() []Button {
|
|
line := v01.src.Read()
|
|
var msg v01Msg
|
|
if err := json.Unmarshal(line, &msg); err != nil {
|
|
log.Printf("%v: %s", err, line)
|
|
}
|
|
v01.telemetry(msg)
|
|
|
|
return v01.cfg.transform(msg).buttons()
|
|
}
|
|
|
|
func (cfg v01Cfg) transform(msg v01Msg) v01Msg {
|
|
if len(cfg.Players) == 0 {
|
|
return msg
|
|
}
|
|
user := cfg.Users[msg.U]
|
|
if user.Player < 1 {
|
|
msg.Y = ""
|
|
msg.N = ""
|
|
return msg
|
|
}
|
|
player := cfg.Players[user.Player-1]
|
|
msg.Y = player.Transformation.pipe(msg.Y)
|
|
msg.N = player.Transformation.pipe(msg.N)
|
|
return msg
|
|
}
|
|
|
|
func (t v01Transformation) pipe(s string) string {
|
|
for i := range s {
|
|
if v := t[s[i:i+1]]; v != "" {
|
|
s = s[:i] + v[:1] + s[i+1:]
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (v01 *V01) telemetry(msg v01Msg) {
|
|
if FlagDebug {
|
|
log.Printf("%s|%dms", msg.U, time.Now().UnixNano()/int64(time.Millisecond)-msg.T)
|
|
}
|
|
}
|
|
|
|
func (msg v01Msg) buttons() []Button {
|
|
buttons := make([]Button, len(msg.Y)+len(msg.N))
|
|
for i := range msg.Y {
|
|
buttons[i] = Button{Char: msg.Y[i], Down: true}
|
|
}
|
|
for i := range msg.N {
|
|
buttons[len(msg.Y)+i] = Button{Char: msg.N[i], Down: false}
|
|
}
|
|
if FlagDebug {
|
|
log.Printf("%+v", msg)
|
|
}
|
|
return buttons
|
|
}
|