-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkvmix.go
101 lines (91 loc) · 2.95 KB
/
kvmix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package kvmix
import (
"io"
"time"
"github.com/marcuswu/KVMix/config"
"github.com/marcuswu/KVMix/ddc"
"github.com/marcuswu/KVMix/viewmodel"
"github.com/marcuswu/gosmartknob"
"github.com/marcuswu/gosmartknob/pb"
"github.com/rs/zerolog/log"
)
type PortOpener func() (io.ReadWriteCloser, error)
type KVMix struct {
smartknob *gosmartknob.SmartKnob
config config.Config
ddc ddc.DDC
viewModels []viewmodel.ViewModel
portOpener PortOpener
Running bool
configNonce int64
}
func New(portOpener PortOpener, config config.Config) *KVMix {
mixer := &KVMix{config: config, Running: true}
mixer.ddc = ddc.NewDDC()
mixer.viewModels = make([]viewmodel.ViewModel, 0, 3)
home := viewmodel.NewHomeViewModel(config, mixer.ddc)
mixer.viewModels = append(mixer.viewModels, home)
mixer.portOpener = portOpener
port, _ := mixer.portOpener()
sk := gosmartknob.New(port, func(message *pb.FromSmartKnob) {
mixer.handleMessage(message)
}, func() { log.Debug().Msg("connection closed"); mixer.handleClosed() })
mixer.smartknob = sk
nonce, _ := mixer.smartknob.SendConfig(mixer.generateConfig())
mixer.configNonce = int64(nonce)
return mixer
}
func (mix *KVMix) generateConfig() *pb.SmartKnobConfig {
return mix.viewModels[len(mix.viewModels)-1].GenerateConfig()
}
func (mix *KVMix) handleMessage(message *pb.FromSmartKnob) {
ack := message.GetAck()
if ack != nil {
log.Debug().Int64("nonce", int64(ack.Nonce)).Msg("handleMessage got ack")
}
if ack != nil && mix.configNonce == int64(ack.Nonce) {
mix.configNonce = -1
}
// Discard everything from the SmartKnob until the last sent config is acknowledged
if mix.configNonce > 0 {
return
}
// ViewModel can change the SmartKnob config based on messages
// It returns true if a configuration update is necessary
state := message.GetSmartknobState()
if state == nil {
return
}
navAction := mix.viewModels[len(mix.viewModels)-1].HandleMessage(state)
switch navAction.Navigation {
case viewmodel.NavTo:
if navAction.ViewModel != nil {
mix.viewModels = append(mix.viewModels, navAction.ViewModel)
}
navAction.RegenConfig = true
case viewmodel.NavBack:
if mix.viewModels[len(mix.viewModels)-1].GenerateConfigBeforeBack() {
nonce, _ := mix.smartknob.SendConfig(mix.generateConfig())
mix.configNonce = int64(nonce)
}
mix.viewModels = mix.viewModels[:len(mix.viewModels)-1]
// Ensure initial state going back is valid (pressNonce has probably changed)
mix.viewModels[len(mix.viewModels)-1].Restore(message.GetSmartknobState())
navAction.RegenConfig = true
}
if navAction.RegenConfig {
nonce, _ := mix.smartknob.SendConfig(mix.generateConfig())
mix.configNonce = int64(nonce)
}
}
func (mix *KVMix) handleClosed() {
// Wait a bit to be nice to CPU
time.Sleep(2 * time.Second)
newPort, _ := mix.portOpener()
mix.smartknob.SetReadWriter(newPort)
nonce, _ := mix.smartknob.SendConfig(mix.generateConfig())
mix.configNonce = int64(nonce)
}
func (mix *KVMix) Stop() {
mix.Running = false
}